Skip to content

Commit

Permalink
Adjusted some calls signatures and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
malcommac committed Jan 7, 2017
1 parent 032ebde commit d16932e
Show file tree
Hide file tree
Showing 17 changed files with 139 additions and 138 deletions.
8 changes: 0 additions & 8 deletions Hydra/DemoApp/ViewController.swift
Expand Up @@ -13,14 +13,6 @@ class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

do {
let x = try await(self.asyncFunc1())
let y = try ..self.asyncFunc1()

} catch {

}
}

func asyncFunc1() -> Promise<Int> {
Expand Down
6 changes: 3 additions & 3 deletions Hydra/Hydra.xcodeproj/project.pbxproj
Expand Up @@ -168,13 +168,13 @@
08295CEB1E1E545B009D32C3 /* Promise+Always.swift */,
08295CED1E1E5485009D32C3 /* Promise+Ensure.swift */,
08295CEF1E1E54A0009D32C3 /* Promise+Timeout.swift */,
08295CF11E1E54FF009D32C3 /* Promise+All.swift */,
08295CF31E1E5518009D32C3 /* Promise+Any.swift */,
08295CF51E1E56F1009D32C3 /* Promise+Delay.swift */,
08C7029B1E1EB7080062706A /* Promise+Zip.swift */,
08295CF31E1E5518009D32C3 /* Promise+Any.swift */,
08295D121E1E7123009D32C3 /* Promise+Forward.swift */,
08C702991E1EB54F0062706A /* Promise+Recover.swift */,
08C7029B1E1EB7080062706A /* Promise+Zip.swift */,
08C7029D1E21477E0062706A /* Promise+Map.swift */,
08295CF11E1E54FF009D32C3 /* Promise+All.swift */,
);
name = Operations;
sourceTree = "<group>";
Expand Down
Binary file not shown.
20 changes: 12 additions & 8 deletions Sources/Await.swift
Expand Up @@ -15,7 +15,6 @@ import Foundation
/// The exact number of tasks executing at any given point is variable and depends on system conditions.
let awaitContext = Context.custom(queue: DispatchQueue(label: "com.hydra.awaitcontext", attributes: .concurrent))


/// This define a `..` operator you can use instead of calling `await` func.
/// If you use this operator you need to also use `do/catch` in order to catch exception for rejected promises.
prefix operator ..
Expand All @@ -36,12 +35,14 @@ public prefix func ..!<T> (_ promise: Promise<T>) -> T? {

/// Awaits that the given promise fulfilled with its value or throws an error if the promise fails
///
/// - Parameter promise: target promise
/// - Parameters:
/// - context: context in which you want to execute the operation. If not specified default concurrent `awaitContext` is used instead.
/// - promise: target promise
/// - Returns: fufilled value of the promise
/// - Throws: exception if promise fails due to an error
/// - Throws: throws an exception if promise fails due to an error
@discardableResult
public func await<T>(_ promise: Promise<T>) throws -> T {
return try awaitContext.await(promise)
public func await<T>(_ context: Context? = nil, _ promise: Promise<T>) throws -> T {
return try (context ?? awaitContext).await(promise)
}

/// Awaits that the given body is resolved. This is a shortcut which simply create a Promise; as for a Promise you need to
Expand All @@ -55,9 +56,12 @@ public func await<T>(_ promise: Promise<T>) throws -> T {
@discardableResult
public func await<T>(_ context: Context = .background, _ body: @escaping ((_ fulfill: @escaping (T) -> (), _ reject: @escaping (Error) -> () ) throws -> ())) throws -> T {
let promise = Promise<T>(context,body)
return try await(promise)
return try await(context, promise)
}


// MARK: - Extension of Context

public extension Context {

/// Awaits that the given promise fulfilled with its value or throws an error if the promise fails.
Expand All @@ -79,11 +83,11 @@ public extension Context {
// the promise is fulfilled or rejected
let semaphore = DispatchSemaphore(value: 0)

promise.then(in: self) { value -> Void in
promise.then(self) { value -> Void in
// promise is fulfilled, fillup error and resume code execution
result = value
semaphore.signal()
}.catch(context: self) { err in
}.catch(self) { err in
// promise is rejected, fillup error and resume code execution
error = err
semaphore.signal()
Expand Down
18 changes: 8 additions & 10 deletions Sources/Promise+All.swift
Expand Up @@ -10,21 +10,21 @@ import Foundation


/// Return a Promises that resolved when all input Promises resolves.
/// Promises are resolved in parallel.
/// Promises are resolved in parallel in background QoS queue.
/// It rejects as soon as a promises reject for any reason; result reject with returned error.
///
/// - Parameters:
/// - context: handler queue to run the handler on
/// - promises: list of promises to resolve in parallel
/// - Returns: resolved promise which contains all resolved values from input promises (value are reported in the same order of input promises)
public func all<L>(_ context: Context = .main, _ promises: Promise<L>...) -> Promise<[L]> {
return all(in: context, promises)
public func all<L>(_ promises: Promise<L>...) -> Promise<[L]> {
return all(promises)
}

public func all<L, S: Sequence>(in context: Context = .main, _ promises: S) -> Promise<[L]> where S.Iterator.Element == Promise<L> {
public func all<L, S: Sequence>(_ promises: S) -> Promise<[L]> where S.Iterator.Element == Promise<L> {
guard Array(promises).count > 0 else {
// If number of passed promises is zero we want to return a resolved promises with an empty array as result
return Promise<[L]>(fulfilled: []);
return Promise<[L]>(asFulfilled: []);
}

// We want to create a Promise which groups all input Promises and return only
Expand All @@ -37,17 +37,15 @@ public func all<L, S: Sequence>(in context: Context = .main, _ promises: S) -> P

for currentPromise in promises {
// Listen for each promise in list to fulfill or reject
currentPromise.registerObserver(in: allPromiseContext, fulfill: { value in
currentPromise.addObserver(in: allPromiseContext, fulfill: { value in
// if currentPromise fulfill
// decrement remaining promise to fulfill
countRemaining -= 1
if countRemaining == 0 {
// if all promises are fullfilled we can resolve our chain Promise
// with an array of all values results of our input promises (in the same order)
context.queue.async { // report result in given context queue
let allResults = promises.map({ return $0.state.value! })
resolve(allResults)
}
let allResults = promises.map({ return $0.state.value! })
resolve(allResults)
}
// if currentPromise reject the entire chain is broken and we reject the group Promise itself
}, reject: reject)
Expand Down
13 changes: 7 additions & 6 deletions Sources/Promise+Always.swift
Expand Up @@ -13,29 +13,30 @@ public extension Promise {
/// If added to the chain this function always run given handler regardless of the wether the chain resolves or rejects.
///
/// - Parameters:
/// - context: handler to run the handler on
/// - finallyHandler: handler to run at the end of the promise chain
/// - context: handler to run the handler on (if not specified `background` queue is used instead)
/// - body: handler to run at the end of the promise chain
/// - Returns: a Promise to chain
@discardableResult
public func always(_ context: Context = .main, _ finallyHandler: @escaping () throws -> Void) -> Promise<R> {
public func always(_ context: Context? = nil, _ body: @escaping () throws -> Void) -> Promise<R> {
let ctx = context ?? .background
return Promise<R> { resolve, reject in
let onResolve: (R) -> (Void) = { value in
do {
try finallyHandler()
try body()
resolve(value)
} catch {
reject(error)
}
}
let onReject: (Error) -> (Void) = { error in
do {
try finallyHandler()
try body()
reject(error)
} catch {
reject(error)
}
}
self.registerObserver(in: context, fulfill: onResolve, reject: onReject)
self.addObserver(in: ctx, fulfill: onResolve, reject: onReject)
}
}

Expand Down
9 changes: 5 additions & 4 deletions Sources/Promise+Any.swift
Expand Up @@ -13,19 +13,20 @@ public extension Promise {
/// Returns a Promise that resolves as soon as one passed in Promise resolves
///
/// - Parameters:
/// - context: dispatch queue to run the handler on
/// - context: dispatch queue to run the handler on (if not specified `background` context is used)
/// - promises: array of Promises to resolve
/// - Returns: Promise that resolves to first resolved Promise
public static func any<L>(context: Context = .main, _ promises: Promise<L>...) -> Promise<L> {
public static func any<L>(_ context: Context? = nil, _ promises: Promise<L>...) -> Promise<L> {
guard Array(promises).count > 0 else {
// if number of passed promises is zero a rejected promises is returned
return Promise<L>(rejected: PromiseError.invalidInput)
return Promise<L>(asRejected: PromiseError.invalidInput)
}

let ctx = context ?? .background
let anyPromise = Promise<L> { (resolve, reject) in
for currentPromise in promises {
// first promises which resolve is returned
currentPromise.registerObserver(in: context, fulfill: resolve, reject: reject)
currentPromise.addObserver(in: ctx, fulfill: resolve, reject: reject)
}
}
return anyPromise
Expand Down
7 changes: 4 additions & 3 deletions Sources/Promise+Catch.swift
Expand Up @@ -17,20 +17,21 @@ public extension Promise {
/// - handler: handler to run when Promise chain rejects
/// - Returns: a void Promise
@discardableResult
public func `catch`(context: Context = .main, _ handler: @escaping (Error) throws -> Void) -> Promise<Void> {
public func `catch`(_ context: Context? = nil, _ body: @escaping (Error) throws -> Void) -> Promise<Void> {
let ctx = context ?? .main
return Promise<Void> { (resolve, reject) in
let onResolve: (R) -> (Void) = { value in
resolve(())
}
let onReject: (Error) -> (Void) = { error in
do {
try handler(error)
try body(error)
} catch {
return reject(error)
}
resolve(())
}
self.registerObserver(in: context, fulfill: onResolve, reject: onReject)
self.addObserver(in: ctx, fulfill: onResolve, reject: onReject)
}
}

Expand Down
8 changes: 3 additions & 5 deletions Sources/Promise+Delay.swift
Expand Up @@ -10,19 +10,17 @@ import Foundation

public extension Promise {


/// Delay the executon of a Promise chain by some number of seconds from current time
///
/// - Parameters:
/// - context: dispatch queue to run the delay on
/// - seconds: delay time in seconds; execution time is `.now()+seconds`
/// - result: the Promise to resolve to after the delay
/// - Returns: Promise
public func delay(_ context: Context = .main, fromNow seconds: TimeInterval) -> Promise<R> {
return self.then(in: context, { value in
public func delay(_ seconds: TimeInterval) -> Promise<R> {
return self.then(context, { value in
return Promise<R> { resolve, _ in
let fireTime: DispatchTime = .now() + seconds
context.queue.asyncAfter(deadline: fireTime) {
Context.background.queue.asyncAfter(deadline: fireTime) {
resolve(value)
}
}
Expand Down
11 changes: 6 additions & 5 deletions Sources/Promise+Ensure.swift
Expand Up @@ -13,12 +13,13 @@ public extension Promise {
/// ensure is a method that takes a predicate, and rejects the promise chain if that predicate fails.
///
/// - Parameters:
/// - context: context queue
/// - predicate: predicate you should use to validation
/// - context: context queue (if not specified `background` context is used instead)
/// - condition: predicate you should use to validation. return `false` to reject promise, true to `fulfill` and pass the value forward.
/// - Returns: Promise
public func ensure(_ context: Context = .main, _ predicate: @escaping (R) -> Bool) -> Promise<R> {
return self.then(in: context, { (value: R) -> R in
guard predicate(value) else {
public func ensure(_ context: Context? = nil, _ condition: @escaping (R) -> Bool) -> Promise<R> {
let ctx = context ?? .background
return self.then(ctx, { (value: R) -> R in
guard condition(value) else {
throw PromiseError.rejected
}
return value
Expand Down
20 changes: 11 additions & 9 deletions Sources/Promise+Forward.swift
Expand Up @@ -14,13 +14,14 @@ public extension Promise {
/// However it may reject the chain.
///
/// - Parameters:
/// - context: dispatch queue to run the body on
/// - context: dispatch queue to run the body on (if not specified `background` is used instead)
/// - body: block to run in the middle of the promise chain. Chain waits for the returned Promise to resolve
/// - Returns: Promise that resolves to the result of the previous Promise
public func forward<N>(_ context: Context = .main, _ body: @escaping (R) throws -> Promise<N>) -> Promise<R> {
return self.then(in: context, { value in
try body(value).then(in: context, { _ in
Promise(fulfilled: value)
public func forward<N>(_ context: Context? = nil, _ body: @escaping (R) throws -> Promise<N>) -> Promise<R> {
let ctx = context ?? .background
return self.then(ctx, { value in
try body(value).then(ctx, { _ in
Promise(asFulfilled: value)
})
})
}
Expand All @@ -29,13 +30,14 @@ public extension Promise {
/// However it may reject the chain.
///
/// - Parameters:
/// - context: dispatch queue to run the body on
/// - context: dispatch queue to run the body on (if not specified `background` is used instead)
/// - body: block to run in the middle of the promise chain
/// - Returns: Promise that resolves to the result of the previous Promise
@discardableResult
public func forward(_ context: Context = .main, _ body: @escaping (R) throws -> Void) -> Promise<R> {
return self.forward(context, { value in
try Promise<Void>(fulfilled: body(value))
public func forward(_ context: Context? = nil, _ body: @escaping (R) throws -> Void) -> Promise<R> {
let ctx = context ?? .background
return self.forward(ctx, { value in
try Promise<Void>(asFulfilled: body(value))
})
}
}
35 changes: 20 additions & 15 deletions Sources/Promise+Map.swift
Expand Up @@ -8,51 +8,56 @@

import Foundation

public enum MapType {
/// Promise resolve tryp
///
/// - parallel: resolve all promises in parallel
/// - series: resolve all promises in series, in order
public enum PromiseResolveType {
case parallel
case series
}

/// Map an array of items and transform it to Promises.
/// Then promsies can be resolved in parallel or serially; rejects as soon as any Promise rejects.
/// Then promises can be resolved in parallel or serially; rejects as soon as any Promise rejects.
///
/// - Parameters:
/// - context: context to run the handler on
/// - context: context to run the handler on (if not specified `background` context is used)
/// - type: type of execution
/// - items: items to transform
/// - transform: transform callback which return the promise
/// - Returns: a Promise which resolve all created promises
public func map<A, B, S: Sequence>(in context: Context = .main, type: MapType, _ items: S, _ transform: @escaping (A) throws -> Promise<B>) -> Promise<[B]> where S.Iterator.Element == A {
public func map<A, B, S: Sequence>(_ context: Context? = nil, type: PromiseResolveType, _ items: S, _ transform: @escaping (A) throws -> Promise<B>) -> Promise<[B]> where S.Iterator.Element == A {

let ctx = context ?? .background
switch type {
case .parallel:
return map_parallel(in: context, items, transform)
return map_parallel(context: ctx, items: items, transform: transform)
default:
return map_series(in: context, items, transform)
return map_series(context: ctx, items: items, transform: transform)
}
}

public func map_series<A, B, S: Sequence>(in context: Context = .main, _ items: S, _ transform: @escaping (A) throws -> Promise<B>) -> Promise<[B]> where S.Iterator.Element == A {
let initial = Promise<[B]>(fulfilled: [])
public func map_series<A, B, S: Sequence>(context: Context, items: S, transform: @escaping (A) throws -> Promise<B>) -> Promise<[B]> where S.Iterator.Element == A {
let initial = Promise<[B]>(asFulfilled: [])

return items.reduce(initial) { chain, item in
return chain.then(in: context) { results in
try transform(item).then(in: context) { results + [$0] }
return chain.then(context) { results in
try transform(item).then(context) { results + [$0] }
}
}
}

internal func map_parallel<A, B, S: Sequence>(in context: Context = .main, _ items: S, _ transform: @escaping (A) throws -> Promise<B>) -> Promise<[B]> where S.Iterator.Element == A {
internal func map_parallel<A, B, S: Sequence>(context: Context, items: S, transform: @escaping (A) throws -> Promise<B>) -> Promise<[B]> where S.Iterator.Element == A {

let transformPromise = Promise<Void>(fulfilled: ())
return transformPromise.then(in: context) { (Void) -> Promise<[B]> in
let transformPromise = Promise<Void>(asFulfilled: ())
return transformPromise.then(context) { (Void) -> Promise<[B]> in
do {
let mappedPromises: [Promise<B>] = try items.map({ item in
return try transform(item)
})
return all(in: context, mappedPromises)
return all(mappedPromises)
} catch let error {
return Promise<[B]>(rejected: error)
return Promise<[B]>(asRejected: error)
}
}
}
Expand Down

0 comments on commit d16932e

Please sign in to comment.