Skip to content

Commit

Permalink
feature: promise execute direct.
Browse files Browse the repository at this point in the history
1. promise execute direct.
2. `yield` change to a Macro define
  • Loading branch information
NianJi committed Mar 5, 2019
1 parent 06ffb7b commit bdc51e5
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@ static id testPromise2() {
}];
}

static COPromise *testPromise21() {
return [COPromise promise:^(COPromiseFullfill _Nonnull fullfill, COPromiseReject _Nonnull reject) {

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
fullfill(@"1");
});
}];
}

static COPromise *testPromise22() {
return [COPromise promise:^(COPromiseFullfill _Nonnull fullfill, COPromiseReject _Nonnull reject) {

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
fullfill(@"2");
});
}];
}

@interface Test123 : NSObject
{
dispatch_block_t _block;
Expand Down Expand Up @@ -269,7 +287,7 @@ static id testPromise3() {
it(@"https://github.com/alibaba/coobjc/issues/26", ^{
co_launch(^{
id dd = await(downloadImageWithError());
expect(co_getError() != nil);
expect(co_getError()).notTo.equal(nil);
});
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
Expand All @@ -287,9 +305,9 @@ static id testPromise3() {
NSLog(@"current progress: %f", (float)v);
progressCount++;
}
expect(progressCount > 0);
expect(progressCount > 0).beTruthy();
NSData *data = await(promise);
expect(data.length > 0);
expect(data.length > 0).beTruthy();
});
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
Expand All @@ -310,9 +328,9 @@ static id testPromise3() {
NSLog(@"current progress: %f", (float)v);
progressCount++;
}
expect(progressCount > 0);
expect(progressCount > 0).beTruthy();
NSData *data = await(promise);
expect(data.length > 0);
expect(data.length > 0).beTruthy();
});
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
Expand All @@ -326,7 +344,7 @@ static id testPromise3() {
int progressCount = 0;
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lian.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg");
NSData *data = await(promise);
expect(data.length > 0);
expect(data.length > 0).beTruthy();
});
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
Expand All @@ -338,7 +356,7 @@ static id testPromise3() {
it(@"test progress promise error", ^{
co_launch(^{
int progressCount = 0;
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lian.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg1111");
COProgressPromise *promise = progressDownloadFileFromUrl(@"http://img17.3lianghhjghj.com/d/file/201701/17/9a0d018ba683b9cbdcc5a7267b90891c.jpg1111");
for(id p in promise){
double v = [p doubleValue];
if(v >= 0.5){
Expand All @@ -347,10 +365,32 @@ static id testPromise3() {
NSLog(@"current progress: %f", (float)v);
progressCount++;
}
expect(progressCount <= 0);
expect(progressCount).to.equal(1);
NSData *data = await(promise);
expect(data == nil);
expect(co_getError() != nil);
expect(data == nil).beTruthy();
expect(co_getError() != nil).beTruthy();
});
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
done();
});
});
});

it(@"test concurrent await promise", ^{
co_launch(^{

NSTimeInterval begin = CACurrentMediaTime();
id p1 = testPromise21();
id p2 = testPromise22();

NSString *r1 = await(p1);
expect(r1).to.equal(@"1");
NSString *r2 = await(p2);
expect(r2).to.equal(@"2");

NSTimeInterval duration = CACurrentMediaTime() - begin;
expect(duration < 5.5).beTruthy();
});
waitUntil(^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,10 @@
});

it(@"yield promise", ^{
__block int count = 0;
COCoroutine *co1 = co_sequence(^{
int index = 0;
while(co_isActive()){
yield(co_downloadWithURL(@"http://pytstore.oss-cn-shanghai.aliyuncs.com/GalileoShellApp.ipa"));
index++;
yield( count++; co_downloadWithURL(@"http://pytstore.oss-cn-shanghai.aliyuncs.com/GalileoShellApp.ipa"));
}
});
int filebytes = 248564;
Expand All @@ -130,19 +129,18 @@
});
waitUntilTimeout(5.0, ^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
XCTAssert(val == filebytes * 10);
expect(val == filebytes * 10).beTruthy();
expect(count).equal(10);
done();
});
});
});

it(@"yield promise chain", ^{

__block int count = 0;
COCoroutine *co2 = co_sequence(^{
int index = 0;
while(co_isActive()){
yield(co_downloadWithURL(@"http://pytstore.oss-cn-shanghai.aliyuncs.com/GalileoShellApp.ipa"));
index++;
yield(count++; co_downloadWithURL(@"http://pytstore.oss-cn-shanghai.aliyuncs.com/GalileoShellApp.ipa"));
}
});

Expand All @@ -168,7 +166,8 @@
});
waitUntilTimeout(5.0, ^(DoneCallback done) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
XCTAssert(val == filebytes * 20);
expect(val == filebytes * 20).beTruthy();
expect(count).to.equal(20);
done();
});
});
Expand Down
18 changes: 14 additions & 4 deletions coobjc/api/COCoroutine.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@

NS_ASSUME_NONNULL_BEGIN

@class COCoroutine;

/**
Can used in a generator, use this method to yield a Promise object.
Prepare for yield. must use with `co_generator_yield_do`
@see `yield` in coobjc.h
@param co the current coroutine
*/
void co_generator_yield_prepare(COCoroutine *co);

/**
do yield. must use with `co_generator_yield_prepare`
@see `yield` in coobjc.h
@param co the current coroutine
@param promiseOrChan `COPromise` or `COChan` object
*/
void co_generator_yield(id promiseOrChan);
void co_generator_yield_do(COCoroutine *co, id promiseOrChan);


/**
Expand All @@ -54,8 +66,6 @@ id _Nullable co_await(id awaitable);
*/
NSArray *_Nullable co_batch_await(NSArray *awaitableArray);

@class COCoroutine;

/**
Get the Coroutine ObjC object from the struct.
Expand Down
8 changes: 4 additions & 4 deletions coobjc/api/COCoroutine.m
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,7 @@ id co_await(id awaitable) {
return result.copy;
}


void co_generator_yield(id _Nonnull promiseOrChan) {
COCoroutine *co = [COCoroutine currentCoroutine];
void co_generator_yield_prepare(COCoroutine *co) {
if (co == nil) {
@throw [NSException exceptionWithName:COInvalidException
reason:@"Cannot run co_generator_yield out of a coroutine"
Expand All @@ -439,8 +437,10 @@ void co_generator_yield(id _Nonnull promiseOrChan) {
if (!co.yieldChan) {
co.yieldChan = [COChan chan];
}

[co.yieldChan send:[CONextBeginObj instance]]; // 第一个等待next开始
}

void co_generator_yield_do(COCoroutine *co, id _Nonnull promiseOrChan) {
if (co.isCancelled) return;
id val = co_await(promiseOrChan);
if (co.isCancelled) return;
Expand Down
15 changes: 10 additions & 5 deletions coobjc/api/coobjc.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ NS_INLINE id _Nullable await(id _Nonnull _promiseOrChan) {
return val;
}


/**
batch_await
Expand All @@ -165,15 +166,19 @@ NS_INLINE NSArray<id> *_Nullable batch_await(NSArray<id> * _Nonnull _promiseOrCh
@discussion `yield` means pause the expression execution,
until Generator(coroutine) call `next`.
So, you should passing a `COPromise` object with constructor,
To make the expression lazy loading.
@param _promise the COPromise object.
*/
NS_INLINE void yield(id _Nonnull _promise) {
co_generator_yield(_promise);
#define yield(_expr) \
{ \
COCoroutine *__co__ = [COCoroutine currentCoroutine]; \
co_generator_yield_prepare(__co__); \
if (!__co__.isCancelled) { \
id __promiseOrChan__ = ({ _expr; }); \
co_generator_yield_do(__co__, __promiseOrChan__); \
} \
}


/**
yield with a value.
Expand Down
44 changes: 19 additions & 25 deletions coobjc/promise/COPromise.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#import "COPromise.h"
#import "COChan.h"
#import "COCoroutine.h"
#import "co_queue.h"

typedef NS_ENUM(NSInteger, COPromiseState) {
COPromiseStatePending = 0,
Expand All @@ -38,7 +39,6 @@ @interface COPromise<Value>()
NSMutableArray<COPromiseObserver> *_observers;
id __nullable _value;
NSError *__nullable _error;
COPromiseConstructor _constructor;
}

@property (nonatomic, strong) NSLock *lock;
Expand All @@ -61,10 +61,24 @@ - (instancetype)init
return self;
}

- (instancetype)initWithContructor:(COPromiseConstructor)constructor {
- (instancetype)initWithContructor:(COPromiseConstructor)constructor queue:(dispatch_queue_t)queue {
self = [self init];
if (self) {
_constructor = constructor;
if (constructor) {
COPromiseFullfill fullfill = ^(id value){
[self fulfill:value];
};
COPromiseReject reject = ^(NSError *error){
[self reject:error];
};
if (queue) {
dispatch_async(queue, ^{
constructor(fullfill, reject);
});
} else {
constructor(fullfill, reject);
}
}
}
return self;
}
Expand All @@ -74,20 +88,11 @@ + (instancetype)promise {
}

+ (instancetype)promise:(COPromiseConstructor)constructor {
return [[self alloc] initWithContructor:constructor];
return [[self alloc] initWithContructor:constructor queue:co_get_current_queue()];
}

+ (instancetype)promise:(COPromiseConstructor)constructor onQueue:(dispatch_queue_t)queue {
if (queue) {
return [[self alloc] initWithContructor:^(COPromiseFullfill fullfill, COPromiseReject reject) {
dispatch_async(queue, ^{
constructor(fullfill, reject);
});
}];
}
else{
return [[self alloc] initWithContructor:constructor];
}
return [[self alloc] initWithContructor:constructor queue:queue];
}

- (BOOL)isPending {
Expand Down Expand Up @@ -136,7 +141,6 @@ - (void)fulfill:(id)value {
_value = value;
observers = [_observers copy];
_observers = nil;
_constructor = nil;
}
else{
[_lock unlock];
Expand All @@ -162,7 +166,6 @@ - (void)reject:(NSError *)error {
_error = error;
observers = [_observers copy];
_observers = nil;
_constructor = nil;
}
else{
[_lock unlock];
Expand Down Expand Up @@ -284,15 +287,6 @@ - (COPromise *)chainedPromiseWithFulfill:(COPromiseChainedFulfillBlock)chainedFu
}

- (COPromise *)then:(COPromiseThenWorkBlock)work {
if (_constructor) {
COPromiseFullfill fullfill = ^(id value){
[self fulfill:value];
};
COPromiseReject reject = ^(NSError *error){
[self reject:error];
};
_constructor(fullfill, reject);
}
return [self chainedPromiseWithFulfill:work chainedReject:nil];
}

Expand Down

0 comments on commit bdc51e5

Please sign in to comment.