OSDN Git Service

extensionをファイルに分離
[kcd/KCD.git] / KCD / Future.swift
1 //
2 //  Future.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2018/01/13.
6 //  Copyright © 2018年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 enum Result<T> {
12     
13     case value(T)
14     
15     case error(Error)
16     
17     init(_ value: T) {
18         self = .value(value)
19     }
20     init(_ error: Error) {
21         self = .error(error)
22     }
23 }
24
25 enum FutureError: Error {
26     
27     case unsolvedFuture
28     
29     case noSuchElement
30 }
31
32 private let defaultWaitingQueue = DispatchQueue(label: "Future", attributes: .concurrent)
33 private final class FutureSynchronous {
34     
35     private let queue: DispatchQueue
36     private let semaphore = DispatchSemaphore(value: 1)
37     
38     init(queue: DispatchQueue = defaultWaitingQueue) {
39         self.queue = queue
40     }
41     
42     func excuteAfterWaiting(_ block: @escaping () -> Void) {
43         
44         queue.async {
45             self.semaphore.wait()
46             block()
47             self.semaphore.signal()
48         }
49     }
50     
51     func startWaiting() {
52         self.semaphore.wait()
53     }
54     
55     func stopWaiting() {
56         self.semaphore.signal()
57     }
58 }
59
60 class Future<T> {
61     
62     private let synchronous: FutureSynchronous
63     
64     fileprivate var result: Result<T>? {
65         willSet {
66             if result != nil {
67                 fatalError("Result already seted")
68             }
69         }
70         didSet {
71             synchronous.stopWaiting()
72         }
73     }
74     
75     /// Life cycle
76     init(queue: DispatchQueue? = nil) {
77         
78         self.synchronous = queue.map { FutureSynchronous(queue: $0) } ?? FutureSynchronous()
79         
80         synchronous.startWaiting()
81     }
82     
83     init(queue: DispatchQueue? = nil, _ block: @escaping () throws -> T) {
84         
85         self.synchronous = queue.map { FutureSynchronous(queue: $0) } ?? FutureSynchronous()
86         
87         synchronous.excuteAfterWaiting {
88             do {
89                 self.result = Result(try block())
90             } catch {
91                 self.result = Result(error)
92             }
93         }
94     }
95     
96     init(queue: DispatchQueue? = nil, _ result: Result<T>) {
97         
98         self.synchronous = queue.map { FutureSynchronous(queue: $0) } ?? FutureSynchronous()
99         
100         self.result = result
101     }
102     convenience init(_ value: T) {
103         
104         self.init(Result(value))
105     }
106     convenience init(_ error: Error) {
107         
108         self.init(Result(error))
109     }
110     
111     deinit {
112         synchronous.stopWaiting()
113     }
114     
115 }
116
117 extension Future {
118     ///
119     @discardableResult
120     func await() -> Self {
121         
122         synchronous.excuteAfterWaiting {
123             // do nothing
124         }
125         
126         return self
127     }
128     
129     @discardableResult
130     func onComplete(_ block: @escaping (Result<T>) -> Void) -> Self {
131         
132         synchronous.excuteAfterWaiting {
133             block(self.result!)
134         }
135         
136         return self
137     }
138     
139     @discardableResult
140     func onSuccess(_ block: @escaping (T) -> Void) -> Self {
141         
142         synchronous.excuteAfterWaiting {
143             if case let .value(value)? = self.result { block(value) }
144         }
145         
146         return self
147     }
148     
149     @discardableResult
150     func onFailure(_ block: @escaping (Error) -> Void) -> Self {
151         
152         synchronous.excuteAfterWaiting {
153             if case let .error(error)? = self.result { block(error) }
154         }
155         
156         return self
157     }
158 }
159
160 extension Future {
161     
162     ///
163     func transform<U>(_ s: @escaping (T) -> U, _ f: @escaping (Error) -> (Error)) -> Future<U> {
164         
165         return transform {
166             switch $0 {
167                 
168             case let .value(value): return Result(s(value))
169                 
170             case let .error(error): return Result(f(error))
171             }
172         }
173     }
174     
175     func transform<U>(_ s: @escaping (Result<T>) -> Result<U>) ->Future<U> {
176         
177         return Promise()
178             .complete {
179                 guard let r = self.await().result.map({s($0)}) else {
180                     return Result(FutureError.unsolvedFuture)
181                 }
182                 return r
183             }
184             .future
185     }
186     
187     func map<U>(_ t: @escaping (T) -> U) -> Future<U> {
188         
189         return transform(t, { $0 })
190     }
191     
192     func flatMap<U>(_ t: @escaping (T) -> Future<U>) -> Future<U> {
193         
194         return Promise()
195             .completeWith {
196                 switch self.await().result {
197                 case let .value(v)?: return t(v)
198                 case let .error(e)?: return Future<U>(e)
199                 case .none: return Future<U>(FutureError.unsolvedFuture)
200                 }
201             }
202             .future
203     }
204     
205     func filter(_ f: @escaping (T) -> Bool) -> Future<T> {
206         
207         return Promise()
208             .complete {
209                 if case let .value(v)? = self.result, f(v) {
210                     return Result(v)
211                 }
212                 return Result(FutureError.noSuchElement)
213             }
214             .future
215     }
216     
217     func recover(_ s: @escaping (Error) throws -> T) -> Future<T> {
218         
219         return transform {
220             do {
221                 if case let .error(e) = $0 {
222                     return Result(try s(e))
223                 }
224             } catch {
225                 return Result(error)
226             }
227             return $0
228         }
229     }
230 }
231
232 fileprivate extension Future {
233     
234     func complete(_ result: Result<T>) {
235         
236         self.result = result
237     }
238 }
239
240 private let promiseQueue = DispatchQueue(label: "Promise", attributes: .concurrent)
241 final class Promise<T> {
242     
243     let future: Future<T> = Future<T>()
244     
245     ///
246     func complete(_ result: Result<T>) {
247         
248         future.complete(result)
249     }
250     func success(_ value: T) {
251         
252         complete(Result(value))
253     }
254     func failure(_ error: Error) {
255         
256         complete(Result(error))
257     }
258     
259     func complete(_ completor: @escaping () -> Result<T>) -> Self {
260         
261         promiseQueue.async {
262             self.complete(completor())
263         }
264         
265         return self
266     }
267     
268     func completeWith(_ completor: @escaping () -> Future<T>) -> Self {
269         
270         promiseQueue.async {
271             completor()
272                 .onSuccess {
273                     self.success($0)
274                 }
275                 .onFailure {
276                     self.failure($0)
277             }
278         }
279         
280         return self
281     }
282 }