import Cocoa
-
enum Result<T> {
case value(T)
- case none
+
case error(Error)
}
private let queue: DispatchQueue
private let semaphore = DispatchSemaphore(value: 1)
- private var result: Result<T> = .none
+ private var result: Result<T>?
init(queue: DispatchQueue = watingQueue) {
self.semaphore.wait()
}
+ convenience init(queue: DispatchQueue = watingQueue, _ block: @escaping () throws -> T) {
+
+ self.init(queue: queue)
+
+ queue.async {
+ do {
+ self.success(try block())
+ } catch {
+ self.failure(error)
+ }
+ }
+ }
deinit {
semaphore.signal()
}
@discardableResult
- func onSuccess(block: @escaping (T) -> Void) -> Future<T> {
+ func onSuccess(_ block: @escaping (T) -> Void) -> Self {
queue.async {
-
self.semaphore.wait()
- if case .value(let value) = self.result { block(value) }
+ if case let .value(value)? = self.result { block(value) }
self.semaphore.signal()
}
}
@discardableResult
- func onFailure(block: @escaping (Error) -> Void) -> Future<T> {
+ func onFailure(_ block: @escaping (Error) -> Void) -> Self {
queue.async {
-
self.semaphore.wait()
- if case .error(let error) = self.result { block(error) }
+ if case let .error(error)? = self.result { block(error) }
self.semaphore.signal()
}
return self
}
- func success(_ value: T) {
+ func success(_ newValue: T) {
switch result {
- case .value, .error:
- Logger.shared.log("multi call success(_:)")
- fatalError()
-
case .none:
- result = .value(value)
+ result = .value(newValue)
semaphore.signal()
+
+ default:
+ fatalError("multi call success(_:)")
}
}
- func failure(_ error: Error) {
+ func failure(_ newError: Error) {
switch result {
- case .value, .error:
- Logger.shared.log("multi call failure(_:)")
- fatalError()
-
case .none:
- result = .error(error)
+ result = .error(newError)
semaphore.signal()
+
+ default:
+ fatalError("multi call failure(_:)")
+ }
+ }
+
+ @discardableResult
+ func await() -> Self {
+
+ semaphore.wait()
+ semaphore.signal()
+
+ return self
+ }
+
+ func map<U>(_ transform: @escaping (T) throws -> U) -> Future<U> {
+
+ return Future<U> {
+
+ self.semaphore.wait()
+ defer { self.semaphore.signal() }
+
+ if case let .value(value)? = self.result {
+ return try transform(value)
+ }
+ if case let .error(error)? = self.result {
+ throw error
+ }
+
+ fatalError("Not reach")
}
}
+
+ func flatMap<U>(_ transform: @escaping (T) -> Future<U>) -> Future<U> {
+
+ let future = Future<U>()
+
+ onSuccess {
+ transform($0)
+ .onSuccess { val in future.success(val) }
+ .onFailure { error in future.failure(error) }
+ }
+ onFailure {
+ future.failure($0)
+ }
+
+ return future
+ }
}
/// - object: 監視対象
/// - block:
/// Parameters: Notification
- /// Returns: `Result<T>` : 成功時は `.value<T>`, エラー時は `.error<Error>`, 監視を継続するときは `.none`を返す
+ /// Returns: `Result<T>?` : 成功時は `.value<T>`, エラー時は `.error<Error>`, 監視を継続するときは `Optional.none`を返す
/// - Returns: Notificationによって値が設定される Future<T>
- func future<T>(name: Notification.Name, object: Any?, block: @escaping (Notification) -> Result<T>) -> Future<T> {
+ func future<T>(name: Notification.Name, object: Any?, block: @escaping (Notification) -> Result<T>?) -> Future<T> {
let future = Future<T>()
switch block(notification) {
- case .value(let val): future.success(val)
+ case .value(let val)?: future.success(val)
- case .none: return
+ case .error(let error)?: future.failure(error)
- case .error(let error): future.failure(error)
+ case .none: return
}
token.map(NotificationCenter.default.removeObserver)
/// - Parameters:
/// - block:
/// Parameters: Notification (NSManagedObjectContextObjectsDidChange)
- /// Returns: `Result<T>` : 成功時は `.value<T>`, エラー時は `.error<Error>`, 監視を継続するときは `.none`を返す
+ /// Returns: `Result<T>?` : 成功時は `.value<T>`, エラー時は `.error<Error>`, 監視を継続するときは `Optional.none`を返す
/// - Returns: CoreDataの更新で値が設定される Future<T>
- func future<T>(block: @escaping (Notification) -> Result<T>) -> Future<T> {
+ func future<T>(block: @escaping (Notification) -> Result<T>?) -> Future<T> {
return NotificationCenter.default
.future(name: .NSManagedObjectContextObjectsDidChange, object: self.context, block: block)