Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // Asynchronous computation control library
- //
- import class Dispatch.DispatchQueue
- import struct Dispatch.DispatchQoS
- // Outcome of a fallible process
- //
- public enum Result<R, T> {
- case success(T)
- case failure(R)
- }
- // Single unit of asynchronous computation
- //
- public class Promise<T> {
- internal var result: Result<Error, T>?
- private weak var queue: PromiseQueue?
- // Promises are created through a `PromiseQueue` instance
- //
- internal init(queue: PromiseQueue, result: Result<Error, T>? = nil) {
- self.queue = queue
- self.result = result
- }
- // Schedule a promise to execute after another one
- //
- // The body only gets executed if the preceding promise
- // was fulfilled. In the other case, a new promise is returned
- // with the same reason as the broken preceding one.
- //
- @discardableResult
- public func `then`<Y>(_ body: @escaping (T) throws -> Y) -> Promise<Y> {
- return queue!.promise({
- switch self.result! {
- case .success(let result):
- return try body(result)
- case .failure(let reason):
- throw reason
- }
- })
- }
- // Provide a fallback value by executing a promise
- //
- // Upon successful return, the new promise
- // becomes fulfilled with its value.
- // If the body throws, the new promise becomes broken
- // with the new reason.
- //
- @discardableResult
- public func `else`(_ body: @escaping (Error) throws -> T) -> Promise<T> {
- return queue!.promise({
- switch self.result! {
- case .success(let result):
- return result
- case .failure(let reason):
- return try body(reason)
- }
- })
- }
- // Chain an action regardless of the preceding promise state
- //
- @discardableResult
- public func anyway<Y>(_ body: @escaping (Result<Error, T>) throws -> Y) -> Promise<Y> {
- return queue!.promise({
- return try body(self.result!)
- })
- }
- // Wait until the promise finishes,
- // after that return the value or throw the reason
- //
- public func join() throws -> T {
- queue!.joinAll()
- switch self.result! {
- case .success(let result):
- return result
- case .failure(let reason):
- throw reason
- }
- }
- }
- // Factory of Promises
- //
- public class PromiseQueue {
- private let queue: DispatchQueue
- public init() {
- self.queue = DispatchQueue(label: "", qos: DispatchQoS.background)
- }
- // Make a promise from a throwing function
- //
- // The returned value of the supplied body
- // shall become the value of the fulfilled promise.
- // If the body throws, the promise becomes broken
- // with the reason of the error thrown.
- //
- @discardableResult
- public func promise<T>(_ body: @escaping () throws -> T) -> Promise<T> {
- let promise = Promise<T>(queue: self)
- queue.async(execute: {
- do {
- let result = try body()
- promise.result = .success(result)
- } catch (let error) {
- promise.result = .failure(error)
- }
- })
- return promise
- }
- // Wrap a pair of callbacks into a promise
- //
- // The first callback is used fulfill the promise with the given value;
- // the second one is used to break it with the given reason.
- //
- // After the promise has been either fulfilled or broken,
- // any subsequent calls to either of two callback have no effect.
- //
- // Note that other promises shall not start
- // until this promise has finished.
- //
- @discardableResult
- public func promise<T>(
- by body: @escaping (@escaping (T) -> Void, @escaping (Error) -> Void) -> ()
- ) -> Promise<T> {
- let promise = Promise<T>(queue: self)
- queue.async(execute: {
- self.queue.suspend()
- body({ x in
- guard promise.result == nil else { return }
- promise.result = .success(x)
- self.queue.resume()
- }, { x in
- guard promise.result == nil else { return }
- promise.result = .failure(x)
- self.queue.resume()
- })
- })
- return promise
- }
- // Wait until all previously submitted promises are finished
- //
- public func joinAll() {
- queue.sync(execute: {})
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement