// // Future.swift // KCD // // Created by Hori,Masaki on 2018/01/13. // Copyright © 2018年 Hori,Masaki. All rights reserved. // import Cocoa enum Result { case value(T) case error(Error) init(_ value: T) { self = .value(value) } init(_ error: Error) { self = .error(error) } } extension Result { var value: T? { if case let .value(value) = self { return value } return nil } var error: Error? { if case let .error(error) = self { return error } return nil } } enum FutureError: Error { case unsolvedFuture case noSuchElement } final class Future { private let semaphore: DispatchSemaphore? private var callbacks: [(Result) -> Void] = [] fileprivate var result: Result? { willSet { if result != nil { fatalError("Result already seted.") } } didSet { guard let result = self.result else { fatalError("set nil to result.") } callbacks.forEach { f in f(result) } callbacks = [] semaphore?.signal() } } var isCompleted: Bool { return result != nil } var value: Result? { return result } /// Life cycle init() { // for await() semaphore = DispatchSemaphore(value: 1) semaphore?.wait() } init(in queue: DispatchQueue = .global(), _ block: @escaping () throws -> T) { semaphore = DispatchSemaphore(value: 1) semaphore?.wait() queue.async { defer { self.semaphore?.signal() } do { self.result = Result(try block()) } catch { self.result = Result(error) } } } init(_ result: Result) { semaphore = nil self.result = result } convenience init(_ value: T) { self.init(Result(value)) } convenience init(_ error: Error) { self.init(Result(error)) } deinit { semaphore?.signal() } } extension Future { /// @discardableResult func await() -> Self { if result == nil { semaphore?.wait() semaphore?.signal() } return self } @discardableResult func onComplete(_ callback: @escaping (Result) -> Void) -> Self { if let r = result { callback(r) } else { callbacks.append(callback) } return self } @discardableResult func onSuccess(_ callback: @escaping (T) -> Void) -> Self { onComplete { result in if case let .value(v) = result { callback(v) } } return self } @discardableResult func onFailure(_ callback: @escaping (Error) -> Void) -> Self { onComplete { result in if case let .error(e) = result { callback(e) } } return self } } extension Future { /// func transform(_ s: @escaping (T) -> U, _ f: @escaping (Error) -> Error) -> Future { return transform { result in switch result { case let .value(value): return Result(s(value)) case let .error(error): return Result(f(error)) } } } func transform(_ s: @escaping (Result) -> Result) ->Future { return Promise() .complete { self.await().value.map(s) ?? Result(FutureError.unsolvedFuture) } .future } func map(_ t: @escaping (T) -> U) -> Future { return transform(t, { $0 }) } func flatMap(_ t: @escaping (T) -> Future) -> Future { return Promise() .completeWith { switch self.await().value { case .value(let v)?: return t(v) case .error(let e)?: return Future(e) case .none: fatalError("Future not complete") } } .future } func filter(_ f: @escaping (T) -> Bool) -> Future { return Promise() .complete { if case let .value(v)? = self.await().value, f(v) { return Result(v) } return Result(FutureError.noSuchElement) } .future } func recover(_ s: @escaping (Error) throws -> T) -> Future { return transform { result in do { return try result.error.map { error in Result(try s(error)) } ?? Result(FutureError.unsolvedFuture) } catch { return Result(error) } } } @discardableResult func andThen(_ f: @escaping (Result) -> Void) -> Future { return Promise() .complete { guard let result = self.await().result else { fatalError("Future not complete") } f(result) return result } .future } } private extension Future { func complete(_ result: Result) { self.result = result } } private let promiseQueue = DispatchQueue(label: "Promise", attributes: .concurrent) final class Promise { let future: Future = Future() /// func complete(_ result: Result) { future.complete(result) } func success(_ value: T) { complete(Result(value)) } func failure(_ error: Error) { complete(Result(error)) } func complete(_ completor: @escaping () -> Result) -> Self { promiseQueue.async { self.complete(completor()) } return self } func completeWith(_ completor: @escaping () -> Future) -> Self { promiseQueue.async { completor() .onSuccess { self.success($0) } .onFailure { self.failure($0) } } return self } }