Add PromiseKit dependency
- Added PromiseKit dependency
This commit is contained in:
32
Carthage/Checkouts/PromiseKit/Sources/AnyPromise+Private.h
vendored
Normal file
32
Carthage/Checkouts/PromiseKit/Sources/AnyPromise+Private.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
@import Foundation.NSError;
|
||||
@import Foundation.NSPointerArray;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define NSPointerArrayMake(N) ({ \
|
||||
NSPointerArray *aa = [NSPointerArray strongObjectsPointerArray]; \
|
||||
aa.count = N; \
|
||||
aa; \
|
||||
})
|
||||
#else
|
||||
static inline NSPointerArray * __nonnull NSPointerArrayMake(NSUInteger count) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
NSPointerArray *aa = [[NSPointerArray class] respondsToSelector:@selector(strongObjectsPointerArray)]
|
||||
? [NSPointerArray strongObjectsPointerArray]
|
||||
: [NSPointerArray pointerArrayWithStrongObjects];
|
||||
#pragma clang diagnostic pop
|
||||
aa.count = count;
|
||||
return aa;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define IsError(o) [o isKindOfClass:[NSError class]]
|
||||
#define IsPromise(o) [o isKindOfClass:[AnyPromise class]]
|
||||
|
||||
#import "AnyPromise.h"
|
||||
|
||||
@class PMKArray;
|
||||
|
||||
@interface AnyPromise ()
|
||||
- (void)__pipe:(void(^ __nonnull)(__nullable id))block NS_REFINED_FOR_SWIFT;
|
||||
@end
|
||||
299
Carthage/Checkouts/PromiseKit/Sources/AnyPromise.h
vendored
Normal file
299
Carthage/Checkouts/PromiseKit/Sources/AnyPromise.h
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <dispatch/dispatch.h>
|
||||
#import "fwd.h"
|
||||
|
||||
/// INTERNAL DO NOT USE
|
||||
@class __AnyPromise;
|
||||
|
||||
/// Provided to simplify some usage sites
|
||||
typedef void (^PMKResolver)(id __nullable) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
/// An Objective-C implementation of the promise pattern.
|
||||
@interface AnyPromise: NSObject
|
||||
|
||||
/**
|
||||
Create a new promise that resolves with the provided block.
|
||||
|
||||
Use this method when wrapping asynchronous code that does *not* use promises so that this code can be used in promise chains.
|
||||
|
||||
If `resolve` is called with an `NSError` object, the promise is rejected, otherwise the promise is fulfilled.
|
||||
|
||||
Don’t use this method if you already have promises! Instead, just return your promise.
|
||||
|
||||
Should you need to fulfill a promise but have no sensical value to use: your promise is a `void` promise: fulfill with `nil`.
|
||||
|
||||
The block you pass is executed immediately on the calling thread.
|
||||
|
||||
- Parameter block: The provided block is immediately executed, inside the block call `resolve` to resolve this promise and cause any attached handlers to execute. If you are wrapping a delegate-based system, we recommend instead to use: initWithResolver:
|
||||
- Returns: A new promise.
|
||||
- Warning: Resolving a promise with `nil` fulfills it.
|
||||
- SeeAlso: http://promisekit.org/sealing-your-own-promises/
|
||||
- SeeAlso: http://promisekit.org/wrapping-delegation/
|
||||
*/
|
||||
+ (instancetype __nonnull)promiseWithResolverBlock:(void (^ __nonnull)(__nonnull PMKResolver))resolveBlock NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
/// INTERNAL DO NOT USE
|
||||
- (instancetype __nonnull)initWith__D:(__AnyPromise * __nonnull)d;
|
||||
|
||||
/**
|
||||
Creates a resolved promise.
|
||||
|
||||
When developing your own promise systems, it is occasionally useful to be able to return an already resolved promise.
|
||||
|
||||
- Parameter value: The value with which to resolve this promise. Passing an `NSError` will cause the promise to be rejected, passing an AnyPromise will return a new AnyPromise bound to that promise, otherwise the promise will be fulfilled with the value passed.
|
||||
- Returns: A resolved promise.
|
||||
*/
|
||||
+ (instancetype __nonnull)promiseWithValue:(__nullable id)value NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
The value of the asynchronous task this promise represents.
|
||||
|
||||
A promise has `nil` value if the asynchronous task it represents has not finished. If the value is `nil` the promise is still `pending`.
|
||||
|
||||
- Warning: *Note* Our Swift variant’s value property returns nil if the promise is rejected where AnyPromise will return the error object. This fits with the pattern where AnyPromise is not strictly typed and is more dynamic, but you should be aware of the distinction.
|
||||
|
||||
- Note: If the AnyPromise was fulfilled with a `PMKManifold`, returns only the first fulfillment object.
|
||||
|
||||
- Returns: The value with which this promise was resolved or `nil` if this promise is pending.
|
||||
*/
|
||||
@property (nonatomic, readonly) __nullable id value NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/// - Returns: if the promise is pending resolution.
|
||||
@property (nonatomic, readonly) BOOL pending NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/// - Returns: if the promise is resolved and fulfilled.
|
||||
@property (nonatomic, readonly) BOOL fulfilled NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/// - Returns: if the promise is resolved and rejected.
|
||||
@property (nonatomic, readonly) BOOL rejected NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
/**
|
||||
The provided block is executed when its receiver is resolved.
|
||||
|
||||
If you provide a block that takes a parameter, the value of the receiver will be passed as that parameter.
|
||||
|
||||
[NSURLSession GET:url].then(^(NSData *data){
|
||||
// do something with data
|
||||
});
|
||||
|
||||
@return A new promise that is resolved with the value returned from the provided block. For example:
|
||||
|
||||
[NSURLSession GET:url].then(^(NSData *data){
|
||||
return data.length;
|
||||
}).then(^(NSNumber *number){
|
||||
//…
|
||||
});
|
||||
|
||||
@warning *Important* The block passed to `then` may take zero, one, two or three arguments, and return an object or return nothing. This flexibility is why the method signature for then is `id`, which means you will not get completion for the block parameter, and must type it yourself. It is safe to type any block syntax here, so to start with try just: `^{}`.
|
||||
|
||||
@warning *Important* If an `NSError` or `NSString` is thrown inside your block, or you return an `NSError` object the next `Promise` will be rejected. See `catch` for documentation on error handling.
|
||||
|
||||
@warning *Important* `then` is always executed on the main queue.
|
||||
|
||||
@see thenOn
|
||||
@see thenInBackground
|
||||
*/
|
||||
- (AnyPromise * __nonnull (^ __nonnull)(id __nonnull))then NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
/**
|
||||
The provided block is executed on the default queue when the receiver is fulfilled.
|
||||
|
||||
This method is provided as a convenience for `thenOn`.
|
||||
|
||||
@see then
|
||||
@see thenOn
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(id __nonnull))thenInBackground NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
The provided block is executed on the dispatch queue of your choice when the receiver is fulfilled.
|
||||
|
||||
@see then
|
||||
@see thenInBackground
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, id __nonnull))thenOn NS_REFINED_FOR_SWIFT;
|
||||
|
||||
#ifndef __cplusplus
|
||||
/**
|
||||
The provided block is executed when the receiver is rejected.
|
||||
|
||||
Provide a block of form `^(NSError *){}` or simply `^{}`. The parameter has type `id` to give you the freedom to choose either.
|
||||
|
||||
The provided block always runs on the main queue.
|
||||
|
||||
@warning *Note* Cancellation errors are not caught.
|
||||
|
||||
@warning *Note* Since catch is a c++ keyword, this method is not available in Objective-C++ files. Instead use catchOn.
|
||||
|
||||
@see catchOn
|
||||
@see catchInBackground
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(id __nonnull))catch NS_REFINED_FOR_SWIFT;
|
||||
#endif
|
||||
|
||||
/**
|
||||
The provided block is executed when the receiver is rejected.
|
||||
|
||||
Provide a block of form `^(NSError *){}` or simply `^{}`. The parameter has type `id` to give you the freedom to choose either.
|
||||
|
||||
The provided block always runs on the global background queue.
|
||||
|
||||
@warning *Note* Cancellation errors are not caught.
|
||||
|
||||
@warning *Note* Since catch is a c++ keyword, this method is not available in Objective-C++ files. Instead use catchWithPolicy.
|
||||
|
||||
@see catch
|
||||
@see catchOn
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(id __nonnull))catchInBackground NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
/**
|
||||
The provided block is executed when the receiver is rejected.
|
||||
|
||||
Provide a block of form `^(NSError *){}` or simply `^{}`. The parameter has type `id` to give you the freedom to choose either.
|
||||
|
||||
The provided block always runs on queue provided.
|
||||
|
||||
@warning *Note* Cancellation errors are not caught.
|
||||
|
||||
@see catch
|
||||
@see catchInBackground
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, id __nonnull))catchOn NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
The provided block is executed when the receiver is resolved.
|
||||
|
||||
The provided block always runs on the main queue.
|
||||
|
||||
@see ensureOn
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))ensure NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
The provided block is executed on the dispatch queue of your choice when the receiver is resolved.
|
||||
|
||||
@see ensure
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, dispatch_block_t __nonnull))ensureOn NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
Create a new promise with an associated resolver.
|
||||
|
||||
Use this method when wrapping asynchronous code that does *not* use
|
||||
promises so that this code can be used in promise chains. Generally,
|
||||
prefer `promiseWithResolverBlock:` as the resulting code is more elegant.
|
||||
|
||||
PMKResolver resolve;
|
||||
AnyPromise *promise = [[AnyPromise alloc] initWithResolver:&resolve];
|
||||
|
||||
// later
|
||||
resolve(@"foo");
|
||||
|
||||
@param resolver A reference to a block pointer of PMKResolver type.
|
||||
You can then call your resolver to resolve this promise.
|
||||
|
||||
@return A new promise.
|
||||
|
||||
@warning *Important* The resolver strongly retains the promise.
|
||||
|
||||
@see promiseWithResolverBlock:
|
||||
*/
|
||||
- (instancetype __nonnull)initWithResolver:(PMKResolver __strong __nonnull * __nonnull)resolver NS_REFINED_FOR_SWIFT;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
typedef void (^PMKAdapter)(id __nullable, NSError * __nullable) NS_REFINED_FOR_SWIFT;
|
||||
typedef void (^PMKIntegerAdapter)(NSInteger, NSError * __nullable) NS_REFINED_FOR_SWIFT;
|
||||
typedef void (^PMKBooleanAdapter)(BOOL, NSError * __nullable) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
@interface AnyPromise (Adapters)
|
||||
|
||||
/**
|
||||
Create a new promise by adapting an existing asynchronous system.
|
||||
|
||||
The pattern of a completion block that passes two parameters, the first
|
||||
the result and the second an `NSError` object is so common that we
|
||||
provide this convenience adapter to make wrapping such systems more
|
||||
elegant.
|
||||
|
||||
return [PMKPromise promiseWithAdapterBlock:^(PMKAdapter adapter){
|
||||
PFQuery *query = [PFQuery …];
|
||||
[query findObjectsInBackgroundWithBlock:adapter];
|
||||
}];
|
||||
|
||||
@warning *Important* If both parameters are nil, the promise fulfills,
|
||||
if both are non-nil the promise rejects. This is per the convention.
|
||||
|
||||
@see http://promisekit.org/sealing-your-own-promises/
|
||||
*/
|
||||
+ (instancetype __nonnull)promiseWithAdapterBlock:(void (^ __nonnull)(PMKAdapter __nonnull adapter))block NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
Create a new promise by adapting an existing asynchronous system.
|
||||
|
||||
Adapts asynchronous systems that complete with `^(NSInteger, NSError *)`.
|
||||
NSInteger will cast to enums provided the enum has been wrapped with
|
||||
`NS_ENUM`. All of Apple’s enums are, so if you find one that hasn’t you
|
||||
may need to make a pull-request.
|
||||
|
||||
@see promiseWithAdapter
|
||||
*/
|
||||
+ (instancetype __nonnull)promiseWithIntegerAdapterBlock:(void (^ __nonnull)(PMKIntegerAdapter __nonnull adapter))block NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
Create a new promise by adapting an existing asynchronous system.
|
||||
|
||||
Adapts asynchronous systems that complete with `^(BOOL, NSError *)`.
|
||||
|
||||
@see promiseWithAdapter
|
||||
*/
|
||||
+ (instancetype __nonnull)promiseWithBooleanAdapterBlock:(void (^ __nonnull)(PMKBooleanAdapter __nonnull adapter))block NS_REFINED_FOR_SWIFT;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Whenever resolving a promise you may resolve with a tuple, eg.
|
||||
returning from a `then` or `catch` handler or resolving a new promise.
|
||||
|
||||
Consumers of your Promise are not compelled to consume any arguments and
|
||||
in fact will often only consume the first parameter. Thus ensure the
|
||||
order of parameters is: from most-important to least-important.
|
||||
|
||||
Currently PromiseKit limits you to THREE parameters to the manifold.
|
||||
*/
|
||||
#define PMKManifold(...) __PMKManifold(__VA_ARGS__, 3, 2, 1)
|
||||
#define __PMKManifold(_1, _2, _3, N, ...) __PMKArrayWithCount(N, _1, _2, _3)
|
||||
extern id __nonnull __PMKArrayWithCount(NSUInteger, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // Extern C
|
||||
#endif
|
||||
|
||||
|
||||
@interface AnyPromise (Unavailable)
|
||||
|
||||
- (instancetype __nonnull)init __attribute__((unavailable("It is illegal to create an unresolvable promise.")));
|
||||
+ (instancetype __nonnull)new __attribute__((unavailable("It is illegal to create an unresolvable promise.")));
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))always __attribute__((unavailable("See -ensure")));
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))alwaysOn __attribute__((unavailable("See -ensureOn")));
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull))finally __attribute__((unavailable("See -ensure")));
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_block_t __nonnull, dispatch_block_t __nonnull))finallyOn __attribute__((unavailable("See -ensureOn")));
|
||||
|
||||
@end
|
||||
|
||||
__attribute__((unavailable("See AnyPromise")))
|
||||
@interface PMKPromise
|
||||
@end
|
||||
175
Carthage/Checkouts/PromiseKit/Sources/AnyPromise.m
vendored
Normal file
175
Carthage/Checkouts/PromiseKit/Sources/AnyPromise.m
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
#if __has_include("PromiseKit-Swift.h")
|
||||
#import "PromiseKit-Swift.h"
|
||||
#else
|
||||
#import <PromiseKit/PromiseKit-Swift.h>
|
||||
#endif
|
||||
#import "PMKCallVariadicBlock.m"
|
||||
#import "AnyPromise+Private.h"
|
||||
#import "AnyPromise.h"
|
||||
|
||||
NSString *const PMKErrorDomain = @"PMKErrorDomain";
|
||||
|
||||
|
||||
@implementation AnyPromise {
|
||||
__AnyPromise *d;
|
||||
}
|
||||
|
||||
- (instancetype)initWith__D:(__AnyPromise *)dd {
|
||||
self = [super init];
|
||||
if (self) self->d = dd;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithResolver:(PMKResolver __strong *)resolver {
|
||||
self = [super init];
|
||||
if (self)
|
||||
d = [[__AnyPromise alloc] initWithResolver:^(void (^resolve)(id)) {
|
||||
*resolver = resolve;
|
||||
}];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)promiseWithResolverBlock:(void (^)(PMKResolver _Nonnull))resolveBlock {
|
||||
id d = [[__AnyPromise alloc] initWithResolver:resolveBlock];
|
||||
return [[self alloc] initWith__D:d];
|
||||
}
|
||||
|
||||
+ (instancetype)promiseWithValue:(id)value {
|
||||
//TODO provide a more efficient route for sealed promises
|
||||
id d = [[__AnyPromise alloc] initWithResolver:^(void (^resolve)(id)) {
|
||||
resolve(value);
|
||||
}];
|
||||
return [[self alloc] initWith__D:d];
|
||||
}
|
||||
|
||||
//TODO remove if possible, but used by when.m
|
||||
- (void)__pipe:(void (^)(id _Nullable))block {
|
||||
[d __pipe:block];
|
||||
}
|
||||
|
||||
//NOTE used by AnyPromise.swift
|
||||
- (id)__d {
|
||||
return d;
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(id))then {
|
||||
return ^(id block) {
|
||||
return [self->d __thenOn:dispatch_get_main_queue() execute:^(id obj) {
|
||||
return PMKCallVariadicBlock(block, obj);
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(dispatch_queue_t, id))thenOn {
|
||||
return ^(dispatch_queue_t queue, id block) {
|
||||
return [self->d __thenOn:queue execute:^(id obj) {
|
||||
return PMKCallVariadicBlock(block, obj);
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(id))thenInBackground {
|
||||
return ^(id block) {
|
||||
return [self->d __thenOn:dispatch_get_global_queue(0, 0) execute:^(id obj) {
|
||||
return PMKCallVariadicBlock(block, obj);
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(dispatch_queue_t, id))catchOn {
|
||||
return ^(dispatch_queue_t q, id block) {
|
||||
return [self->d __catchOn:q execute:^(id obj) {
|
||||
return PMKCallVariadicBlock(block, obj);
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(id))catch {
|
||||
return ^(id block) {
|
||||
return [self->d __catchOn:dispatch_get_main_queue() execute:^(id obj) {
|
||||
return PMKCallVariadicBlock(block, obj);
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(id))catchInBackground {
|
||||
return ^(id block) {
|
||||
return [self->d __catchOn:dispatch_get_global_queue(0, 0) execute:^(id obj) {
|
||||
return PMKCallVariadicBlock(block, obj);
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(dispatch_block_t))ensure {
|
||||
return ^(dispatch_block_t block) {
|
||||
return [self->d __ensureOn:dispatch_get_main_queue() execute:block];
|
||||
};
|
||||
}
|
||||
|
||||
- (AnyPromise *(^)(dispatch_queue_t, dispatch_block_t))ensureOn {
|
||||
return ^(dispatch_queue_t queue, dispatch_block_t block) {
|
||||
return [self->d __ensureOn:queue execute:block];
|
||||
};
|
||||
}
|
||||
|
||||
- (BOOL)pending {
|
||||
return [[d valueForKey:@"__pending"] boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)rejected {
|
||||
return IsError([d __value]);
|
||||
}
|
||||
|
||||
- (BOOL)fulfilled {
|
||||
return !self.rejected;
|
||||
}
|
||||
|
||||
- (id)value {
|
||||
id obj = [d __value];
|
||||
|
||||
if ([obj isKindOfClass:[PMKArray class]]) {
|
||||
return obj[0];
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation AnyPromise (Adapters)
|
||||
|
||||
+ (instancetype)promiseWithAdapterBlock:(void (^)(PMKAdapter))block {
|
||||
return [self promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
block(^(id value, id error){
|
||||
resolve(error ?: value);
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)promiseWithIntegerAdapterBlock:(void (^)(PMKIntegerAdapter))block {
|
||||
return [self promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
block(^(NSInteger value, id error){
|
||||
if (error) {
|
||||
resolve(error);
|
||||
} else {
|
||||
resolve(@(value));
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)promiseWithBooleanAdapterBlock:(void (^)(PMKBooleanAdapter adapter))block {
|
||||
return [self promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
block(^(BOOL value, id error){
|
||||
if (error) {
|
||||
resolve(error);
|
||||
} else {
|
||||
resolve(@(value));
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
204
Carthage/Checkouts/PromiseKit/Sources/AnyPromise.swift
vendored
Normal file
204
Carthage/Checkouts/PromiseKit/Sources/AnyPromise.swift
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
__AnyPromise is an implementation detail.
|
||||
|
||||
Because of how ObjC/Swift compatability work we have to compose our AnyPromise
|
||||
with this internal object, however this is still part of the public interface.
|
||||
Sadly. Please don’t use it.
|
||||
*/
|
||||
@objc(__AnyPromise) public class __AnyPromise: NSObject {
|
||||
fileprivate let box: Box<Any?>
|
||||
|
||||
@objc public init(resolver body: (@escaping (Any?) -> Void) -> Void) {
|
||||
box = EmptyBox<Any?>()
|
||||
super.init()
|
||||
body {
|
||||
if let p = $0 as? AnyPromise {
|
||||
p.d.__pipe(self.box.seal)
|
||||
} else {
|
||||
self.box.seal($0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func __thenOn(_ q: DispatchQueue, execute: @escaping (Any?) -> Any?) -> AnyPromise {
|
||||
return AnyPromise(__D: __AnyPromise(resolver: { resolve in
|
||||
self.__pipe { obj in
|
||||
if !(obj is NSError) {
|
||||
q.async {
|
||||
resolve(execute(obj))
|
||||
}
|
||||
} else {
|
||||
resolve(obj)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
@objc public func __catchOn(_ q: DispatchQueue, execute: @escaping (Any?) -> Any?) -> AnyPromise {
|
||||
return AnyPromise(__D: __AnyPromise(resolver: { resolve in
|
||||
self.__pipe { obj in
|
||||
if obj is NSError {
|
||||
q.async {
|
||||
resolve(execute(obj))
|
||||
}
|
||||
} else {
|
||||
resolve(obj)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
@objc public func __ensureOn(_ q: DispatchQueue, execute: @escaping () -> Void) -> AnyPromise {
|
||||
return AnyPromise(__D: __AnyPromise(resolver: { resolve in
|
||||
self.__pipe { obj in
|
||||
q.async {
|
||||
execute()
|
||||
resolve(obj)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
/// Internal, do not use! Some behaviors undefined.
|
||||
@objc public func __pipe(_ to: @escaping (Any?) -> Void) {
|
||||
let to = { (obj: Any?) -> Void in
|
||||
if obj is NSError {
|
||||
to(obj) // or we cannot determine if objects are errors in objc land
|
||||
} else {
|
||||
to(obj)
|
||||
}
|
||||
}
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
box.inspect {
|
||||
switch $0 {
|
||||
case .pending(let handlers):
|
||||
handlers.append { obj in
|
||||
to(obj)
|
||||
}
|
||||
case .resolved(let obj):
|
||||
to(obj)
|
||||
}
|
||||
}
|
||||
case .resolved(let obj):
|
||||
to(obj)
|
||||
}
|
||||
}
|
||||
|
||||
@objc public var __value: Any? {
|
||||
switch box.inspect() {
|
||||
case .resolved(let obj):
|
||||
return obj
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@objc public var __pending: Bool {
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
return true
|
||||
case .resolved:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension AnyPromise: Thenable, CatchMixin {
|
||||
|
||||
/// - Returns: A new `AnyPromise` bound to a `Promise<Any>`.
|
||||
public convenience init<U: Thenable>(_ bridge: U) {
|
||||
self.init(__D: __AnyPromise(resolver: { resolve in
|
||||
bridge.pipe {
|
||||
switch $0 {
|
||||
case .rejected(let error):
|
||||
resolve(error as NSError)
|
||||
case .fulfilled(let value):
|
||||
resolve(value)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
public func pipe(to body: @escaping (Result<Any?>) -> Void) {
|
||||
|
||||
func fulfill() {
|
||||
// calling through to the ObjC `value` property unwraps (any) PMKManifold
|
||||
// and considering this is the Swift pipe; we want that.
|
||||
body(.fulfilled(self.value(forKey: "value")))
|
||||
}
|
||||
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
box.inspect {
|
||||
switch $0 {
|
||||
case .pending(let handlers):
|
||||
handlers.append {
|
||||
if let error = $0 as? Error {
|
||||
body(.rejected(error))
|
||||
} else {
|
||||
fulfill()
|
||||
}
|
||||
}
|
||||
case .resolved(let error as Error):
|
||||
body(.rejected(error))
|
||||
case .resolved:
|
||||
fulfill()
|
||||
}
|
||||
}
|
||||
case .resolved(let error as Error):
|
||||
body(.rejected(error))
|
||||
case .resolved:
|
||||
fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var d: __AnyPromise {
|
||||
return value(forKey: "__d") as! __AnyPromise
|
||||
}
|
||||
|
||||
var box: Box<Any?> {
|
||||
return d.box
|
||||
}
|
||||
|
||||
public var result: Result<Any?>? {
|
||||
guard let value = __value else {
|
||||
return nil
|
||||
}
|
||||
if let error = value as? Error {
|
||||
return .rejected(error)
|
||||
} else {
|
||||
return .fulfilled(value)
|
||||
}
|
||||
}
|
||||
|
||||
public typealias T = Any?
|
||||
}
|
||||
|
||||
|
||||
#if swift(>=3.1)
|
||||
public extension Promise where T == Any? {
|
||||
convenience init(_ anyPromise: AnyPromise) {
|
||||
self.init {
|
||||
anyPromise.pipe(to: $0.resolve)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
extension AnyPromise {
|
||||
public func asPromise() -> Promise<Any?> {
|
||||
return Promise(.pending, resolver: { resolve in
|
||||
pipe { result in
|
||||
switch result {
|
||||
case .rejected(let error):
|
||||
resolve.reject(error)
|
||||
case .fulfilled(let obj):
|
||||
resolve.fulfill(obj)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
#endif
|
||||
101
Carthage/Checkouts/PromiseKit/Sources/Box.swift
vendored
Normal file
101
Carthage/Checkouts/PromiseKit/Sources/Box.swift
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
import Dispatch
|
||||
|
||||
enum Sealant<R> {
|
||||
case pending(Handlers<R>)
|
||||
case resolved(R)
|
||||
}
|
||||
|
||||
class Handlers<R> {
|
||||
var bodies: [(R) -> Void] = []
|
||||
func append(_ item: @escaping(R) -> Void) { bodies.append(item) }
|
||||
}
|
||||
|
||||
/// - Remark: not protocol ∵ http://www.russbishop.net/swift-associated-types-cont
|
||||
class Box<T> {
|
||||
func inspect() -> Sealant<T> { fatalError() }
|
||||
func inspect(_: (Sealant<T>) -> Void) { fatalError() }
|
||||
func seal(_: T) {}
|
||||
}
|
||||
|
||||
class SealedBox<T>: Box<T> {
|
||||
let value: T
|
||||
|
||||
init(value: T) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
override func inspect() -> Sealant<T> {
|
||||
return .resolved(value)
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyBox<T>: Box<T> {
|
||||
private var sealant = Sealant<T>.pending(.init())
|
||||
private let barrier = DispatchQueue(label: "org.promisekit.barrier", attributes: .concurrent)
|
||||
|
||||
override func seal(_ value: T) {
|
||||
var handlers: Handlers<T>!
|
||||
barrier.sync(flags: .barrier) {
|
||||
guard case .pending(let _handlers) = self.sealant else {
|
||||
return // already fulfilled!
|
||||
}
|
||||
handlers = _handlers
|
||||
self.sealant = .resolved(value)
|
||||
}
|
||||
|
||||
//FIXME we are resolved so should `pipe(to:)` be called at this instant, “thens are called in order” would be invalid
|
||||
//NOTE we don’t do this in the above `sync` because that could potentially deadlock
|
||||
//THOUGH since `then` etc. typically invoke after a run-loop cycle, this issue is somewhat less severe
|
||||
|
||||
if let handlers = handlers {
|
||||
handlers.bodies.forEach{ $0(value) }
|
||||
}
|
||||
|
||||
//TODO solution is an unfortunate third state “sealed” where then's get added
|
||||
// to a separate handler pool for that state
|
||||
// any other solution has potential races
|
||||
}
|
||||
|
||||
override func inspect() -> Sealant<T> {
|
||||
var rv: Sealant<T>!
|
||||
barrier.sync {
|
||||
rv = self.sealant
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
override func inspect(_ body: (Sealant<T>) -> Void) {
|
||||
var sealed = false
|
||||
barrier.sync(flags: .barrier) {
|
||||
switch sealant {
|
||||
case .pending:
|
||||
// body will append to handlers, so we must stay barrier’d
|
||||
body(sealant)
|
||||
case .resolved:
|
||||
sealed = true
|
||||
}
|
||||
}
|
||||
if sealed {
|
||||
// we do this outside the barrier to prevent potential deadlocks
|
||||
// it's safe because we never transition away from this state
|
||||
body(sealant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Optional where Wrapped: DispatchQueue {
|
||||
@inline(__always)
|
||||
func async(flags: DispatchWorkItemFlags?, _ body: @escaping() -> Void) {
|
||||
switch self {
|
||||
case .none:
|
||||
body()
|
||||
case .some(let q):
|
||||
if let flags = flags {
|
||||
q.async(flags: flags, execute: body)
|
||||
} else {
|
||||
q.async(execute: body)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
256
Carthage/Checkouts/PromiseKit/Sources/Catchable.swift
vendored
Normal file
256
Carthage/Checkouts/PromiseKit/Sources/Catchable.swift
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
import Dispatch
|
||||
|
||||
/// Provides `catch` and `recover` to your object that conforms to `Thenable`
|
||||
public protocol CatchMixin: Thenable
|
||||
{}
|
||||
|
||||
public extension CatchMixin {
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise rejects.
|
||||
|
||||
Rejecting a promise cascades: rejecting all subsequent promises (unless
|
||||
recover is invoked) thus you will typically place your catch at the end
|
||||
of a chain. Often utility promises will not have a catch, instead
|
||||
delegating the error handling to the caller.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter policy: The default policy does not execute your handler for cancellation errors.
|
||||
- Parameter execute: The handler to execute if this promise is rejected.
|
||||
- Returns: A promise finalizer.
|
||||
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
|
||||
*/
|
||||
@discardableResult
|
||||
func `catch`(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer {
|
||||
let finalizer = PMKFinalizer()
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .rejected(let error):
|
||||
guard policy == .allErrors || !error.isCancelled else {
|
||||
fallthrough
|
||||
}
|
||||
on.async(flags: flags) {
|
||||
body(error)
|
||||
finalizer.pending.resolve(())
|
||||
}
|
||||
case .fulfilled:
|
||||
finalizer.pending.resolve(())
|
||||
}
|
||||
}
|
||||
return finalizer
|
||||
}
|
||||
}
|
||||
|
||||
public class PMKFinalizer {
|
||||
let pending = Guarantee<Void>.pending()
|
||||
|
||||
/// `finally` is the same as `ensure`, but it is not chainable
|
||||
public func finally(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) {
|
||||
pending.guarantee.done(on: on, flags: flags) {
|
||||
body()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public extension CatchMixin {
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise rejects.
|
||||
|
||||
Unlike `catch`, `recover` continues the chain.
|
||||
Use `recover` in circumstances where recovering the chain from certain errors is a possibility. For example:
|
||||
|
||||
firstly {
|
||||
CLLocationManager.requestLocation()
|
||||
}.recover { error in
|
||||
guard error == CLError.unknownLocation else { throw error }
|
||||
return .value(CLLocation.chicago)
|
||||
}
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The handler to execute if this promise is rejected.
|
||||
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
|
||||
*/
|
||||
func recover<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> U) -> Promise<T> where U.T == T {
|
||||
let rp = Promise<U.T>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
rp.box.seal(.fulfilled(value))
|
||||
case .rejected(let error):
|
||||
if policy == .allErrors || !error.isCancelled {
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
let rv = try body(error)
|
||||
guard rv !== rp else { throw PMKError.returnedSelf }
|
||||
rv.pipe(to: rp.box.seal)
|
||||
} catch {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise rejects.
|
||||
This variant of `recover` requires the handler to return a Guarantee, thus it returns a Guarantee itself and your closure cannot `throw`.
|
||||
- Note it is logically impossible for this to take a `catchPolicy`, thus `allErrors` are handled.
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The handler to execute if this promise is rejected.
|
||||
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
|
||||
*/
|
||||
@discardableResult
|
||||
func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Guarantee<T>) -> Guarantee<T> {
|
||||
let rg = Guarantee<T>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
rg.box.seal(value)
|
||||
case .rejected(let error):
|
||||
on.async(flags: flags) {
|
||||
body(error).pipe(to: rg.box.seal)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise resolves, whether it rejects or not.
|
||||
|
||||
firstly {
|
||||
UIApplication.shared.networkActivityIndicatorVisible = true
|
||||
}.done {
|
||||
//…
|
||||
}.ensure {
|
||||
UIApplication.shared.networkActivityIndicatorVisible = false
|
||||
}.catch {
|
||||
//…
|
||||
}
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that executes when this promise resolves.
|
||||
- Returns: A new promise, resolved with this promise’s resolution.
|
||||
*/
|
||||
func ensure(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Void) -> Promise<T> {
|
||||
let rp = Promise<T>(.pending)
|
||||
pipe { result in
|
||||
on.async(flags: flags) {
|
||||
body()
|
||||
rp.box.seal(result)
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise resolves, whether it rejects or not.
|
||||
The chain waits on the returned `Guarantee<Void>`.
|
||||
|
||||
firstly {
|
||||
setup()
|
||||
}.done {
|
||||
//…
|
||||
}.ensureThen {
|
||||
teardown() // -> Guarante<Void>
|
||||
}.catch {
|
||||
//…
|
||||
}
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that executes when this promise resolves.
|
||||
- Returns: A new promise, resolved with this promise’s resolution.
|
||||
*/
|
||||
func ensureThen(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping () -> Guarantee<Void>) -> Promise<T> {
|
||||
let rp = Promise<T>(.pending)
|
||||
pipe { result in
|
||||
on.async(flags: flags) {
|
||||
body().done {
|
||||
rp.box.seal(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Consumes the Swift unused-result warning.
|
||||
- Note: You should `catch`, but in situations where you know you don’t need a `catch`, `cauterize` makes your intentions clear.
|
||||
*/
|
||||
@discardableResult
|
||||
func cauterize() -> PMKFinalizer {
|
||||
return self.catch {
|
||||
Swift.print("PromiseKit:cauterized-error:", $0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public extension CatchMixin where T == Void {
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise rejects.
|
||||
|
||||
This variant of `recover` is specialized for `Void` promises and de-errors your chain returning a `Guarantee`, thus you cannot `throw` and you must handle all errors including cancellation.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The handler to execute if this promise is rejected.
|
||||
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
|
||||
*/
|
||||
@discardableResult
|
||||
func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Error) -> Void) -> Guarantee<Void> {
|
||||
let rg = Guarantee<Void>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled:
|
||||
rg.box.seal(())
|
||||
case .rejected(let error):
|
||||
on.async(flags: flags) {
|
||||
body(error)
|
||||
rg.box.seal(())
|
||||
}
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure executes when this promise rejects.
|
||||
|
||||
This variant of `recover` ensures that no error is thrown from the handler and allows specifying a catch policy.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The handler to execute if this promise is rejected.
|
||||
- SeeAlso: [Cancellation](http://promisekit.org/docs/)
|
||||
*/
|
||||
func recover(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) throws -> Void) -> Promise<Void> {
|
||||
let rg = Promise<Void>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled:
|
||||
rg.box.seal(.fulfilled(()))
|
||||
case .rejected(let error):
|
||||
if policy == .allErrors || !error.isCancelled {
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
rg.box.seal(.fulfilled(try body(error)))
|
||||
} catch {
|
||||
rg.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rg.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
}
|
||||
13
Carthage/Checkouts/PromiseKit/Sources/Configuration.swift
vendored
Normal file
13
Carthage/Checkouts/PromiseKit/Sources/Configuration.swift
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import Dispatch
|
||||
|
||||
/// PromiseKit’s configurable parameters
|
||||
public struct PMKConfiguration {
|
||||
/// The default queues that promises handlers dispatch to
|
||||
public var Q: (map: DispatchQueue?, return: DispatchQueue?) = (map: DispatchQueue.main, return: DispatchQueue.main)
|
||||
|
||||
/// The default catch-policy for all `catch` and `resolve`
|
||||
public var catchPolicy = CatchPolicy.allErrorsExceptCancellation
|
||||
}
|
||||
|
||||
/// Modify this as soon as possible in your application’s lifetime
|
||||
public var conf = PMKConfiguration()
|
||||
44
Carthage/Checkouts/PromiseKit/Sources/CustomStringConvertible.swift
vendored
Normal file
44
Carthage/Checkouts/PromiseKit/Sources/CustomStringConvertible.swift
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
extension Promise: CustomStringConvertible {
|
||||
/// - Returns: A description of the state of this promise.
|
||||
public var description: String {
|
||||
switch result {
|
||||
case nil:
|
||||
return "Promise(…\(T.self))"
|
||||
case .rejected(let error)?:
|
||||
return "Promise(\(error))"
|
||||
case .fulfilled(let value)?:
|
||||
return "Promise(\(value))"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Promise: CustomDebugStringConvertible {
|
||||
/// - Returns: A debug-friendly description of the state of this promise.
|
||||
public var debugDescription: String {
|
||||
switch box.inspect() {
|
||||
case .pending(let handlers):
|
||||
return "Promise<\(T.self)>.pending(handlers: \(handlers.bodies.count))"
|
||||
case .resolved(.rejected(let error)):
|
||||
return "Promise<\(T.self)>.rejected(\(type(of: error)).\(error))"
|
||||
case .resolved(.fulfilled(let value)):
|
||||
return "Promise<\(T.self)>.fulfilled(\(value))"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !SWIFT_PACKAGE
|
||||
extension AnyPromise {
|
||||
/// - Returns: A description of the state of this promise.
|
||||
override open var description: String {
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
return "AnyPromise(…)"
|
||||
case .resolved(let obj?):
|
||||
return "AnyPromise(\(obj))"
|
||||
case .resolved(nil):
|
||||
return "AnyPromise(nil)"
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
93
Carthage/Checkouts/PromiseKit/Sources/Deprecations.swift
vendored
Normal file
93
Carthage/Checkouts/PromiseKit/Sources/Deprecations.swift
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
import Dispatch
|
||||
|
||||
@available(*, deprecated, message: "See `init(resolver:)`")
|
||||
public func wrap<T>(_ body: (@escaping (T?, Error?) -> Void) throws -> Void) -> Promise<T> {
|
||||
return Promise { seal in
|
||||
try body(seal.resolve)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "See `init(resolver:)`")
|
||||
public func wrap<T>(_ body: (@escaping (T, Error?) -> Void) throws -> Void) -> Promise<T> {
|
||||
return Promise { seal in
|
||||
try body(seal.resolve)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "See `init(resolver:)`")
|
||||
public func wrap<T>(_ body: (@escaping (Error?, T?) -> Void) throws -> Void) -> Promise<T> {
|
||||
return Promise { seal in
|
||||
try body(seal.resolve)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "See `init(resolver:)`")
|
||||
public func wrap(_ body: (@escaping (Error?) -> Void) throws -> Void) -> Promise<Void> {
|
||||
return Promise { seal in
|
||||
try body(seal.resolve)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "See `init(resolver:)`")
|
||||
public func wrap<T>(_ body: (@escaping (T) -> Void) throws -> Void) -> Promise<T> {
|
||||
return Promise { seal in
|
||||
try body(seal.fulfill)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Promise {
|
||||
@available(*, deprecated, message: "See `ensure`")
|
||||
public func always(on q: DispatchQueue = .main, execute body: @escaping () -> Void) -> Promise {
|
||||
return ensure(on: q, body)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable {
|
||||
#if PMKFullDeprecations
|
||||
/// disabled due to ambiguity with the other `.flatMap`
|
||||
@available(*, deprecated: 6.1, message: "See: `compactMap`")
|
||||
func flatMap<U>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T) throws -> U?) -> Promise<U> {
|
||||
return compactMap(on: on, transform)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public extension Thenable where T: Sequence {
|
||||
#if PMKFullDeprecations
|
||||
/// disabled due to ambiguity with the other `.map`
|
||||
@available(*, deprecated, message: "See: `mapValues`")
|
||||
func map<U>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> {
|
||||
return mapValues(on: on, transform)
|
||||
}
|
||||
|
||||
/// disabled due to ambiguity with the other `.flatMap`
|
||||
@available(*, deprecated, message: "See: `flatMapValues`")
|
||||
func flatMap<U: Sequence>(on: DispatchQueue? = conf.Q.map, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.Iterator.Element]> {
|
||||
return flatMapValues(on: on, transform)
|
||||
}
|
||||
#endif
|
||||
|
||||
@available(*, deprecated, message: "See: `filterValues`")
|
||||
func filter(on: DispatchQueue? = conf.Q.map, test: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> {
|
||||
return filterValues(on: on, test)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable where T: Collection {
|
||||
@available(*, deprecated, message: "See: `firstValue`")
|
||||
var first: Promise<T.Iterator.Element> {
|
||||
return firstValue
|
||||
}
|
||||
|
||||
@available(*, deprecated, message: "See: `lastValue`")
|
||||
var last: Promise<T.Iterator.Element> {
|
||||
return lastValue
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable where T: Sequence, T.Iterator.Element: Comparable {
|
||||
@available(*, deprecated, message: "See: `sortedValues`")
|
||||
func sorted(on: DispatchQueue? = conf.Q.map) -> Promise<[T.Iterator.Element]> {
|
||||
return sortedValues(on: on)
|
||||
}
|
||||
}
|
||||
103
Carthage/Checkouts/PromiseKit/Sources/Error.swift
vendored
Normal file
103
Carthage/Checkouts/PromiseKit/Sources/Error.swift
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
import Foundation
|
||||
|
||||
public enum PMKError: Error {
|
||||
/**
|
||||
The completionHandler with form `(T?, Error?)` was called with `(nil, nil)`.
|
||||
This is invalid as per Cocoa/Apple calling conventions.
|
||||
*/
|
||||
case invalidCallingConvention
|
||||
|
||||
/**
|
||||
A handler returned its own promise. 99% of the time, this is likely a
|
||||
programming error. It is also invalid per Promises/A+.
|
||||
*/
|
||||
case returnedSelf
|
||||
|
||||
/** `when()`, `race()` etc. were called with invalid parameters, eg. an empty array. */
|
||||
case badInput
|
||||
|
||||
/// The operation was cancelled
|
||||
case cancelled
|
||||
|
||||
/// `nil` was returned from `flatMap`
|
||||
@available(*, deprecated, message: "See: `compactMap`")
|
||||
case flatMap(Any, Any.Type)
|
||||
|
||||
/// `nil` was returned from `compactMap`
|
||||
case compactMap(Any, Any.Type)
|
||||
|
||||
/**
|
||||
The lastValue or firstValue of a sequence was requested but the sequence was empty.
|
||||
|
||||
Also used if all values of this collection failed the test passed to `firstValue(where:)`.
|
||||
*/
|
||||
case emptySequence
|
||||
}
|
||||
|
||||
extension PMKError: CustomDebugStringConvertible {
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .flatMap(let obj, let type):
|
||||
return "Could not `flatMap<\(type)>`: \(obj)"
|
||||
case .compactMap(let obj, let type):
|
||||
return "Could not `compactMap<\(type)>`: \(obj)"
|
||||
case .invalidCallingConvention:
|
||||
return "A closure was called with an invalid calling convention, probably (nil, nil)"
|
||||
case .returnedSelf:
|
||||
return "A promise handler returned itself"
|
||||
case .badInput:
|
||||
return "Bad input was provided to a PromiseKit function"
|
||||
case .cancelled:
|
||||
return "The asynchronous sequence was cancelled"
|
||||
case .emptySequence:
|
||||
return "The first or last element was requested for an empty sequence"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PMKError: LocalizedError {
|
||||
public var errorDescription: String? {
|
||||
return debugDescription
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////// Cancellation
|
||||
|
||||
/// An error that may represent the cancelled condition
|
||||
public protocol CancellableError: Error {
|
||||
/// returns true if this Error represents a cancelled condition
|
||||
var isCancelled: Bool { get }
|
||||
}
|
||||
|
||||
extension Error {
|
||||
public var isCancelled: Bool {
|
||||
do {
|
||||
throw self
|
||||
} catch PMKError.cancelled {
|
||||
return true
|
||||
} catch let error as CancellableError {
|
||||
return error.isCancelled
|
||||
} catch URLError.cancelled {
|
||||
return true
|
||||
} catch CocoaError.userCancelled {
|
||||
return true
|
||||
} catch {
|
||||
#if os(macOS) || os(iOS) || os(tvOS)
|
||||
let pair = { ($0.domain, $0.code) }(error as NSError)
|
||||
return ("SKErrorDomain", 2) == pair
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `catch` and `recover`
|
||||
public enum CatchPolicy {
|
||||
/// Indicates that `catch` or `recover` handle all error types including cancellable-errors.
|
||||
case allErrors
|
||||
|
||||
/// Indicates that `catch` or `recover` handle all error except cancellable-errors.
|
||||
case allErrorsExceptCancellation
|
||||
}
|
||||
201
Carthage/Checkouts/PromiseKit/Sources/Guarantee.swift
vendored
Normal file
201
Carthage/Checkouts/PromiseKit/Sources/Guarantee.swift
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
import class Foundation.Thread
|
||||
import Dispatch
|
||||
|
||||
/**
|
||||
A `Guarantee` is a functional abstraction around an asynchronous operation that cannot error.
|
||||
- See: `Thenable`
|
||||
*/
|
||||
public class Guarantee<T>: Thenable {
|
||||
let box: Box<T>
|
||||
|
||||
fileprivate init(box: SealedBox<T>) {
|
||||
self.box = box
|
||||
}
|
||||
|
||||
/// Returns a `Guarantee` sealed with the provided value.
|
||||
public static func value(_ value: T) -> Guarantee<T> {
|
||||
return .init(box: SealedBox(value: value))
|
||||
}
|
||||
|
||||
/// Returns a pending `Guarantee` that can be resolved with the provided closure’s parameter.
|
||||
public init(resolver body: (@escaping(T) -> Void) -> Void) {
|
||||
box = EmptyBox()
|
||||
body(box.seal)
|
||||
}
|
||||
|
||||
/// - See: `Thenable.pipe`
|
||||
public func pipe(to: @escaping(Result<T>) -> Void) {
|
||||
pipe{ to(.fulfilled($0)) }
|
||||
}
|
||||
|
||||
func pipe(to: @escaping(T) -> Void) {
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
box.inspect {
|
||||
switch $0 {
|
||||
case .pending(let handlers):
|
||||
handlers.append(to)
|
||||
case .resolved(let value):
|
||||
to(value)
|
||||
}
|
||||
}
|
||||
case .resolved(let value):
|
||||
to(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// - See: `Thenable.result`
|
||||
public var result: Result<T>? {
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
return nil
|
||||
case .resolved(let value):
|
||||
return .fulfilled(value)
|
||||
}
|
||||
}
|
||||
|
||||
init(_: PMKUnambiguousInitializer) {
|
||||
box = EmptyBox()
|
||||
}
|
||||
|
||||
/// Returns a tuple of a pending `Guarantee` and a function that resolves it.
|
||||
public class func pending() -> (guarantee: Guarantee<T>, resolve: (T) -> Void) {
|
||||
return { ($0, $0.box.seal) }(Guarantee<T>(.pending))
|
||||
}
|
||||
}
|
||||
|
||||
public extension Guarantee {
|
||||
@discardableResult
|
||||
func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Void) -> Guarantee<Void> {
|
||||
let rg = Guarantee<Void>(.pending)
|
||||
pipe { (value: T) in
|
||||
on.async(flags: flags) {
|
||||
body(value)
|
||||
rg.box.seal(())
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) -> Void) -> Guarantee<T> {
|
||||
return map(on: on, flags: flags) {
|
||||
body($0)
|
||||
return $0
|
||||
}
|
||||
}
|
||||
|
||||
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> U) -> Guarantee<U> {
|
||||
let rg = Guarantee<U>(.pending)
|
||||
pipe { value in
|
||||
on.async(flags: flags) {
|
||||
rg.box.seal(body(value))
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func then<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Guarantee<U>) -> Guarantee<U> {
|
||||
let rg = Guarantee<U>(.pending)
|
||||
pipe { value in
|
||||
on.async(flags: flags) {
|
||||
body(value).pipe(to: rg.box.seal)
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
public func asVoid() -> Guarantee<Void> {
|
||||
return map(on: nil) { _ in }
|
||||
}
|
||||
|
||||
/**
|
||||
Blocks this thread, so you know, don’t call this on a serial thread that
|
||||
any part of your chain may use. Like the main thread for example.
|
||||
*/
|
||||
public func wait() -> T {
|
||||
|
||||
if Thread.isMainThread {
|
||||
print("PromiseKit: warning: `wait()` called on main thread!")
|
||||
}
|
||||
|
||||
var result = value
|
||||
|
||||
if result == nil {
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
pipe { (foo: T) in result = foo; group.leave() }
|
||||
group.wait()
|
||||
}
|
||||
|
||||
return result!
|
||||
}
|
||||
}
|
||||
|
||||
public extension Guarantee where T: Sequence {
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> `Guarantee<U>` => `Guaranetee<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.thenMap {
|
||||
.value($0 * 2)
|
||||
}.done {
|
||||
// $0 => [2,4,6]
|
||||
}
|
||||
*/
|
||||
func thenMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> Guarantee<U>) -> Guarantee<[U]> {
|
||||
return then(on: on, flags: flags) {
|
||||
when(fulfilled: $0.map(transform))
|
||||
}.recover {
|
||||
// if happens then is bug inside PromiseKit
|
||||
fatalError(String(describing: $0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=3.1)
|
||||
public extension Guarantee where T == Void {
|
||||
convenience init() {
|
||||
self.init(box: SealedBox(value: Void()))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public extension DispatchQueue {
|
||||
/**
|
||||
Asynchronously executes the provided closure on a dispatch queue.
|
||||
|
||||
DispatchQueue.global().async(.promise) {
|
||||
md5(input)
|
||||
}.done { md5 in
|
||||
//…
|
||||
}
|
||||
|
||||
- Parameter body: The closure that resolves this promise.
|
||||
- Returns: A new `Guarantee` resolved by the result of the provided closure.
|
||||
- Note: There is no Promise/Thenable version of this due to Swift compiler ambiguity issues.
|
||||
*/
|
||||
@available(macOS 10.10, iOS 2.0, tvOS 10.0, watchOS 2.0, *)
|
||||
final func async<T>(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS = .default, flags: DispatchWorkItemFlags = [], execute body: @escaping () -> T) -> Guarantee<T> {
|
||||
let rg = Guarantee<T>(.pending)
|
||||
async(group: group, qos: qos, flags: flags) {
|
||||
rg.box.seal(body())
|
||||
}
|
||||
return rg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if os(Linux)
|
||||
import func CoreFoundation._CFIsMainThread
|
||||
|
||||
extension Thread {
|
||||
// `isMainThread` is not implemented yet in swift-corelibs-foundation.
|
||||
static var isMainThread: Bool {
|
||||
return _CFIsMainThread()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
28
Carthage/Checkouts/PromiseKit/Sources/Info.plist
vendored
Normal file
28
Carthage/Checkouts/PromiseKit/Sources/Info.plist
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
77
Carthage/Checkouts/PromiseKit/Sources/NSMethodSignatureForBlock.m
vendored
Normal file
77
Carthage/Checkouts/PromiseKit/Sources/NSMethodSignatureForBlock.m
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
#import <Foundation/NSMethodSignature.h>
|
||||
|
||||
struct PMKBlockLiteral {
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(void *, ...);
|
||||
struct block_descriptor {
|
||||
unsigned long int reserved; // NULL
|
||||
unsigned long int size; // sizeof(struct Block_literal_1)
|
||||
// optional helper functions
|
||||
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
|
||||
void (*dispose_helper)(void *src); // IFF (1<<25)
|
||||
// required ABI.2010.3.16
|
||||
const char *signature; // IFF (1<<30)
|
||||
} *descriptor;
|
||||
// imported variables
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, PMKBlockDescriptionFlags) {
|
||||
PMKBlockDescriptionFlagsHasCopyDispose = (1 << 25),
|
||||
PMKBlockDescriptionFlagsHasCtor = (1 << 26), // helpers have C++ code
|
||||
PMKBlockDescriptionFlagsIsGlobal = (1 << 28),
|
||||
PMKBlockDescriptionFlagsHasStret = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
|
||||
PMKBlockDescriptionFlagsHasSignature = (1 << 30)
|
||||
};
|
||||
|
||||
// It appears 10.7 doesn't support quotes in method signatures. Remove them
|
||||
// via @rabovik's method. See https://github.com/OliverLetterer/SLObjectiveCRuntimeAdditions/pull/2
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8
|
||||
NS_INLINE static const char * pmk_removeQuotesFromMethodSignature(const char *str){
|
||||
char *result = malloc(strlen(str) + 1);
|
||||
BOOL skip = NO;
|
||||
char *to = result;
|
||||
char c;
|
||||
while ((c = *str++)) {
|
||||
if ('"' == c) {
|
||||
skip = !skip;
|
||||
continue;
|
||||
}
|
||||
if (skip) continue;
|
||||
*to++ = c;
|
||||
}
|
||||
*to = '\0';
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static NSMethodSignature *NSMethodSignatureForBlock(id block) {
|
||||
if (!block)
|
||||
return nil;
|
||||
|
||||
struct PMKBlockLiteral *blockRef = (__bridge struct PMKBlockLiteral *)block;
|
||||
PMKBlockDescriptionFlags flags = (PMKBlockDescriptionFlags)blockRef->flags;
|
||||
|
||||
if (flags & PMKBlockDescriptionFlagsHasSignature) {
|
||||
void *signatureLocation = blockRef->descriptor;
|
||||
signatureLocation += sizeof(unsigned long int);
|
||||
signatureLocation += sizeof(unsigned long int);
|
||||
|
||||
if (flags & PMKBlockDescriptionFlagsHasCopyDispose) {
|
||||
signatureLocation += sizeof(void(*)(void *dst, void *src));
|
||||
signatureLocation += sizeof(void (*)(void *src));
|
||||
}
|
||||
|
||||
const char *signature = (*(const char **)signatureLocation);
|
||||
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8
|
||||
signature = pmk_removeQuotesFromMethodSignature(signature);
|
||||
NSMethodSignature *nsSignature = [NSMethodSignature signatureWithObjCTypes:signature];
|
||||
free((void *)signature);
|
||||
|
||||
return nsSignature;
|
||||
#endif
|
||||
return [NSMethodSignature signatureWithObjCTypes:signature];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
120
Carthage/Checkouts/PromiseKit/Sources/PMKCallVariadicBlock.m
vendored
Normal file
120
Carthage/Checkouts/PromiseKit/Sources/PMKCallVariadicBlock.m
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
#import "NSMethodSignatureForBlock.m"
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import "AnyPromise+Private.h"
|
||||
#import <Foundation/NSError.h>
|
||||
#import <dispatch/once.h>
|
||||
#import <string.h>
|
||||
|
||||
#ifndef PMKLog
|
||||
#define PMKLog NSLog
|
||||
#endif
|
||||
|
||||
@interface PMKArray : NSObject {
|
||||
@public
|
||||
id objs[3];
|
||||
NSUInteger count;
|
||||
} @end
|
||||
|
||||
@implementation PMKArray
|
||||
|
||||
- (id)objectAtIndexedSubscript:(NSUInteger)idx {
|
||||
if (count <= idx) {
|
||||
// this check is necessary due to lack of checks in `pmk_safely_call_block`
|
||||
return nil;
|
||||
}
|
||||
return objs[idx];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
id __PMKArrayWithCount(NSUInteger count, ...) {
|
||||
PMKArray *this = [PMKArray new];
|
||||
this->count = count;
|
||||
va_list args;
|
||||
va_start(args, count);
|
||||
for (NSUInteger x = 0; x < count; ++x)
|
||||
this->objs[x] = va_arg(args, id);
|
||||
va_end(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
static inline id _PMKCallVariadicBlock(id frock, id result) {
|
||||
NSCAssert(frock, @"");
|
||||
|
||||
NSMethodSignature *sig = NSMethodSignatureForBlock(frock);
|
||||
const NSUInteger nargs = sig.numberOfArguments;
|
||||
const char rtype = sig.methodReturnType[0];
|
||||
|
||||
#define call_block_with_rtype(type) ({^type{ \
|
||||
switch (nargs) { \
|
||||
case 1: \
|
||||
return ((type(^)(void))frock)(); \
|
||||
case 2: { \
|
||||
const id arg = [result class] == [PMKArray class] ? result[0] : result; \
|
||||
return ((type(^)(id))frock)(arg); \
|
||||
} \
|
||||
case 3: { \
|
||||
type (^block)(id, id) = frock; \
|
||||
return [result class] == [PMKArray class] \
|
||||
? block(result[0], result[1]) \
|
||||
: block(result, nil); \
|
||||
} \
|
||||
case 4: { \
|
||||
type (^block)(id, id, id) = frock; \
|
||||
return [result class] == [PMKArray class] \
|
||||
? block(result[0], result[1], result[2]) \
|
||||
: block(result, nil, nil); \
|
||||
} \
|
||||
default: \
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"PromiseKit: The provided block’s argument count is unsupported." userInfo:nil]; \
|
||||
}}();})
|
||||
|
||||
switch (rtype) {
|
||||
case 'v':
|
||||
call_block_with_rtype(void);
|
||||
return nil;
|
||||
case '@':
|
||||
return call_block_with_rtype(id) ?: nil;
|
||||
case '*': {
|
||||
char *str = call_block_with_rtype(char *);
|
||||
return str ? @(str) : nil;
|
||||
}
|
||||
case 'c': return @(call_block_with_rtype(char));
|
||||
case 'i': return @(call_block_with_rtype(int));
|
||||
case 's': return @(call_block_with_rtype(short));
|
||||
case 'l': return @(call_block_with_rtype(long));
|
||||
case 'q': return @(call_block_with_rtype(long long));
|
||||
case 'C': return @(call_block_with_rtype(unsigned char));
|
||||
case 'I': return @(call_block_with_rtype(unsigned int));
|
||||
case 'S': return @(call_block_with_rtype(unsigned short));
|
||||
case 'L': return @(call_block_with_rtype(unsigned long));
|
||||
case 'Q': return @(call_block_with_rtype(unsigned long long));
|
||||
case 'f': return @(call_block_with_rtype(float));
|
||||
case 'd': return @(call_block_with_rtype(double));
|
||||
case 'B': return @(call_block_with_rtype(_Bool));
|
||||
case '^':
|
||||
if (strcmp(sig.methodReturnType, "^v") == 0) {
|
||||
call_block_with_rtype(void);
|
||||
return nil;
|
||||
}
|
||||
// else fall through!
|
||||
default:
|
||||
@throw [NSException exceptionWithName:@"PromiseKit" reason:@"PromiseKit: Unsupported method signature." userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
static id PMKCallVariadicBlock(id frock, id result) {
|
||||
@try {
|
||||
return _PMKCallVariadicBlock(frock, result);
|
||||
} @catch (id thrown) {
|
||||
if ([thrown isKindOfClass:[NSString class]])
|
||||
return thrown;
|
||||
if ([thrown isKindOfClass:[NSError class]])
|
||||
return thrown;
|
||||
|
||||
// we don’t catch objc exceptions: they are meant to crash your app
|
||||
@throw thrown;
|
||||
}
|
||||
}
|
||||
179
Carthage/Checkouts/PromiseKit/Sources/Promise.swift
vendored
Normal file
179
Carthage/Checkouts/PromiseKit/Sources/Promise.swift
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
import class Foundation.Thread
|
||||
import Dispatch
|
||||
|
||||
/**
|
||||
A `Promise` is a functional abstraction around a failable asynchronous operation.
|
||||
- See: `Thenable`
|
||||
*/
|
||||
public class Promise<T>: Thenable, CatchMixin {
|
||||
let box: Box<Result<T>>
|
||||
|
||||
fileprivate init(box: SealedBox<Result<T>>) {
|
||||
self.box = box
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize a new fulfilled promise.
|
||||
|
||||
We do not provide `init(value:)` because Swift is “greedy”
|
||||
and would pick that initializer in cases where it should pick
|
||||
one of the other more specific options leading to Promises with
|
||||
`T` that is eg: `Error` or worse `(T->Void,Error->Void)` for
|
||||
uses of our PMK < 4 pending initializer due to Swift trailing
|
||||
closure syntax (nothing good comes without pain!).
|
||||
|
||||
Though often easy to detect, sometimes these issues would be
|
||||
hidden by other type inference leading to some nasty bugs in
|
||||
production.
|
||||
|
||||
In PMK5 we tried to work around this by making the pending
|
||||
initializer take the form `Promise(.pending)` but this led to
|
||||
bad migration errors for PMK4 users. Hence instead we quickly
|
||||
released PMK6 and now only provide this initializer for making
|
||||
sealed & fulfilled promises.
|
||||
|
||||
Usage is still (usually) good:
|
||||
|
||||
guard foo else {
|
||||
return .value(bar)
|
||||
}
|
||||
*/
|
||||
public class func value(_ value: T) -> Promise<T> {
|
||||
return Promise(box: SealedBox(value: .fulfilled(value)))
|
||||
}
|
||||
|
||||
/// Initialize a new rejected promise.
|
||||
public init(error: Error) {
|
||||
box = SealedBox(value: .rejected(error))
|
||||
}
|
||||
|
||||
/// Initialize a new promise bound to the provided `Thenable`.
|
||||
public init<U: Thenable>(_ bridge: U) where U.T == T {
|
||||
box = EmptyBox()
|
||||
bridge.pipe(to: box.seal)
|
||||
}
|
||||
|
||||
/// Initialize a new promise that can be resolved with the provided `Resolver`.
|
||||
public init(resolver body: (Resolver<T>) throws -> Void) {
|
||||
box = EmptyBox()
|
||||
let resolver = Resolver(box)
|
||||
do {
|
||||
try body(resolver)
|
||||
} catch {
|
||||
resolver.reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// - Returns: a tuple of a new pending promise and its `Resolver`.
|
||||
public class func pending() -> (promise: Promise<T>, resolver: Resolver<T>) {
|
||||
return { ($0, Resolver($0.box)) }(Promise<T>(.pending))
|
||||
}
|
||||
|
||||
/// - See: `Thenable.pipe`
|
||||
public func pipe(to: @escaping(Result<T>) -> Void) {
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
box.inspect {
|
||||
switch $0 {
|
||||
case .pending(let handlers):
|
||||
handlers.append(to)
|
||||
case .resolved(let value):
|
||||
to(value)
|
||||
}
|
||||
}
|
||||
case .resolved(let value):
|
||||
to(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// - See: `Thenable.result`
|
||||
public var result: Result<T>? {
|
||||
switch box.inspect() {
|
||||
case .pending:
|
||||
return nil
|
||||
case .resolved(let result):
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
init(_: PMKUnambiguousInitializer) {
|
||||
box = EmptyBox()
|
||||
}
|
||||
}
|
||||
|
||||
public extension Promise {
|
||||
/**
|
||||
Blocks this thread, so—you know—don’t call this on a serial thread that
|
||||
any part of your chain may use. Like the main thread for example.
|
||||
*/
|
||||
func wait() throws -> T {
|
||||
|
||||
if Thread.isMainThread {
|
||||
Swift.print("PromiseKit: warning: `wait()` called on main thread!")
|
||||
}
|
||||
|
||||
var result = self.result
|
||||
|
||||
if result == nil {
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
pipe { result = $0; group.leave() }
|
||||
group.wait()
|
||||
}
|
||||
|
||||
switch result! {
|
||||
case .rejected(let error):
|
||||
throw error
|
||||
case .fulfilled(let value):
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=3.1)
|
||||
extension Promise where T == Void {
|
||||
/// Initializes a new promise fulfilled with `Void`
|
||||
public convenience init() {
|
||||
self.init(box: SealedBox(value: .fulfilled(Void())))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public extension DispatchQueue {
|
||||
/**
|
||||
Asynchronously executes the provided closure on a dispatch queue.
|
||||
|
||||
DispatchQueue.global().async(.promise) {
|
||||
try md5(input)
|
||||
}.done { md5 in
|
||||
//…
|
||||
}
|
||||
|
||||
- Parameter body: The closure that resolves this promise.
|
||||
- Returns: A new `Promise` resolved by the result of the provided closure.
|
||||
- Note: There is no Promise/Thenable version of this due to Swift compiler ambiguity issues.
|
||||
*/
|
||||
@available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *)
|
||||
final func async<T>(_: PMKNamespacer, group: DispatchGroup? = nil, qos: DispatchQoS = .default, flags: DispatchWorkItemFlags = [], execute body: @escaping () throws -> T) -> Promise<T> {
|
||||
let promise = Promise<T>(.pending)
|
||||
async(group: group, qos: qos, flags: flags) {
|
||||
do {
|
||||
promise.box.seal(.fulfilled(try body()))
|
||||
} catch {
|
||||
promise.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return promise
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// used by our extensions to provide unambiguous functions with the same name as the original function
|
||||
public enum PMKNamespacer {
|
||||
case promise
|
||||
}
|
||||
|
||||
enum PMKUnambiguousInitializer {
|
||||
case pending
|
||||
}
|
||||
7
Carthage/Checkouts/PromiseKit/Sources/PromiseKit.h
vendored
Normal file
7
Carthage/Checkouts/PromiseKit/Sources/PromiseKit.h
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
#import "fwd.h"
|
||||
#import "AnyPromise.h"
|
||||
|
||||
#import <Foundation/NSObjCRuntime.h> // `FOUNDATION_EXPORT`
|
||||
|
||||
FOUNDATION_EXPORT double PromiseKitVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char PromiseKitVersionString[];
|
||||
85
Carthage/Checkouts/PromiseKit/Sources/Resolver.swift
vendored
Normal file
85
Carthage/Checkouts/PromiseKit/Sources/Resolver.swift
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/// An object for resolving promises
|
||||
public class Resolver<T> {
|
||||
let box: Box<Result<T>>
|
||||
|
||||
init(_ box: Box<Result<T>>) {
|
||||
self.box = box
|
||||
}
|
||||
|
||||
deinit {
|
||||
if case .pending = box.inspect() {
|
||||
print("PromiseKit: warning: pending promise deallocated")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Resolver {
|
||||
/// Fulfills the promise with the provided value
|
||||
func fulfill(_ value: T) {
|
||||
box.seal(.fulfilled(value))
|
||||
}
|
||||
|
||||
/// Rejects the promise with the provided error
|
||||
func reject(_ error: Error) {
|
||||
box.seal(.rejected(error))
|
||||
}
|
||||
|
||||
/// Resolves the promise with the provided result
|
||||
public func resolve(_ result: Result<T>) {
|
||||
box.seal(result)
|
||||
}
|
||||
|
||||
/// Resolves the promise with the provided value or error
|
||||
public func resolve(_ obj: T?, _ error: Error?) {
|
||||
if let error = error {
|
||||
reject(error)
|
||||
} else if let obj = obj {
|
||||
fulfill(obj)
|
||||
} else {
|
||||
reject(PMKError.invalidCallingConvention)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fulfills the promise with the provided value unless the provided error is non-nil
|
||||
public func resolve(_ obj: T, _ error: Error?) {
|
||||
if let error = error {
|
||||
reject(error)
|
||||
} else {
|
||||
fulfill(obj)
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the promise, provided for non-conventional value-error ordered completion handlers.
|
||||
public func resolve(_ error: Error?, _ obj: T?) {
|
||||
resolve(obj, error)
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=3.1)
|
||||
extension Resolver where T == Void {
|
||||
/// Fulfills the promise unless error is non-nil
|
||||
public func resolve(_ error: Error?) {
|
||||
if let error = error {
|
||||
reject(error)
|
||||
} else {
|
||||
fulfill(())
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public enum Result<T> {
|
||||
case fulfilled(T)
|
||||
case rejected(Error)
|
||||
}
|
||||
|
||||
public extension PromiseKit.Result {
|
||||
var isFulfilled: Bool {
|
||||
switch self {
|
||||
case .fulfilled:
|
||||
return true
|
||||
case .rejected:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
424
Carthage/Checkouts/PromiseKit/Sources/Thenable.swift
vendored
Normal file
424
Carthage/Checkouts/PromiseKit/Sources/Thenable.swift
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
import Dispatch
|
||||
|
||||
/// Thenable represents an asynchronous operation that can be chained.
|
||||
public protocol Thenable: class {
|
||||
/// The type of the wrapped value
|
||||
associatedtype T
|
||||
|
||||
/// `pipe` is immediately executed when this `Thenable` is resolved
|
||||
func pipe(to: @escaping(Result<T>) -> Void)
|
||||
|
||||
/// The resolved result or nil if pending.
|
||||
var result: Result<T>? { get }
|
||||
}
|
||||
|
||||
public extension Thenable {
|
||||
/**
|
||||
The provided closure executes when this promise resolves.
|
||||
|
||||
This allows chaining promises. The promise returned by the provided closure is resolved before the promise returned by this closure resolves.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that executes when this promise fulfills. It must return a promise.
|
||||
- Returns: A new promise that resolves when the promise returned from the provided closure resolves. For example:
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(.promise, with: url1)
|
||||
}.then { response in
|
||||
transform(data: response.data)
|
||||
}.done { transformation in
|
||||
//…
|
||||
}
|
||||
*/
|
||||
func then<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise<U.T> {
|
||||
let rp = Promise<U.T>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
let rv = try body(value)
|
||||
guard rv !== rp else { throw PMKError.returnedSelf }
|
||||
rv.pipe(to: rp.box.seal)
|
||||
} catch {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
case .rejected(let error):
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
|
||||
This is like `then` but it requires the closure to return a non-promise.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter transform: The closure that is executed when this Promise is fulfilled. It must return a non-promise.
|
||||
- Returns: A new promise that is resolved with the value returned from the provided closure. For example:
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(.promise, with: url1)
|
||||
}.map { response in
|
||||
response.data.length
|
||||
}.done { length in
|
||||
//…
|
||||
}
|
||||
*/
|
||||
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U) -> Promise<U> {
|
||||
let rp = Promise<U>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
rp.box.seal(.fulfilled(try transform(value)))
|
||||
} catch {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
case .rejected(let error):
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
|
||||
In your closure return an `Optional`, if you return `nil` the resulting promise is rejected with `PMKError.compactMap`, otherwise the promise is fulfilled with the unwrapped value.
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(.promise, with: url)
|
||||
}.compactMap {
|
||||
try JSONSerialization.jsonObject(with: $0.data) as? [String: String]
|
||||
}.done { dictionary in
|
||||
//…
|
||||
}.catch {
|
||||
// either `PMKError.compactMap` or a `JSONError`
|
||||
}
|
||||
*/
|
||||
func compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise<U> {
|
||||
let rp = Promise<U>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
if let rv = try transform(value) {
|
||||
rp.box.seal(.fulfilled(rv))
|
||||
} else {
|
||||
throw PMKError.compactMap(value, U.self)
|
||||
}
|
||||
} catch {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
case .rejected(let error):
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
|
||||
Equivalent to `map { x -> Void in`, but since we force the `Void` return Swift
|
||||
is happier and gives you less hassle about your closure’s qualification.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that is executed when this Promise is fulfilled.
|
||||
- Returns: A new promise fulfilled as `Void`.
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(.promise, with: url)
|
||||
}.done { response in
|
||||
print(response.data)
|
||||
}
|
||||
*/
|
||||
func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> Promise<Void> {
|
||||
let rp = Promise<Void>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
try body(value)
|
||||
rp.box.seal(.fulfilled(()))
|
||||
} catch {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
case .rejected(let error):
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
|
||||
This is like `done` but it returns the same value that the handler is fed.
|
||||
`get` immutably accesses the fulfilled value; the returned Promise maintains that value.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that is executed when this Promise is fulfilled.
|
||||
- Returns: A new promise that is resolved with the value that the handler is fed. For example:
|
||||
|
||||
firstly {
|
||||
.value(1)
|
||||
}.get { foo in
|
||||
print(foo, " is 1")
|
||||
}.done { foo in
|
||||
print(foo, " is 1")
|
||||
}.done { foo in
|
||||
print(foo, " is Void")
|
||||
}
|
||||
*/
|
||||
func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> Promise<T> {
|
||||
return map(on: on, flags: flags) {
|
||||
try body($0)
|
||||
return $0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed with promise result.
|
||||
|
||||
This is like `get` but provides the Result<T> of the Promise so you can inspect the value of the chain at this point without causing any side effects.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that is executed with Result of Promise.
|
||||
- Returns: A new promise that is resolved with the result that the handler is fed. For example:
|
||||
|
||||
promise.tap{ print($0) }.then{ /*…*/ }
|
||||
*/
|
||||
func tap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result<T>) -> Void) -> Promise<T> {
|
||||
return Promise { seal in
|
||||
pipe { result in
|
||||
on.async(flags: flags) {
|
||||
body(result)
|
||||
seal.resolve(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// - Returns: a new promise chained off this promise but with its value discarded.
|
||||
func asVoid() -> Promise<Void> {
|
||||
return map(on: nil) { _ in }
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable {
|
||||
/**
|
||||
- Returns: The error with which this promise was rejected; `nil` if this promise is not rejected.
|
||||
*/
|
||||
var error: Error? {
|
||||
switch result {
|
||||
case .none:
|
||||
return nil
|
||||
case .some(.fulfilled):
|
||||
return nil
|
||||
case .some(.rejected(let error)):
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
- Returns: `true` if the promise has not yet resolved.
|
||||
*/
|
||||
var isPending: Bool {
|
||||
return result == nil
|
||||
}
|
||||
|
||||
/**
|
||||
- Returns: `true` if the promise has resolved.
|
||||
*/
|
||||
var isResolved: Bool {
|
||||
return !isPending
|
||||
}
|
||||
|
||||
/**
|
||||
- Returns: `true` if the promise was fulfilled.
|
||||
*/
|
||||
var isFulfilled: Bool {
|
||||
return value != nil
|
||||
}
|
||||
|
||||
/**
|
||||
- Returns: `true` if the promise was rejected.
|
||||
*/
|
||||
var isRejected: Bool {
|
||||
return error != nil
|
||||
}
|
||||
|
||||
/**
|
||||
- Returns: The value with which this promise was fulfilled or `nil` if this promise is pending or rejected.
|
||||
*/
|
||||
var value: T? {
|
||||
switch result {
|
||||
case .none:
|
||||
return nil
|
||||
case .some(.fulfilled(let value)):
|
||||
return value
|
||||
case .some(.rejected):
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable where T: Sequence {
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `U` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.mapValues { integer in
|
||||
integer * 2
|
||||
}.done {
|
||||
// $0 => [2,4,6]
|
||||
}
|
||||
*/
|
||||
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]> {
|
||||
return map(on: on, flags: flags){ try $0.map(transform) }
|
||||
}
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `[U]` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.flatMapValues { integer in
|
||||
[integer, integer]
|
||||
}.done {
|
||||
// $0 => [1,1,2,2,3,3]
|
||||
}
|
||||
*/
|
||||
func flatMapValues<U: Sequence>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.Iterator.Element]> {
|
||||
return map(on: on, flags: flags){ (foo: T) in
|
||||
try foo.flatMap{ try transform($0) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `U?` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value(["1","2","a","3"])
|
||||
}.compactMapValues {
|
||||
Int($0)
|
||||
}.done {
|
||||
// $0 => [1,2,3]
|
||||
}
|
||||
*/
|
||||
func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U?) -> Promise<[U]> {
|
||||
return map(on: on, flags: flags) { foo -> [U] in
|
||||
#if !swift(>=3.3) || (swift(>=4) && !swift(>=4.1))
|
||||
return try foo.flatMap(transform)
|
||||
#else
|
||||
return try foo.compactMap(transform)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `Promise<U>` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.thenMap { integer in
|
||||
.value(integer * 2)
|
||||
}.done {
|
||||
// $0 => [2,4,6]
|
||||
}
|
||||
*/
|
||||
func thenMap<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T]> {
|
||||
return then(on: on, flags: flags) {
|
||||
when(fulfilled: try $0.map(transform))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `Promise<[U]>` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.thenFlatMap { integer in
|
||||
.value([integer, integer])
|
||||
}.done {
|
||||
// $0 => [1,1,2,2,3,3]
|
||||
}
|
||||
*/
|
||||
func thenFlatMap<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U.T.Iterator.Element]> where U.T: Sequence {
|
||||
return then(on: on, flags: flags) {
|
||||
when(fulfilled: try $0.map(transform))
|
||||
}.map(on: nil) {
|
||||
$0.flatMap{ $0 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> Bool => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.filterValues {
|
||||
$0 > 1
|
||||
}.done {
|
||||
// $0 => [2,3]
|
||||
}
|
||||
*/
|
||||
func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ isIncluded: @escaping (T.Iterator.Element) -> Bool) -> Promise<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) {
|
||||
$0.filter(isIncluded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable where T: Collection {
|
||||
/// - Returns: a promise fulfilled with the first value of this `Collection` or, if empty, a promise rejected with PMKError.emptySequence.
|
||||
var firstValue: Promise<T.Iterator.Element> {
|
||||
return map(on: nil) { aa in
|
||||
if let a1 = aa.first {
|
||||
return a1
|
||||
} else {
|
||||
throw PMKError.emptySequence
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func firstValue(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, where test: @escaping (T.Iterator.Element) -> Bool) -> Promise<T.Iterator.Element> {
|
||||
return map(on: on, flags: flags) {
|
||||
for x in $0 where test(x) {
|
||||
return x
|
||||
}
|
||||
throw PMKError.emptySequence
|
||||
}
|
||||
}
|
||||
|
||||
/// - Returns: a promise fulfilled with the last value of this `Collection` or, if empty, a promise rejected with PMKError.emptySequence.
|
||||
var lastValue: Promise<T.Iterator.Element> {
|
||||
return map(on: nil) { aa in
|
||||
if aa.isEmpty {
|
||||
throw PMKError.emptySequence
|
||||
} else {
|
||||
let i = aa.index(aa.endIndex, offsetBy: -1)
|
||||
return aa[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Thenable where T: Sequence, T.Iterator.Element: Comparable {
|
||||
/// - Returns: a promise fulfilled with the sorted values of this `Sequence`.
|
||||
func sortedValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil) -> Promise<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags){ $0.sorted() }
|
||||
}
|
||||
}
|
||||
14
Carthage/Checkouts/PromiseKit/Sources/after.m
vendored
Normal file
14
Carthage/Checkouts/PromiseKit/Sources/after.m
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#import "AnyPromise.h"
|
||||
@import Dispatch;
|
||||
@import Foundation.NSDate;
|
||||
@import Foundation.NSValue;
|
||||
|
||||
/// @return A promise that fulfills after the specified duration.
|
||||
AnyPromise *PMKAfter(NSTimeInterval duration) {
|
||||
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC));
|
||||
dispatch_after(time, dispatch_get_global_queue(0, 0), ^{
|
||||
resolve(@(duration));
|
||||
});
|
||||
}];
|
||||
}
|
||||
46
Carthage/Checkouts/PromiseKit/Sources/after.swift
vendored
Normal file
46
Carthage/Checkouts/PromiseKit/Sources/after.swift
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import struct Foundation.TimeInterval
|
||||
import Dispatch
|
||||
|
||||
/**
|
||||
after(.seconds(2)).then {
|
||||
//…
|
||||
}
|
||||
|
||||
- Returns: A guarantee that resolves after the specified duration.
|
||||
*/
|
||||
public func after(seconds: TimeInterval) -> Guarantee<Void> {
|
||||
let (rg, seal) = Guarantee<Void>.pending()
|
||||
let when = DispatchTime.now() + seconds
|
||||
#if swift(>=4.0)
|
||||
q.asyncAfter(deadline: when) { seal(()) }
|
||||
#else
|
||||
q.asyncAfter(deadline: when, execute: seal)
|
||||
#endif
|
||||
return rg
|
||||
}
|
||||
|
||||
/**
|
||||
after(seconds: 1.5).then {
|
||||
//…
|
||||
}
|
||||
|
||||
- Returns: A guarantee that resolves after the specified duration.
|
||||
*/
|
||||
public func after(_ interval: DispatchTimeInterval) -> Guarantee<Void> {
|
||||
let (rg, seal) = Guarantee<Void>.pending()
|
||||
let when = DispatchTime.now() + interval
|
||||
#if swift(>=4.0)
|
||||
q.asyncAfter(deadline: when) { seal(()) }
|
||||
#else
|
||||
q.asyncAfter(deadline: when, execute: seal)
|
||||
#endif
|
||||
return rg
|
||||
}
|
||||
|
||||
private var q: DispatchQueue {
|
||||
if #available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *) {
|
||||
return DispatchQueue.global(qos: .default)
|
||||
} else {
|
||||
return DispatchQueue.global(priority: .default)
|
||||
}
|
||||
}
|
||||
10
Carthage/Checkouts/PromiseKit/Sources/dispatch_promise.m
vendored
Normal file
10
Carthage/Checkouts/PromiseKit/Sources/dispatch_promise.m
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#import "AnyPromise.h"
|
||||
@import Dispatch;
|
||||
|
||||
AnyPromise *dispatch_promise_on(dispatch_queue_t queue, id block) {
|
||||
return [AnyPromise promiseWithValue:nil].thenOn(queue, block);
|
||||
}
|
||||
|
||||
AnyPromise *dispatch_promise(id block) {
|
||||
return dispatch_promise_on(dispatch_get_global_queue(0, 0), block);
|
||||
}
|
||||
39
Carthage/Checkouts/PromiseKit/Sources/firstly.swift
vendored
Normal file
39
Carthage/Checkouts/PromiseKit/Sources/firstly.swift
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import Dispatch
|
||||
|
||||
/**
|
||||
Judicious use of `firstly` *may* make chains more readable.
|
||||
|
||||
Compare:
|
||||
|
||||
URLSession.shared.dataTask(url: url1).then {
|
||||
URLSession.shared.dataTask(url: url2)
|
||||
}.then {
|
||||
URLSession.shared.dataTask(url: url3)
|
||||
}
|
||||
|
||||
With:
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(url: url1)
|
||||
}.then {
|
||||
URLSession.shared.dataTask(url: url2)
|
||||
}.then {
|
||||
URLSession.shared.dataTask(url: url3)
|
||||
}
|
||||
|
||||
- Note: the block you pass excecutes immediately on the current thread/queue.
|
||||
*/
|
||||
public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> {
|
||||
do {
|
||||
let rp = Promise<U.T>(.pending)
|
||||
try body().pipe(to: rp.box.seal)
|
||||
return rp
|
||||
} catch {
|
||||
return Promise(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
/// - See: firstly()
|
||||
public func firstly<T>(execute body: () -> Guarantee<T>) -> Guarantee<T> {
|
||||
return body()
|
||||
}
|
||||
165
Carthage/Checkouts/PromiseKit/Sources/fwd.h
vendored
Normal file
165
Carthage/Checkouts/PromiseKit/Sources/fwd.h
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <dispatch/dispatch.h>
|
||||
|
||||
@class AnyPromise;
|
||||
extern NSString * __nonnull const PMKErrorDomain;
|
||||
|
||||
#define PMKFailingPromiseIndexKey @"PMKFailingPromiseIndexKey"
|
||||
#define PMKJoinPromisesKey @"PMKJoinPromisesKey"
|
||||
|
||||
#define PMKUnexpectedError 1l
|
||||
#define PMKInvalidUsageError 3l
|
||||
#define PMKAccessDeniedError 4l
|
||||
#define PMKOperationFailed 8l
|
||||
#define PMKTaskError 9l
|
||||
#define PMKJoinError 10l
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
@return A new promise that resolves after the specified duration.
|
||||
|
||||
@parameter duration The duration in seconds to wait before this promise is resolve.
|
||||
|
||||
For example:
|
||||
|
||||
PMKAfter(1).then(^{
|
||||
//…
|
||||
});
|
||||
*/
|
||||
extern AnyPromise * __nonnull PMKAfter(NSTimeInterval duration) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
`when` is a mechanism for waiting more than one asynchronous task and responding when they are all complete.
|
||||
|
||||
`PMKWhen` accepts varied input. If an array is passed then when those promises fulfill, when’s promise fulfills with an array of fulfillment values. If a dictionary is passed then the same occurs, but when’s promise fulfills with a dictionary of fulfillments keyed as per the input.
|
||||
|
||||
Interestingly, if a single promise is passed then when waits on that single promise, and if a single non-promise object is passed then when fulfills immediately with that object. If the array or dictionary that is passed contains objects that are not promises, then these objects are considered fulfilled promises. The reason we do this is to allow a pattern know as "abstracting away asynchronicity".
|
||||
|
||||
If *any* of the provided promises reject, the returned promise is immediately rejected with that promise’s rejection. The error’s `userInfo` object is supplemented with `PMKFailingPromiseIndexKey`.
|
||||
|
||||
For example:
|
||||
|
||||
PMKWhen(@[promise1, promise2]).then(^(NSArray *results){
|
||||
//…
|
||||
});
|
||||
|
||||
@warning *Important* In the event of rejection the other promises will continue to resolve and as per any other promise will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed. In such situations use `PMKJoin`.
|
||||
|
||||
@param input The input upon which to wait before resolving this promise.
|
||||
|
||||
@return A promise that is resolved with either:
|
||||
|
||||
1. An array of values from the provided array of promises.
|
||||
2. The value from the provided promise.
|
||||
3. The provided non-promise object.
|
||||
|
||||
@see PMKJoin
|
||||
|
||||
*/
|
||||
extern AnyPromise * __nonnull PMKWhen(id __nonnull input) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Creates a new promise that resolves only when all provided promises have resolved.
|
||||
|
||||
Typically, you should use `PMKWhen`.
|
||||
|
||||
For example:
|
||||
|
||||
PMKJoin(@[promise1, promise2]).then(^(NSArray *resultingValues){
|
||||
//…
|
||||
}).catch(^(NSError *error){
|
||||
assert(error.domain == PMKErrorDomain);
|
||||
assert(error.code == PMKJoinError);
|
||||
|
||||
NSArray *promises = error.userInfo[PMKJoinPromisesKey];
|
||||
for (AnyPromise *promise in promises) {
|
||||
if (promise.rejected) {
|
||||
//…
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@param promises An array of promises.
|
||||
|
||||
@return A promise that thens three parameters:
|
||||
|
||||
1) An array of mixed values and errors from the resolved input.
|
||||
2) An array of values from the promises that fulfilled.
|
||||
3) An array of errors from the promises that rejected or nil if all promises fulfilled.
|
||||
|
||||
@see when
|
||||
*/
|
||||
AnyPromise *__nonnull PMKJoin(NSArray * __nonnull promises) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Literally hangs this thread until the promise has resolved.
|
||||
|
||||
Do not use hang… unless you are testing, playing or debugging.
|
||||
|
||||
If you use it in production code I will literally and honestly cry like a child.
|
||||
|
||||
@return The resolved value of the promise.
|
||||
|
||||
@warning T SAFE. IT IS NOT SAFE. IT IS NOT SAFE. IT IS NOT SAFE. IT IS NO
|
||||
*/
|
||||
extern id __nullable PMKHang(AnyPromise * __nonnull promise);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Executes the provided block on a background queue.
|
||||
|
||||
dispatch_promise is a convenient way to start a promise chain where the
|
||||
first step needs to run synchronously on a background queue.
|
||||
|
||||
dispatch_promise(^{
|
||||
return md5(input);
|
||||
}).then(^(NSString *md5){
|
||||
NSLog(@"md5: %@", md5);
|
||||
});
|
||||
|
||||
@param block The block to be executed in the background. Returning an `NSError` will reject the promise, everything else (including void) fulfills the promise.
|
||||
|
||||
@return A promise resolved with the return value of the provided block.
|
||||
|
||||
@see dispatch_async
|
||||
*/
|
||||
extern AnyPromise * __nonnull dispatch_promise(id __nonnull block) NS_SWIFT_UNAVAILABLE("Use our `DispatchQueue.async` override instead");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Executes the provided block on the specified background queue.
|
||||
|
||||
dispatch_promise_on(myDispatchQueue, ^{
|
||||
return md5(input);
|
||||
}).then(^(NSString *md5){
|
||||
NSLog(@"md5: %@", md5);
|
||||
});
|
||||
|
||||
@param block The block to be executed in the background. Returning an `NSError` will reject the promise, everything else (including void) fulfills the promise.
|
||||
|
||||
@return A promise resolved with the return value of the provided block.
|
||||
|
||||
@see dispatch_promise
|
||||
*/
|
||||
extern AnyPromise * __nonnull dispatch_promise_on(dispatch_queue_t __nonnull queue, id __nonnull block) NS_SWIFT_UNAVAILABLE("Use our `DispatchQueue.async` override instead");
|
||||
|
||||
/**
|
||||
Returns a new promise that resolves when the value of the first resolved promise in the provided array of promises.
|
||||
*/
|
||||
extern AnyPromise * __nonnull PMKRace(NSArray * __nonnull promises) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // Extern C
|
||||
#endif
|
||||
29
Carthage/Checkouts/PromiseKit/Sources/hang.m
vendored
Normal file
29
Carthage/Checkouts/PromiseKit/Sources/hang.m
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#import "AnyPromise.h"
|
||||
#import "AnyPromise+Private.h"
|
||||
@import CoreFoundation.CFRunLoop;
|
||||
|
||||
/**
|
||||
Suspends the active thread waiting on the provided promise.
|
||||
|
||||
@return The value of the provided promise once resolved.
|
||||
*/
|
||||
id PMKHang(AnyPromise *promise) {
|
||||
if (promise.pending) {
|
||||
static CFRunLoopSourceContext context;
|
||||
|
||||
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
|
||||
CFRunLoopSourceRef runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context);
|
||||
CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
|
||||
|
||||
promise.ensure(^{
|
||||
CFRunLoopStop(runLoop);
|
||||
});
|
||||
while (promise.pending) {
|
||||
CFRunLoopRun();
|
||||
}
|
||||
CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
|
||||
CFRelease(runLoopSource);
|
||||
}
|
||||
|
||||
return promise.value;
|
||||
}
|
||||
51
Carthage/Checkouts/PromiseKit/Sources/hang.swift
vendored
Normal file
51
Carthage/Checkouts/PromiseKit/Sources/hang.swift
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import Foundation
|
||||
import CoreFoundation
|
||||
|
||||
/**
|
||||
Runs the active run-loop until the provided promise resolves.
|
||||
|
||||
This is for debug and is not a generally safe function to use in your applications. We mostly provide it for use in testing environments.
|
||||
|
||||
Still if you like, study how it works (by reading the sources!) and use at your own risk.
|
||||
|
||||
- Returns: The value of the resolved promise
|
||||
- Throws: An error, should the promise be rejected
|
||||
- See: `wait()`
|
||||
*/
|
||||
public func hang<T>(_ promise: Promise<T>) throws -> T {
|
||||
#if os(Linux) || os(Android)
|
||||
// isMainThread is not yet implemented on Linux.
|
||||
let runLoopModeRaw = RunLoopMode.defaultRunLoopMode.rawValue._bridgeToObjectiveC()
|
||||
let runLoopMode: CFString = unsafeBitCast(runLoopModeRaw, to: CFString.self)
|
||||
#else
|
||||
guard Thread.isMainThread else {
|
||||
// hang doesn't make sense on threads that aren't the main thread.
|
||||
// use `.wait()` on those threads.
|
||||
fatalError("Only call hang() on the main thread.")
|
||||
}
|
||||
let runLoopMode: CFRunLoopMode = CFRunLoopMode.defaultMode
|
||||
#endif
|
||||
|
||||
if promise.isPending {
|
||||
var context = CFRunLoopSourceContext()
|
||||
let runLoop = CFRunLoopGetCurrent()
|
||||
let runLoopSource = CFRunLoopSourceCreate(nil, 0, &context)
|
||||
CFRunLoopAddSource(runLoop, runLoopSource, runLoopMode)
|
||||
|
||||
_ = promise.ensure {
|
||||
CFRunLoopStop(runLoop)
|
||||
}
|
||||
|
||||
while promise.isPending {
|
||||
CFRunLoopRun()
|
||||
}
|
||||
CFRunLoopRemoveSource(runLoop, runLoopSource, runLoopMode)
|
||||
}
|
||||
|
||||
switch promise.result! {
|
||||
case .rejected(let error):
|
||||
throw error
|
||||
case .fulfilled(let value):
|
||||
return value
|
||||
}
|
||||
}
|
||||
54
Carthage/Checkouts/PromiseKit/Sources/join.m
vendored
Normal file
54
Carthage/Checkouts/PromiseKit/Sources/join.m
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
@import Foundation.NSDictionary;
|
||||
#import "AnyPromise+Private.h"
|
||||
#import <libkern/OSAtomic.h>
|
||||
@import Foundation.NSError;
|
||||
@import Foundation.NSNull;
|
||||
#import "PromiseKit.h"
|
||||
#import <stdatomic.h>
|
||||
|
||||
/**
|
||||
Waits on all provided promises.
|
||||
|
||||
`PMKWhen` rejects as soon as one of the provided promises rejects. `PMKJoin` waits on all provided promises, then rejects if any of those promises rejects, otherwise it fulfills with values from the provided promises.
|
||||
|
||||
- Returns: A new promise that resolves once all the provided promises resolve.
|
||||
*/
|
||||
AnyPromise *PMKJoin(NSArray *promises) {
|
||||
if (promises == nil)
|
||||
return [AnyPromise promiseWithValue:[NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"PMKJoin(nil)"}]];
|
||||
|
||||
if (promises.count == 0)
|
||||
return [AnyPromise promiseWithValue:promises];
|
||||
|
||||
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
NSPointerArray *results = NSPointerArrayMake(promises.count);
|
||||
__block atomic_int countdown = promises.count;
|
||||
__block BOOL rejected = NO;
|
||||
|
||||
[promises enumerateObjectsUsingBlock:^(AnyPromise *promise, NSUInteger ii, BOOL *stop) {
|
||||
[promise __pipe:^(id value) {
|
||||
|
||||
if (IsError(value)) {
|
||||
rejected = YES;
|
||||
}
|
||||
|
||||
//FIXME surely this isn't thread safe on multiple cores?
|
||||
[results replacePointerAtIndex:ii withPointer:(__bridge void *)(value ?: [NSNull null])];
|
||||
|
||||
atomic_fetch_sub_explicit(&countdown, 1, memory_order_relaxed);
|
||||
|
||||
if (countdown == 0) {
|
||||
if (!rejected) {
|
||||
resolve(results.allObjects);
|
||||
} else {
|
||||
id userInfo = @{PMKJoinPromisesKey: promises};
|
||||
id err = [NSError errorWithDomain:PMKErrorDomain code:PMKJoinError userInfo:userInfo];
|
||||
resolve(err);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
(void) stop;
|
||||
}];
|
||||
}];
|
||||
}
|
||||
9
Carthage/Checkouts/PromiseKit/Sources/race.m
vendored
Normal file
9
Carthage/Checkouts/PromiseKit/Sources/race.m
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
#import "AnyPromise+Private.h"
|
||||
|
||||
AnyPromise *PMKRace(NSArray *promises) {
|
||||
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
for (AnyPromise *promise in promises) {
|
||||
[promise __pipe:resolve];
|
||||
}
|
||||
}];
|
||||
}
|
||||
57
Carthage/Checkouts/PromiseKit/Sources/race.swift
vendored
Normal file
57
Carthage/Checkouts/PromiseKit/Sources/race.swift
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
@inline(__always)
|
||||
private func _race<U: Thenable>(_ thenables: [U]) -> Promise<U.T> {
|
||||
let rp = Promise<U.T>(.pending)
|
||||
for thenable in thenables {
|
||||
thenable.pipe(to: rp.box.seal)
|
||||
}
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
Waits for one promise to resolve
|
||||
|
||||
race(promise1, promise2, promise3).then { winner in
|
||||
//…
|
||||
}
|
||||
|
||||
- Returns: The promise that resolves first
|
||||
- Warning: If the first resolution is a rejection, the returned promise is rejected
|
||||
*/
|
||||
public func race<U: Thenable>(_ thenables: U...) -> Promise<U.T> {
|
||||
return _race(thenables)
|
||||
}
|
||||
|
||||
/**
|
||||
Waits for one promise to resolve
|
||||
|
||||
race(promise1, promise2, promise3).then { winner in
|
||||
//…
|
||||
}
|
||||
|
||||
- Returns: The promise that resolves first
|
||||
- Warning: If the first resolution is a rejection, the returned promise is rejected
|
||||
- Remark: If the provided array is empty the returned promise is rejected with PMKError.badInput
|
||||
*/
|
||||
public func race<U: Thenable>(_ thenables: [U]) -> Promise<U.T> {
|
||||
guard !thenables.isEmpty else {
|
||||
return Promise(error: PMKError.badInput)
|
||||
}
|
||||
return _race(thenables)
|
||||
}
|
||||
|
||||
/**
|
||||
Waits for one guarantee to resolve
|
||||
|
||||
race(promise1, promise2, promise3).then { winner in
|
||||
//…
|
||||
}
|
||||
|
||||
- Returns: The guarantee that resolves first
|
||||
*/
|
||||
public func race<T>(_ guarantees: Guarantee<T>...) -> Guarantee<T> {
|
||||
let rg = Guarantee<T>(.pending)
|
||||
for guarantee in guarantees {
|
||||
guarantee.pipe(to: rg.box.seal)
|
||||
}
|
||||
return rg
|
||||
}
|
||||
107
Carthage/Checkouts/PromiseKit/Sources/when.m
vendored
Normal file
107
Carthage/Checkouts/PromiseKit/Sources/when.m
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
@import Foundation.NSDictionary;
|
||||
#import "AnyPromise+Private.h"
|
||||
@import Foundation.NSProgress;
|
||||
#import <libkern/OSAtomic.h>
|
||||
@import Foundation.NSError;
|
||||
@import Foundation.NSNull;
|
||||
#import "PromiseKit.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
// ^^ OSAtomicDecrement32 is deprecated on watchOS
|
||||
|
||||
|
||||
// NSProgress resources:
|
||||
// * https://robots.thoughtbot.com/asynchronous-nsprogress
|
||||
// * http://oleb.net/blog/2014/03/nsprogress/
|
||||
// NSProgress! Beware!
|
||||
// * https://github.com/AFNetworking/AFNetworking/issues/2261
|
||||
|
||||
/**
|
||||
Wait for all promises in a set to resolve.
|
||||
|
||||
@note If *any* of the provided promises reject, the returned promise is immediately rejected with that error.
|
||||
@warning In the event of rejection the other promises will continue to resolve and, as per any other promise, will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed, in such situations use `when(resolved:)`.
|
||||
@param promises The promises upon which to wait before the returned promise resolves.
|
||||
@note PMKWhen provides NSProgress.
|
||||
@return A new promise that resolves when all the provided promises fulfill or one of the provided promises rejects.
|
||||
*/
|
||||
AnyPromise *PMKWhen(id promises) {
|
||||
if (promises == nil)
|
||||
return [AnyPromise promiseWithValue:[NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"PMKWhen(nil)"}]];
|
||||
|
||||
if ([promises isKindOfClass:[NSArray class]] || [promises isKindOfClass:[NSDictionary class]]) {
|
||||
if ([promises count] == 0)
|
||||
return [AnyPromise promiseWithValue:promises];
|
||||
} else if ([promises isKindOfClass:[AnyPromise class]]) {
|
||||
promises = @[promises];
|
||||
} else {
|
||||
return [AnyPromise promiseWithValue:promises];
|
||||
}
|
||||
|
||||
#ifndef PMKDisableProgress
|
||||
NSProgress *progress = [NSProgress progressWithTotalUnitCount:(int64_t)[promises count]];
|
||||
progress.pausable = NO;
|
||||
progress.cancellable = NO;
|
||||
#else
|
||||
struct PMKProgress {
|
||||
int completedUnitCount;
|
||||
int totalUnitCount;
|
||||
double fractionCompleted;
|
||||
};
|
||||
__block struct PMKProgress progress;
|
||||
#endif
|
||||
|
||||
__block int32_t countdown = (int32_t)[promises count];
|
||||
BOOL const isdict = [promises isKindOfClass:[NSDictionary class]];
|
||||
|
||||
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
NSInteger index = 0;
|
||||
|
||||
for (__strong id key in promises) {
|
||||
AnyPromise *promise = isdict ? promises[key] : key;
|
||||
if (!isdict) key = @(index);
|
||||
|
||||
if (![promise isKindOfClass:[AnyPromise class]])
|
||||
promise = [AnyPromise promiseWithValue:promise];
|
||||
|
||||
[promise __pipe:^(id value){
|
||||
if (progress.fractionCompleted >= 1)
|
||||
return;
|
||||
|
||||
if (IsError(value)) {
|
||||
progress.completedUnitCount = progress.totalUnitCount;
|
||||
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[(NSError *)value userInfo] ?: @{}];
|
||||
userInfo[PMKFailingPromiseIndexKey] = key;
|
||||
[userInfo setObject:value forKey:NSUnderlyingErrorKey];
|
||||
id err = [[NSError alloc] initWithDomain:[value domain] code:[value code] userInfo:userInfo];
|
||||
resolve(err);
|
||||
}
|
||||
else if (OSAtomicDecrement32(&countdown) == 0) {
|
||||
progress.completedUnitCount = progress.totalUnitCount;
|
||||
|
||||
id results;
|
||||
if (isdict) {
|
||||
results = [NSMutableDictionary new];
|
||||
for (id key in promises) {
|
||||
id promise = promises[key];
|
||||
results[key] = IsPromise(promise) ? ((AnyPromise *)promise).value : promise;
|
||||
}
|
||||
} else {
|
||||
results = [NSMutableArray new];
|
||||
for (AnyPromise *promise in promises) {
|
||||
id value = IsPromise(promise) ? (promise.value ?: [NSNull null]) : promise;
|
||||
[results addObject:value];
|
||||
}
|
||||
}
|
||||
resolve(results);
|
||||
} else {
|
||||
progress.completedUnitCount++;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
262
Carthage/Checkouts/PromiseKit/Sources/when.swift
vendored
Normal file
262
Carthage/Checkouts/PromiseKit/Sources/when.swift
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
import Foundation
|
||||
import Dispatch
|
||||
|
||||
private func _when<U: Thenable>(_ thenables: [U]) -> Promise<Void> {
|
||||
var countdown = thenables.count
|
||||
guard countdown > 0 else {
|
||||
return .value(Void())
|
||||
}
|
||||
|
||||
let rp = Promise<Void>(.pending)
|
||||
|
||||
#if PMKDisableProgress || os(Linux)
|
||||
var progress: (completedUnitCount: Int, totalUnitCount: Int) = (0, 0)
|
||||
#else
|
||||
let progress = Progress(totalUnitCount: Int64(thenables.count))
|
||||
progress.isCancellable = false
|
||||
progress.isPausable = false
|
||||
#endif
|
||||
|
||||
let barrier = DispatchQueue(label: "org.promisekit.barrier.when", attributes: .concurrent)
|
||||
|
||||
for promise in thenables {
|
||||
promise.pipe { result in
|
||||
barrier.sync(flags: .barrier) {
|
||||
switch result {
|
||||
case .rejected(let error):
|
||||
if rp.isPending {
|
||||
progress.completedUnitCount = progress.totalUnitCount
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
case .fulfilled:
|
||||
guard rp.isPending else { return }
|
||||
progress.completedUnitCount += 1
|
||||
countdown -= 1
|
||||
if countdown == 0 {
|
||||
rp.box.seal(.fulfilled(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rp
|
||||
}
|
||||
|
||||
/**
|
||||
Wait for all promises in a set to fulfill.
|
||||
|
||||
For example:
|
||||
|
||||
when(fulfilled: promise1, promise2).then { results in
|
||||
//…
|
||||
}.catch { error in
|
||||
switch error {
|
||||
case URLError.notConnectedToInternet:
|
||||
//…
|
||||
case CLError.denied:
|
||||
//…
|
||||
}
|
||||
}
|
||||
|
||||
- Note: If *any* of the provided promises reject, the returned promise is immediately rejected with that error.
|
||||
- Warning: In the event of rejection the other promises will continue to resolve and, as per any other promise, will either fulfill or reject. This is the right pattern for `getter` style asynchronous tasks, but often for `setter` tasks (eg. storing data on a server), you most likely will need to wait on all tasks and then act based on which have succeeded and which have failed, in such situations use `when(resolved:)`.
|
||||
- Parameter promises: The promises upon which to wait before the returned promise resolves.
|
||||
- Returns: A new promise that resolves when all the provided promises fulfill or one of the provided promises rejects.
|
||||
- Note: `when` provides `NSProgress`.
|
||||
- SeeAlso: `when(resolved:)`
|
||||
*/
|
||||
public func when<U: Thenable>(fulfilled thenables: [U]) -> Promise<[U.T]> {
|
||||
return _when(thenables).map(on: nil) { thenables.map{ $0.value! } }
|
||||
}
|
||||
|
||||
/// Wait for all promises in a set to fulfill.
|
||||
public func when<U: Thenable>(fulfilled promises: U...) -> Promise<Void> where U.T == Void {
|
||||
return _when(promises)
|
||||
}
|
||||
|
||||
/// Wait for all promises in a set to fulfill.
|
||||
public func when<U: Thenable>(fulfilled promises: [U]) -> Promise<Void> where U.T == Void {
|
||||
return _when(promises)
|
||||
}
|
||||
|
||||
/// Wait for all promises in a set to fulfill.
|
||||
public func when<U: Thenable, V: Thenable>(fulfilled pu: U, _ pv: V) -> Promise<(U.T, V.T)> {
|
||||
return _when([pu.asVoid(), pv.asVoid()]).map(on: nil) { (pu.value!, pv.value!) }
|
||||
}
|
||||
|
||||
/// Wait for all promises in a set to fulfill.
|
||||
public func when<U: Thenable, V: Thenable, W: Thenable>(fulfilled pu: U, _ pv: V, _ pw: W) -> Promise<(U.T, V.T, W.T)> {
|
||||
return _when([pu.asVoid(), pv.asVoid(), pw.asVoid()]).map(on: nil) { (pu.value!, pv.value!, pw.value!) }
|
||||
}
|
||||
|
||||
/// Wait for all promises in a set to fulfill.
|
||||
public func when<U: Thenable, V: Thenable, W: Thenable, X: Thenable>(fulfilled pu: U, _ pv: V, _ pw: W, _ px: X) -> Promise<(U.T, V.T, W.T, X.T)> {
|
||||
return _when([pu.asVoid(), pv.asVoid(), pw.asVoid(), px.asVoid()]).map(on: nil) { (pu.value!, pv.value!, pw.value!, px.value!) }
|
||||
}
|
||||
|
||||
/// Wait for all promises in a set to fulfill.
|
||||
public func when<U: Thenable, V: Thenable, W: Thenable, X: Thenable, Y: Thenable>(fulfilled pu: U, _ pv: V, _ pw: W, _ px: X, _ py: Y) -> Promise<(U.T, V.T, W.T, X.T, Y.T)> {
|
||||
return _when([pu.asVoid(), pv.asVoid(), pw.asVoid(), px.asVoid(), py.asVoid()]).map(on: nil) { (pu.value!, pv.value!, pw.value!, px.value!, py.value!) }
|
||||
}
|
||||
|
||||
/**
|
||||
Generate promises at a limited rate and wait for all to fulfill.
|
||||
|
||||
For example:
|
||||
|
||||
func downloadFile(url: URL) -> Promise<Data> {
|
||||
// ...
|
||||
}
|
||||
|
||||
let urls: [URL] = /*…*/
|
||||
let urlGenerator = urls.makeIterator()
|
||||
|
||||
let generator = AnyIterator<Promise<Data>> {
|
||||
guard url = urlGenerator.next() else {
|
||||
return nil
|
||||
}
|
||||
return downloadFile(url)
|
||||
}
|
||||
|
||||
when(generator, concurrently: 3).done { datas in
|
||||
// ...
|
||||
}
|
||||
|
||||
No more than three downloads will occur simultaneously.
|
||||
|
||||
- Note: The generator is called *serially* on a *background* queue.
|
||||
- Warning: Refer to the warnings on `when(fulfilled:)`
|
||||
- Parameter promiseGenerator: Generator of promises.
|
||||
- Returns: A new promise that resolves when all the provided promises fulfill or one of the provided promises rejects.
|
||||
- SeeAlso: `when(resolved:)`
|
||||
*/
|
||||
|
||||
public func when<It: IteratorProtocol>(fulfilled promiseIterator: It, concurrently: Int) -> Promise<[It.Element.T]> where It.Element: Thenable {
|
||||
|
||||
guard concurrently > 0 else {
|
||||
return Promise(error: PMKError.badInput)
|
||||
}
|
||||
|
||||
var generator = promiseIterator
|
||||
var root = Promise<[It.Element.T]>.pending()
|
||||
var pendingPromises = 0
|
||||
var promises: [It.Element] = []
|
||||
|
||||
let barrier = DispatchQueue(label: "org.promisekit.barrier.when", attributes: [.concurrent])
|
||||
|
||||
func dequeue() {
|
||||
guard root.promise.isPending else { return } // don’t continue dequeueing if root has been rejected
|
||||
|
||||
var shouldDequeue = false
|
||||
barrier.sync {
|
||||
shouldDequeue = pendingPromises < concurrently
|
||||
}
|
||||
guard shouldDequeue else { return }
|
||||
|
||||
var index: Int!
|
||||
var promise: It.Element!
|
||||
|
||||
barrier.sync(flags: .barrier) {
|
||||
guard let next = generator.next() else { return }
|
||||
|
||||
promise = next
|
||||
index = promises.count
|
||||
|
||||
pendingPromises += 1
|
||||
promises.append(next)
|
||||
}
|
||||
|
||||
func testDone() {
|
||||
barrier.sync {
|
||||
if pendingPromises == 0 {
|
||||
#if !swift(>=3.3) || (swift(>=4) && !swift(>=4.1))
|
||||
root.resolver.fulfill(promises.flatMap{ $0.value })
|
||||
#else
|
||||
root.resolver.fulfill(promises.compactMap{ $0.value })
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard promise != nil else {
|
||||
return testDone()
|
||||
}
|
||||
|
||||
promise.pipe { resolution in
|
||||
barrier.sync(flags: .barrier) {
|
||||
pendingPromises -= 1
|
||||
}
|
||||
|
||||
switch resolution {
|
||||
case .fulfilled:
|
||||
dequeue()
|
||||
testDone()
|
||||
case .rejected(let error):
|
||||
root.resolver.reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
dequeue()
|
||||
}
|
||||
|
||||
dequeue()
|
||||
|
||||
return root.promise
|
||||
}
|
||||
|
||||
/**
|
||||
Waits on all provided promises.
|
||||
|
||||
`when(fulfilled:)` rejects as soon as one of the provided promises rejects. `when(resolved:)` waits on all provided promises whatever their result, and then provides an array of `Result<T>` so you can individually inspect the results. As a consequence this function returns a `Guarantee`, ie. errors are lifted from the individual promises into the results array of the returned `Guarantee`.
|
||||
|
||||
when(resolved: promise1, promise2, promise3).then { results in
|
||||
for result in results where case .fulfilled(let value) {
|
||||
//…
|
||||
}
|
||||
}.catch { error in
|
||||
// invalid! Never rejects
|
||||
}
|
||||
|
||||
- Returns: A new promise that resolves once all the provided promises resolve. The array is ordered the same as the input, ie. the result order is *not* resolution order.
|
||||
- Note: we do not provide tuple variants for `when(resolved:)` but will accept a pull-request
|
||||
- Remark: Doesn't take Thenable due to protocol `associatedtype` paradox
|
||||
*/
|
||||
public func when<T>(resolved promises: Promise<T>...) -> Guarantee<[Result<T>]> {
|
||||
return when(resolved: promises)
|
||||
}
|
||||
|
||||
/// - See: `when(resolved: Promise<T>...)`
|
||||
public func when<T>(resolved promises: [Promise<T>]) -> Guarantee<[Result<T>]> {
|
||||
guard !promises.isEmpty else {
|
||||
return .value([])
|
||||
}
|
||||
|
||||
var countdown = promises.count
|
||||
let barrier = DispatchQueue(label: "org.promisekit.barrier.join", attributes: .concurrent)
|
||||
|
||||
let rg = Guarantee<[Result<T>]>(.pending)
|
||||
for promise in promises {
|
||||
promise.pipe { result in
|
||||
barrier.sync(flags: .barrier) {
|
||||
countdown -= 1
|
||||
}
|
||||
barrier.sync {
|
||||
if countdown == 0 {
|
||||
rg.box.seal(promises.map{ $0.result! })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
|
||||
/// Waits on all provided Guarantees.
|
||||
public func when(_ guarantees: Guarantee<Void>...) -> Guarantee<Void> {
|
||||
return when(guarantees: guarantees)
|
||||
}
|
||||
|
||||
// Waits on all provided Guarantees.
|
||||
public func when(guarantees: [Guarantee<Void>]) -> Guarantee<Void> {
|
||||
return when(fulfilled: guarantees).recover{ _ in }.asVoid()
|
||||
}
|
||||
Reference in New Issue
Block a user