@@ -0,0 +1,350 | |||
|
1 | using System; | |
|
2 | using Implab.Parallels; | |
|
3 | using System.Threading; | |
|
4 | using System.Reflection; | |
|
5 | ||
|
6 | namespace Implab { | |
|
7 | public abstract class AbstractEvent<THandler> : ICancelationToken, ICancellable { | |
|
8 | ||
|
9 | const int UNRESOLVED_SATE = 0; | |
|
10 | const int TRANSITIONAL_STATE = 1; | |
|
11 | const int SUCCEEDED_STATE = 2; | |
|
12 | const int REJECTED_STATE = 3; | |
|
13 | const int CANCELLED_STATE = 4; | |
|
14 | ||
|
15 | const int CANCEL_NOT_REQUESTED = 0; | |
|
16 | const int CANCEL_REQUESTING = 1; | |
|
17 | const int CANCEL_REQUESTED = 2; | |
|
18 | ||
|
19 | const int RESERVED_HANDLERS_COUNT = 4; | |
|
20 | ||
|
21 | int m_state; | |
|
22 | Exception m_error; | |
|
23 | int m_handlersCount; | |
|
24 | ||
|
25 | readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; | |
|
26 | MTQueue<THandler> m_extraHandlers; | |
|
27 | int m_handlerPointer = -1; | |
|
28 | int m_handlersCommited; | |
|
29 | ||
|
30 | int m_cancelRequest; | |
|
31 | Exception m_cancelationReason; | |
|
32 | MTQueue<Action<Exception>> m_cancelationHandlers; | |
|
33 | ||
|
34 | ||
|
35 | #region state managment | |
|
36 | bool BeginTransit() { | |
|
37 | return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); | |
|
38 | } | |
|
39 | ||
|
40 | void CompleteTransit(int state) { | |
|
41 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) | |
|
42 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |
|
43 | } | |
|
44 | ||
|
45 | void WaitTransition() { | |
|
46 | while (m_state == TRANSITIONAL_STATE) { | |
|
47 | Thread.MemoryBarrier(); | |
|
48 | } | |
|
49 | } | |
|
50 | ||
|
51 | protected bool BeginSetResult() { | |
|
52 | if (!BeginTransit()) { | |
|
53 | WaitTransition(); | |
|
54 | if (m_state != CANCELLED_STATE) | |
|
55 | throw new InvalidOperationException("The promise is already resolved"); | |
|
56 | return false; | |
|
57 | } | |
|
58 | return true; | |
|
59 | } | |
|
60 | ||
|
61 | protected void EndSetResult() { | |
|
62 | CompleteTransit(SUCCEEDED_STATE); | |
|
63 | OnSuccess(); | |
|
64 | } | |
|
65 | ||
|
66 | ||
|
67 | ||
|
68 | /// <summary> | |
|
69 | /// ΠΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅, ΡΠΎΠΎΠ±ΡΠ°Ρ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅ | |
|
70 | /// </summary> | |
|
71 | /// <remarks> | |
|
72 | /// ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡΠΎΡΠ½ΠΎΠΉ ΡΡΠ΅Π΄Π΅, ΠΏΡΠΈ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠΎΠΊΠΎΠ² | |
|
73 | /// ΠΌΠΎΠ³Ρ Π²Π΅ΡΠ½ΡΡΡ ΠΎΡΠΈΠ±ΠΊΡ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ²Π°Ρ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ | |
|
74 | /// Π±ΡΠ΄ΡΡ ΠΏΡΠΎΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Ρ. | |
|
75 | /// </remarks> | |
|
76 | /// <param name="error">ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ</param> | |
|
77 | /// <exception cref="InvalidOperationException">ΠΠ°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠΆΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception> | |
|
78 | protected void SetError(Exception error) { | |
|
79 | if (BeginTransit()) { | |
|
80 | if (error is OperationCanceledException) { | |
|
81 | CompleteTransit(CANCELLED_STATE); | |
|
82 | m_error = error.InnerException; | |
|
83 | OnCancelled(); | |
|
84 | } else { | |
|
85 | m_error = error is PromiseTransientException ? error.InnerException : error; | |
|
86 | CompleteTransit(REJECTED_STATE); | |
|
87 | OnError(); | |
|
88 | } | |
|
89 | } else { | |
|
90 | WaitTransition(); | |
|
91 | if (m_state == SUCCEEDED_STATE) | |
|
92 | throw new InvalidOperationException("The promise is already resolved"); | |
|
93 | } | |
|
94 | } | |
|
95 | ||
|
96 | /// <summary> | |
|
97 | /// ΠΡΠΌΠ΅Π½ΡΠ΅Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ, Π΅ΡΠ»ΠΈ ΡΡΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. | |
|
98 | /// </summary> | |
|
99 | /// <remarks>ΠΠ»Ρ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π±ΡΠ»Π° Π»ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ ΠΎΡΠΌΠ΅Π½Π΅Π½Π° ΡΠ»Π΅Π΄ΡΠ΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠ²ΠΎΠΉΡΡΠ²ΠΎ <see cref="IsCancelled"/>.</remarks> | |
|
100 | protected void SetCancelled(Exception reason) { | |
|
101 | if (BeginTransit()) { | |
|
102 | m_error = reason; | |
|
103 | CompleteTransit(CANCELLED_STATE); | |
|
104 | OnCancelled(); | |
|
105 | } | |
|
106 | } | |
|
107 | ||
|
108 | protected abstract void SignalSuccess(THandler handler); | |
|
109 | ||
|
110 | protected abstract void SignalError(THandler handler, Exception error); | |
|
111 | ||
|
112 | protected abstract void SignalCancelled(THandler handler, Exception reason); | |
|
113 | ||
|
114 | void OnSuccess() { | |
|
115 | var hp = m_handlerPointer; | |
|
116 | var slot = hp +1 ; | |
|
117 | while (slot < m_handlersCommited) { | |
|
118 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
119 | SignalSuccess(m_handlers[slot]); | |
|
120 | } | |
|
121 | hp = m_handlerPointer; | |
|
122 | slot = hp +1 ; | |
|
123 | } | |
|
124 | ||
|
125 | ||
|
126 | if (m_extraHandlers != null) { | |
|
127 | THandler handler; | |
|
128 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
129 | SignalSuccess(handler); | |
|
130 | } | |
|
131 | } | |
|
132 | ||
|
133 | void OnError() { | |
|
134 | var hp = m_handlerPointer; | |
|
135 | var slot = hp +1 ; | |
|
136 | while (slot < m_handlersCommited) { | |
|
137 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
138 | SignalError(m_handlers[slot],m_error); | |
|
139 | } | |
|
140 | hp = m_handlerPointer; | |
|
141 | slot = hp +1 ; | |
|
142 | } | |
|
143 | ||
|
144 | if (m_extraHandlers != null) { | |
|
145 | THandler handler; | |
|
146 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
147 | SignalError(handler, m_error); | |
|
148 | } | |
|
149 | } | |
|
150 | ||
|
151 | void OnCancelled() { | |
|
152 | var hp = m_handlerPointer; | |
|
153 | var slot = hp +1 ; | |
|
154 | while (slot < m_handlersCommited) { | |
|
155 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
156 | SignalCancelled(m_handlers[slot], m_error); | |
|
157 | } | |
|
158 | hp = m_handlerPointer; | |
|
159 | slot = hp +1 ; | |
|
160 | } | |
|
161 | ||
|
162 | if (m_extraHandlers != null) { | |
|
163 | THandler handler; | |
|
164 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
165 | SignalCancelled(handler, m_error); | |
|
166 | } | |
|
167 | } | |
|
168 | ||
|
169 | #endregion | |
|
170 | ||
|
171 | protected abstract Signal GetResolveSignal(); | |
|
172 | ||
|
173 | #region synchronization traits | |
|
174 | protected void WaitResult(int timeout) { | |
|
175 | if (!IsResolved) | |
|
176 | GetResolveSignal().Wait(timeout); | |
|
177 | ||
|
178 | switch (m_state) { | |
|
179 | case SUCCEEDED_STATE: | |
|
180 | return; | |
|
181 | case CANCELLED_STATE: | |
|
182 | throw new OperationCanceledException(); | |
|
183 | case REJECTED_STATE: | |
|
184 | throw new TargetInvocationException(m_error); | |
|
185 | default: | |
|
186 | throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); | |
|
187 | } | |
|
188 | } | |
|
189 | #endregion | |
|
190 | ||
|
191 | #region handlers managment | |
|
192 | ||
|
193 | protected void AddHandler(THandler handler) { | |
|
194 | ||
|
195 | if (m_state > 1) { | |
|
196 | // the promise is in the resolved state, just invoke the handler | |
|
197 | InvokeHandler(handler); | |
|
198 | } else { | |
|
199 | var slot = Interlocked.Increment(ref m_handlersCount) - 1; | |
|
200 | ||
|
201 | if (slot < RESERVED_HANDLERS_COUNT) { | |
|
202 | ||
|
203 | m_handlers[slot] = handler; | |
|
204 | ||
|
205 | while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) { | |
|
206 | } | |
|
207 | ||
|
208 | if (m_state > 1) { | |
|
209 | do { | |
|
210 | var hp = m_handlerPointer; | |
|
211 | slot = hp + 1; | |
|
212 | if (slot < m_handlersCommited) { | |
|
213 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp) | |
|
214 | continue; | |
|
215 | InvokeHandler(m_handlers[slot]); | |
|
216 | } | |
|
217 | break; | |
|
218 | } while(true); | |
|
219 | } | |
|
220 | } else { | |
|
221 | if (slot == RESERVED_HANDLERS_COUNT) { | |
|
222 | m_extraHandlers = new MTQueue<THandler>(); | |
|
223 | } else { | |
|
224 | while (m_extraHandlers == null) | |
|
225 | Thread.MemoryBarrier(); | |
|
226 | } | |
|
227 | ||
|
228 | m_extraHandlers.Enqueue(handler); | |
|
229 | ||
|
230 | if (m_state > 1 && m_extraHandlers.TryDequeue(out handler)) | |
|
231 | // if the promise have been resolved while we was adding the handler to the queue | |
|
232 | // we can't guarantee that someone is still processing it | |
|
233 | // therefore we need to fetch a handler from the queue and execute it | |
|
234 | // note that fetched handler may be not the one that we have added | |
|
235 | // even we can fetch no handlers at all :) | |
|
236 | InvokeHandler(handler); | |
|
237 | } | |
|
238 | } | |
|
239 | } | |
|
240 | ||
|
241 | protected void InvokeHandler(THandler handler) { | |
|
242 | switch (m_state) { | |
|
243 | case SUCCEEDED_STATE: | |
|
244 | SignalSuccess(handler); | |
|
245 | break; | |
|
246 | case CANCELLED_STATE: | |
|
247 | SignalCancelled(handler, m_error); | |
|
248 | break; | |
|
249 | case REJECTED_STATE: | |
|
250 | SignalError(handler, m_error); | |
|
251 | break; | |
|
252 | default: | |
|
253 | throw new Exception(String.Format("Invalid promise state {0}", m_state)); | |
|
254 | } | |
|
255 | } | |
|
256 | ||
|
257 | #endregion | |
|
258 | ||
|
259 | #region IPromise implementation | |
|
260 | ||
|
261 | public bool IsResolved { | |
|
262 | get { | |
|
263 | Thread.MemoryBarrier(); | |
|
264 | return m_state > 1; | |
|
265 | } | |
|
266 | } | |
|
267 | ||
|
268 | public bool IsCancelled { | |
|
269 | get { | |
|
270 | Thread.MemoryBarrier(); | |
|
271 | return m_state == CANCELLED_STATE; | |
|
272 | } | |
|
273 | } | |
|
274 | ||
|
275 | #endregion | |
|
276 | ||
|
277 | public Exception Error { | |
|
278 | get { | |
|
279 | return m_error; | |
|
280 | } | |
|
281 | } | |
|
282 | ||
|
283 | public bool AcceptIfRequested() { | |
|
284 | if (IsCancelRequested) | |
|
285 | CancelOperation(CancelReason); | |
|
286 | } | |
|
287 | ||
|
288 | public virtual void CancelOperation(Exception reason) { | |
|
289 | SetCancelled(reason); | |
|
290 | } | |
|
291 | ||
|
292 | public void CancelationRequested(Action<Exception> handler) { | |
|
293 | Safe.ArgumentNotNull(handler, "handler"); | |
|
294 | if (IsCancelRequested) | |
|
295 | handler(CancelReason); | |
|
296 | ||
|
297 | if (m_cancelationHandlers == null) | |
|
298 | Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null); | |
|
299 | ||
|
300 | m_cancelationHandlers.Enqueue(handler); | |
|
301 | ||
|
302 | if (IsCancelRequested && m_cancelationHandlers.TryDequeue(out handler)) | |
|
303 | // TryDeque implies MemoryBarrier() | |
|
304 | handler(m_cancelationReason); | |
|
305 | } | |
|
306 | ||
|
307 | public bool IsCancelRequested { | |
|
308 | get { | |
|
309 | do { | |
|
310 | if (m_cancelRequest == CANCEL_NOT_REQUESTED) | |
|
311 | return false; | |
|
312 | if (m_cancelRequest == CANCEL_REQUESTED) | |
|
313 | return true; | |
|
314 | Thread.MemoryBarrier(); | |
|
315 | } while(true); | |
|
316 | } | |
|
317 | } | |
|
318 | ||
|
319 | public Exception CancelReason { | |
|
320 | get { | |
|
321 | do { | |
|
322 | Thread.MemoryBarrier(); | |
|
323 | } while(m_cancelRequest == CANCEL_REQUESTING); | |
|
324 | ||
|
325 | return m_cancelationReason; | |
|
326 | } | |
|
327 | } | |
|
328 | ||
|
329 | #region ICancellable implementation | |
|
330 | ||
|
331 | public void Cancel() { | |
|
332 | Cancel(null); | |
|
333 | } | |
|
334 | ||
|
335 | public void Cancel(Exception reason) { | |
|
336 | if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING)) { | |
|
337 | m_cancelationReason = reason; | |
|
338 | m_cancelRequest = CANCEL_REQUESTED; | |
|
339 | if (m_cancelationHandlers != null) { | |
|
340 | Action<Exception> handler; | |
|
341 | while (m_cancelationHandlers.TryDequeue(out handler)) | |
|
342 | handler(m_cancelationReason); | |
|
343 | } | |
|
344 | } | |
|
345 | } | |
|
346 | ||
|
347 | #endregion | |
|
348 | } | |
|
349 | } | |
|
350 |
@@ -0,0 +1,185 | |||
|
1 | using System; | |
|
2 | using Implab.Parallels; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public abstract class AbstractPromise<T> : AbstractEvent<AbstractPromise<T>.HandlerDescriptor>, IPromise<T> { | |
|
6 | public struct HandlerDescriptor { | |
|
7 | readonly Action m_handler; | |
|
8 | readonly Action<T> m_success; | |
|
9 | readonly Action<Exception> m_error; | |
|
10 | readonly Action<Exception> m_cancel; | |
|
11 | readonly PromiseEventType m_mask; | |
|
12 | ||
|
13 | public HandlerDescriptor(Action<T> success, Action<Exception> error, Action<Exception> cancel) { | |
|
14 | m_success = success; | |
|
15 | m_error = error; | |
|
16 | m_cancel = cancel; | |
|
17 | } | |
|
18 | ||
|
19 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
20 | m_handler = success; | |
|
21 | m_error = error; | |
|
22 | m_cancel = cancel; | |
|
23 | m_mask = PromiseEventType.Success; | |
|
24 | } | |
|
25 | ||
|
26 | public HandlerDescriptor(Action handler, PromiseEventType mask) { | |
|
27 | m_handler = handler; | |
|
28 | m_mask = mask; | |
|
29 | } | |
|
30 | ||
|
31 | public void SignalSuccess(T result) { | |
|
32 | if (m_success != null) { | |
|
33 | try { | |
|
34 | m_success(result); | |
|
35 | } catch(Exception err) { | |
|
36 | SignalError(err); | |
|
37 | } | |
|
38 | } else if (m_mask & PromiseEventType.Success && m_handler != null) { | |
|
39 | try { | |
|
40 | m_handler(); | |
|
41 | } catch(Exception err) { | |
|
42 | // avoid calling handler twice in case of error | |
|
43 | if (m_error != null) | |
|
44 | SignalError(err); | |
|
45 | } | |
|
46 | } | |
|
47 | } | |
|
48 | ||
|
49 | public void SignalError(Exception err) { | |
|
50 | if (m_error != null) { | |
|
51 | try { | |
|
52 | m_error(err); | |
|
53 | // Analysis disable once EmptyGeneralCatchClause | |
|
54 | } catch { | |
|
55 | } | |
|
56 | } else if (m_mask & PromiseEventType.Error && m_handler != null) { | |
|
57 | try { | |
|
58 | m_handler(); | |
|
59 | // Analysis disable once EmptyGeneralCatchClause | |
|
60 | } catch { | |
|
61 | } | |
|
62 | } | |
|
63 | } | |
|
64 | ||
|
65 | public void SignalCancel(Exception reason) { | |
|
66 | if (m_cancel != null) { | |
|
67 | try { | |
|
68 | m_cancel(reason); | |
|
69 | } catch (Exception err) { | |
|
70 | SignalError(err); | |
|
71 | } | |
|
72 | } else if (m_mask & PromiseEventType.Cancelled && m_handler != null) { | |
|
73 | try { | |
|
74 | m_handler(); | |
|
75 | // Analysis disable once EmptyGeneralCatchClause | |
|
76 | } catch { | |
|
77 | } | |
|
78 | } | |
|
79 | } | |
|
80 | } | |
|
81 | ||
|
82 | ||
|
83 | ||
|
84 | public Type PromiseType { | |
|
85 | get { | |
|
86 | return typeof(T); | |
|
87 | } | |
|
88 | } | |
|
89 | ||
|
90 | public new T Join() { | |
|
91 | WaitResult(-1); | |
|
92 | return m_result; | |
|
93 | } | |
|
94 | public new T Join(int timeout) { | |
|
95 | WaitResult(timeout); | |
|
96 | return m_result; | |
|
97 | } | |
|
98 | ||
|
99 | public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) { | |
|
100 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
101 | return this; | |
|
102 | } | |
|
103 | ||
|
104 | public IPromise<T> On(Action<T> success, Action<Exception> error) { | |
|
105 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
106 | return this; | |
|
107 | } | |
|
108 | ||
|
109 | public IPromise<T> On(Action<T> success) { | |
|
110 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
111 | return this; | |
|
112 | } | |
|
113 | ||
|
114 | public IPromise<T> On(Action handler, PromiseEventType events) { | |
|
115 | AddHandler(new HandlerDescriptor(handler, events)); | |
|
116 | return this; | |
|
117 | } | |
|
118 | ||
|
119 | public IPromise<T> On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
120 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
121 | return this; | |
|
122 | } | |
|
123 | ||
|
124 | public IPromise<T> On(Action success, Action<Exception> error) { | |
|
125 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
126 | return this; | |
|
127 | } | |
|
128 | ||
|
129 | public IPromise<T> On(Action success) { | |
|
130 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
131 | return this; | |
|
132 | } | |
|
133 | ||
|
134 | IPromise IPromise.On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
135 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
136 | return this; | |
|
137 | } | |
|
138 | ||
|
139 | IPromise IPromise.On(Action success, Action<Exception> error) { | |
|
140 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
141 | return this; | |
|
142 | } | |
|
143 | ||
|
144 | IPromise IPromise.On(Action success) { | |
|
145 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
146 | return this; | |
|
147 | } | |
|
148 | ||
|
149 | public IPromise<T2> Cast<T2>() { | |
|
150 | return (IPromise<T2>)this; | |
|
151 | } | |
|
152 | ||
|
153 | #region implemented abstract members of AbstractPromise | |
|
154 | ||
|
155 | protected override Signal GetResolveSignal() { | |
|
156 | var signal = new Signal(); | |
|
157 | AddHandler(new HandlerDescriptor(signal.Set, PromiseEventType.All)); | |
|
158 | return signal; | |
|
159 | } | |
|
160 | ||
|
161 | protected override void SignalSuccess(HandlerDescriptor handler) { | |
|
162 | handler.SignalSuccess(m_result); | |
|
163 | } | |
|
164 | ||
|
165 | protected override void SignalError(HandlerDescriptor handler, Exception error) { | |
|
166 | handler.SignalError(error); | |
|
167 | } | |
|
168 | ||
|
169 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | |
|
170 | handler.SignalCancel(reason); | |
|
171 | } | |
|
172 | ||
|
173 | #endregion | |
|
174 | ||
|
175 | T m_result; | |
|
176 | ||
|
177 | protected void SetResult(T value) { | |
|
178 | if (BeginSetResult()) { | |
|
179 | m_result = value; | |
|
180 | EndSetResult(); | |
|
181 | } | |
|
182 | } | |
|
183 | } | |
|
184 | } | |
|
185 |
@@ -0,0 +1,54 | |||
|
1 | using System; | |
|
2 | using System.Threading; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public class ChainTask : AbstractPromise, IDeferred { | |
|
6 | readonly Func<IPromise> m_task; | |
|
7 | readonly Action<Exception> m_error; | |
|
8 | readonly Action<Exception> m_cancel; | |
|
9 | ||
|
10 | int m_cancelationLock; | |
|
11 | ||
|
12 | public ChainTask(Func<IPromise> task, Func<Exception> error, Func<Exception> cancel) { | |
|
13 | m_task = task; | |
|
14 | } | |
|
15 | ||
|
16 | public void Resolve() { | |
|
17 | if (m_task != null && LockCancelation()) { | |
|
18 | try { | |
|
19 | var operation = m_task(); | |
|
20 | if (operation == null) | |
|
21 | throw new NullReferenceException("The task returned null promise"); | |
|
22 | ||
|
23 | operation.On(SetResult, SetError, SetCancelled); | |
|
24 | ||
|
25 | CancelationRequested(operation.Cancel); | |
|
26 | } catch(Exception err) { | |
|
27 | HandleErrorInternal(err); | |
|
28 | } | |
|
29 | } | |
|
30 | } | |
|
31 | ||
|
32 | public void Reject(Exception error) { | |
|
33 | throw new NotImplementedException(); | |
|
34 | } | |
|
35 | ||
|
36 | protected void HandleErrorInternal(Exception error) { | |
|
37 | if (m_error != null) { | |
|
38 | try { | |
|
39 | m_error(error); | |
|
40 | SetResult(); | |
|
41 | } catch(Exception err) { | |
|
42 | SetError(err); | |
|
43 | } | |
|
44 | } else { | |
|
45 | SetError(error); | |
|
46 | } | |
|
47 | } | |
|
48 | ||
|
49 | protected bool LockCancelation() { | |
|
50 | return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0); | |
|
51 | } | |
|
52 | } | |
|
53 | } | |
|
54 |
@@ -0,0 +1,23 | |||
|
1 | using System; | |
|
2 | using System.Threading; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public class FuncTask<T> : FuncTaskBase<T>, IDeferred { | |
|
6 | readonly Func<T> m_task; | |
|
7 | ||
|
8 | public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel) : base(error,cancel) { | |
|
9 | m_task = task; | |
|
10 | } | |
|
11 | ||
|
12 | public void Resolve() { | |
|
13 | if (m_task != null && LockCancelation()) { | |
|
14 | try { | |
|
15 | SetResult(m_task()); | |
|
16 | } catch(Exception err) { | |
|
17 | HandleErrorInternal(err); | |
|
18 | } | |
|
19 | } | |
|
20 | } | |
|
21 | } | |
|
22 | } | |
|
23 |
@@ -0,0 +1,53 | |||
|
1 | using System; | |
|
2 | using System.Threading; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public class FuncTaskBase<TResult> : AbstractPromise<TResult> { | |
|
6 | readonly Func<Exception, TResult> m_cancel; | |
|
7 | readonly Func<Exception, TResult> m_error; | |
|
8 | ||
|
9 | int m_cancelationLock; | |
|
10 | ||
|
11 | protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel) { | |
|
12 | m_error = error; | |
|
13 | m_cancel = cancel; | |
|
14 | } | |
|
15 | ||
|
16 | public void Reject(Exception error) { | |
|
17 | Safe.ArgumentNotNull(error, "error"); | |
|
18 | if (LockCancelation()) | |
|
19 | HandleErrorInternal(error); | |
|
20 | } | |
|
21 | ||
|
22 | protected void HandleErrorInternal(Exception error) { | |
|
23 | if (m_error != null) { | |
|
24 | try { | |
|
25 | SetResult(m_error(error)); | |
|
26 | } catch(Exception err) { | |
|
27 | SetError(err); | |
|
28 | } | |
|
29 | } else { | |
|
30 | SetError(error); | |
|
31 | } | |
|
32 | } | |
|
33 | ||
|
34 | public override void CancelOperation(Exception reason) { | |
|
35 | if (LockCancelation()) { | |
|
36 | if (m_cancel != null) { | |
|
37 | try { | |
|
38 | SetResult(m_cancel(reason)); | |
|
39 | } catch (Exception err) { | |
|
40 | HandleErrorInternal(err); | |
|
41 | } | |
|
42 | } else { | |
|
43 | SetCancelled(reason); | |
|
44 | } | |
|
45 | } | |
|
46 | } | |
|
47 | ||
|
48 | protected bool LockCancelation() { | |
|
49 | return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0); | |
|
50 | } | |
|
51 | } | |
|
52 | } | |
|
53 |
@@ -0,0 +1,22 | |||
|
1 | using System; | |
|
2 | ||
|
3 | namespace Implab { | |
|
4 | public class FuncTask<TArg, TResult> : FuncTaskBase<TResult>, IDeferred<TArg> { | |
|
5 | readonly Func<TArg, TResult> m_task; | |
|
6 | ||
|
7 | public FuncTask(Func<TArg, TResult> task, Func<Exception, TResult> error,Func<Exception, TResult> cancel) : base(error,cancel) { | |
|
8 | m_task = task; | |
|
9 | } | |
|
10 | ||
|
11 | public void Resolve(TArg value) { | |
|
12 | if (m_task != null && LockCancelation()) { | |
|
13 | try { | |
|
14 | SetResult(m_task(value)); | |
|
15 | } catch (Exception err) { | |
|
16 | HandleErrorInternal(err); | |
|
17 | } | |
|
18 | } | |
|
19 | } | |
|
20 | } | |
|
21 | } | |
|
22 |
@@ -1,295 +1,135 | |||
|
1 | 1 | using System; |
|
2 | 2 | using Implab.Parallels; |
|
3 | using System.Threading; | |
|
4 | using System.Reflection; | |
|
5 | 3 | |
|
6 | 4 | namespace Implab { |
|
7 |
public abstract class AbstractPromise< |
|
|
8 | ||
|
9 | const int UNRESOLVED_SATE = 0; | |
|
10 | const int TRANSITIONAL_STATE = 1; | |
|
11 | const int SUCCEEDED_STATE = 2; | |
|
12 | const int REJECTED_STATE = 3; | |
|
13 | const int CANCELLED_STATE = 4; | |
|
14 | ||
|
15 | const int RESERVED_HANDLERS_COUNT = 4; | |
|
5 | public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | |
|
6 | public struct HandlerDescriptor { | |
|
7 | readonly Action m_handler; | |
|
8 | readonly Action<Exception> m_error; | |
|
9 | readonly Action<Exception> m_cancel; | |
|
10 | readonly PromiseEventType m_mask; | |
|
16 | 11 | |
|
17 | int m_state; | |
|
18 | Exception m_error; | |
|
19 | int m_handlersCount; | |
|
20 | ||
|
21 | readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; | |
|
22 | MTQueue<THandler> m_extraHandlers; | |
|
23 | int m_handlerPointer = -1; | |
|
24 | int m_handlersCommited; | |
|
25 | ||
|
26 | #region state managment | |
|
27 | bool BeginTransit() { | |
|
28 | return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); | |
|
12 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
13 | m_handler = success; | |
|
14 | m_error = error; | |
|
15 | m_cancel = cancel; | |
|
16 | m_mask = PromiseEventType.Success; | |
|
29 | 17 | } |
|
30 | 18 | |
|
31 | void CompleteTransit(int state) { | |
|
32 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) | |
|
33 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |
|
19 | public HandlerDescriptor(Action handler, PromiseEventType mask) { | |
|
20 | m_handler = handler; | |
|
21 | m_mask = mask; | |
|
34 | 22 | } |
|
35 | 23 | |
|
36 | void WaitTransition() { | |
|
37 | while (m_state == TRANSITIONAL_STATE) { | |
|
38 | Thread.MemoryBarrier(); | |
|
24 | public void SignalSuccess() { | |
|
25 | if (m_mask & PromiseEventType.Success && m_handler != null) { | |
|
26 | try { | |
|
27 | m_handler(); | |
|
28 | } catch (Exception err) { | |
|
29 | // avoid calling handler twice in case of error | |
|
30 | if (m_error != null) | |
|
31 | SignalError(err); | |
|
32 | } | |
|
39 | 33 | } |
|
40 | 34 | } |
|
41 | 35 | |
|
42 | protected bool BeginSetResult() { | |
|
43 | if (!BeginTransit()) { | |
|
44 |
|
|
|
45 | if (m_state != CANCELLED_STATE) | |
|
46 | throw new InvalidOperationException("The promise is already resolved"); | |
|
47 |
|
|
|
36 | public void SignalError(Exception err) { | |
|
37 | if (m_error != null) { | |
|
38 | try { | |
|
39 | m_error(err); | |
|
40 | // Analysis disable once EmptyGeneralCatchClause | |
|
41 | } catch { | |
|
48 | 42 | } |
|
49 | return true; | |
|
43 | } else if (m_mask & PromiseEventType.Error && m_handler != null) { | |
|
44 | try { | |
|
45 | m_handler(); | |
|
46 | // Analysis disable once EmptyGeneralCatchClause | |
|
47 | } catch { | |
|
48 | } | |
|
49 | } | |
|
50 | 50 | } |
|
51 | 51 | |
|
52 | protected void EndSetResult() { | |
|
53 | CompleteTransit(SUCCEEDED_STATE); | |
|
54 | OnSuccess(); | |
|
52 | public void SignalCancel(Exception reason) { | |
|
53 | if (m_cancel != null) { | |
|
54 | try { | |
|
55 | m_cancel(reason); | |
|
56 | } catch (Exception err) { | |
|
57 | SignalError(err); | |
|
58 | } | |
|
59 | } else if (m_mask & PromiseEventType.Cancelled && m_handler != null) { | |
|
60 | try { | |
|
61 | m_handler(); | |
|
62 | // Analysis disable once EmptyGeneralCatchClause | |
|
63 | } catch { | |
|
64 | } | |
|
65 | } | |
|
66 | } | |
|
55 | 67 | } |
|
56 | 68 | |
|
57 | 69 | |
|
70 | #region implemented abstract members of AbstractPromise | |
|
58 | 71 | |
|
59 | /// <summary> | |
|
60 | /// ΠΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅, ΡΠΎΠΎΠ±ΡΠ°Ρ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅ | |
|
61 | /// </summary> | |
|
62 | /// <remarks> | |
|
63 | /// ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡΠΎΡΠ½ΠΎΠΉ ΡΡΠ΅Π΄Π΅, ΠΏΡΠΈ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠΎΠΊΠΎΠ² | |
|
64 | /// ΠΌΠΎΠ³Ρ Π²Π΅ΡΠ½ΡΡΡ ΠΎΡΠΈΠ±ΠΊΡ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ²Π°Ρ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ | |
|
65 | /// Π±ΡΠ΄ΡΡ ΠΏΡΠΎΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Ρ. | |
|
66 | /// </remarks> | |
|
67 | /// <param name="error">ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ</param> | |
|
68 | /// <exception cref="InvalidOperationException">ΠΠ°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠΆΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception> | |
|
69 | protected void SetError(Exception error) { | |
|
70 | if (BeginTransit()) { | |
|
71 | if (error is OperationCanceledException) { | |
|
72 | CompleteTransit(CANCELLED_STATE); | |
|
73 | m_error = error.InnerException; | |
|
74 | OnCancelled(); | |
|
75 | } else { | |
|
76 | m_error = error is PromiseTransientException ? error.InnerException : error; | |
|
77 | CompleteTransit(REJECTED_STATE); | |
|
78 | OnError(); | |
|
79 | } | |
|
80 | } else { | |
|
81 | WaitTransition(); | |
|
82 | if (m_state == SUCCEEDED_STATE) | |
|
83 | throw new InvalidOperationException("The promise is already resolved"); | |
|
84 | } | |
|
85 | } | |
|
86 | ||
|
87 | /// <summary> | |
|
88 | /// ΠΡΠΌΠ΅Π½ΡΠ΅Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ, Π΅ΡΠ»ΠΈ ΡΡΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. | |
|
89 | /// </summary> | |
|
90 | /// <remarks>ΠΠ»Ρ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π±ΡΠ»Π° Π»ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ ΠΎΡΠΌΠ΅Π½Π΅Π½Π° ΡΠ»Π΅Π΄ΡΠ΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠ²ΠΎΠΉΡΡΠ²ΠΎ <see cref="IsCancelled"/>.</remarks> | |
|
91 | protected void SetCancelled(Exception reason) { | |
|
92 | if (BeginTransit()) { | |
|
93 | m_error = reason; | |
|
94 | CompleteTransit(CANCELLED_STATE); | |
|
95 | OnCancelled(); | |
|
96 | } | |
|
72 | protected override void SignalSuccess(HandlerDescriptor handler) { | |
|
73 | handler.SignalSuccess(); | |
|
97 | 74 | } |
|
98 | 75 | |
|
99 |
protected |
|
|
100 | ||
|
101 | protected abstract void SignalError(THandler handler, Exception error); | |
|
102 | ||
|
103 | protected abstract void SignalCancelled(THandler handler, Exception reason); | |
|
104 | ||
|
105 | void OnSuccess() { | |
|
106 | var hp = m_handlerPointer; | |
|
107 | var slot = hp +1 ; | |
|
108 | while (slot < m_handlersCommited) { | |
|
109 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
110 | SignalSuccess(m_handlers[slot]); | |
|
111 | } | |
|
112 | hp = m_handlerPointer; | |
|
113 | slot = hp +1 ; | |
|
114 | } | |
|
115 | ||
|
116 | ||
|
117 | if (m_extraHandlers != null) { | |
|
118 | THandler handler; | |
|
119 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
120 | SignalSuccess(handler); | |
|
121 | } | |
|
76 | protected override void SignalError(HandlerDescriptor handler, Exception error) { | |
|
77 | handler.SignalError(error); | |
|
122 | 78 | } |
|
123 | 79 | |
|
124 | void OnError() { | |
|
125 | var hp = m_handlerPointer; | |
|
126 | var slot = hp +1 ; | |
|
127 | while (slot < m_handlersCommited) { | |
|
128 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
129 | SignalError(m_handlers[slot],m_error); | |
|
130 | } | |
|
131 | hp = m_handlerPointer; | |
|
132 | slot = hp +1 ; | |
|
80 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | |
|
81 | handler.SignalCancel(reason); | |
|
133 | 82 |
|
|
134 | 83 | |
|
135 | if (m_extraHandlers != null) { | |
|
136 | THandler handler; | |
|
137 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
138 | SignalError(handler, m_error); | |
|
139 | } | |
|
140 | } | |
|
141 | ||
|
142 | void OnCancelled() { | |
|
143 | var hp = m_handlerPointer; | |
|
144 | var slot = hp +1 ; | |
|
145 | while (slot < m_handlersCommited) { | |
|
146 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
147 | SignalCancelled(m_handlers[slot], m_error); | |
|
148 | } | |
|
149 | hp = m_handlerPointer; | |
|
150 | slot = hp +1 ; | |
|
151 | } | |
|
152 | ||
|
153 | if (m_extraHandlers != null) { | |
|
154 | THandler handler; | |
|
155 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
156 | SignalCancelled(handler, m_error); | |
|
157 | } | |
|
84 | protected override Signal GetResolveSignal() { | |
|
85 | var signal = new Signal(); | |
|
86 | On(signal.Set, PromiseEventType.All); | |
|
158 | 87 | } |
|
159 | 88 | |
|
160 | 89 | #endregion |
|
161 | 90 | |
|
162 | protected abstract void Listen(PromiseEventType events, Action handler); | |
|
163 | 91 | |
|
164 | #region synchronization traits | |
|
165 | protected void WaitResult(int timeout) { | |
|
166 | if (!IsResolved) { | |
|
167 | var lk = new object(); | |
|
168 | ||
|
169 | Listen(PromiseEventType.All, () => { | |
|
170 | lock(lk) { | |
|
171 | Monitor.Pulse(lk); | |
|
172 | } | |
|
173 | }); | |
|
174 | ||
|
175 | lock (lk) { | |
|
176 | while(!IsResolved) { | |
|
177 | if(!Monitor.Wait(lk,timeout)) | |
|
178 | throw new TimeoutException(); | |
|
92 | public Type PromiseType { | |
|
93 | get { | |
|
94 | return typeof(void); | |
|
179 | 95 |
|
|
180 | 96 |
|
|
181 | 97 | |
|
98 | public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
99 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
100 | return this; | |
|
182 | 101 |
|
|
183 | switch (m_state) { | |
|
184 | case SUCCEEDED_STATE: | |
|
185 | return; | |
|
186 | case CANCELLED_STATE: | |
|
187 | throw new OperationCanceledException(); | |
|
188 | case REJECTED_STATE: | |
|
189 | throw new TargetInvocationException(m_error); | |
|
190 | default: | |
|
191 | throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); | |
|
192 | } | |
|
193 | } | |
|
194 | #endregion | |
|
195 | 102 | |
|
196 | #region handlers managment | |
|
197 | ||
|
198 | protected void AddHandler(THandler handler) { | |
|
199 | ||
|
200 | if (m_state > 1) { | |
|
201 | // the promise is in the resolved state, just invoke the handler | |
|
202 | InvokeHandler(handler); | |
|
203 | } else { | |
|
204 | var slot = Interlocked.Increment(ref m_handlersCount) - 1; | |
|
205 | ||
|
206 | if (slot < RESERVED_HANDLERS_COUNT) { | |
|
207 | m_handlers[slot] = handler; | |
|
208 | ||
|
209 | while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) { | |
|
103 | public IPromise On(Action success, Action<Exception> error) { | |
|
104 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
105 | return this; | |
|
210 | 106 |
|
|
211 | 107 | |
|
212 | if (m_state > 1) { | |
|
213 | do { | |
|
214 | var hp = m_handlerPointer; | |
|
215 | slot = hp + 1; | |
|
216 | if (slot < m_handlersCommited) { | |
|
217 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp) | |
|
218 | continue; | |
|
219 | InvokeHandler(m_handlers[slot]); | |
|
220 | } | |
|
221 | break; | |
|
222 | } while(true); | |
|
223 | } | |
|
224 | } else { | |
|
225 | if (slot == RESERVED_HANDLERS_COUNT) { | |
|
226 | m_extraHandlers = new MTQueue<THandler>(); | |
|
227 | } else { | |
|
228 | while (m_extraHandlers == null) | |
|
229 | Thread.MemoryBarrier(); | |
|
108 | public IPromise On(Action success) { | |
|
109 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
110 | return this; | |
|
230 | 111 |
|
|
231 | 112 | |
|
232 | m_extraHandlers.Enqueue(handler); | |
|
233 | ||
|
234 | if (m_state > 1 && m_extraHandlers.TryDequeue(out handler)) | |
|
235 | // if the promise have been resolved while we was adding the handler to the queue | |
|
236 | // we can't guarantee that someone is still processing it | |
|
237 | // therefore we need to fetch a handler from the queue and execute it | |
|
238 | // note that fetched handler may be not the one that we have added | |
|
239 | // even we can fetch no handlers at all :) | |
|
240 | InvokeHandler(handler); | |
|
241 | } | |
|
242 | } | |
|
113 | public IPromise On(Action handler, PromiseEventType events) { | |
|
114 | AddHandler(new HandlerDescriptor(handler,events)); | |
|
115 | return this; | |
|
243 | 116 | } |
|
244 | 117 | |
|
245 | protected void InvokeHandler(THandler handler) { | |
|
246 | switch (m_state) { | |
|
247 | case SUCCEEDED_STATE: | |
|
248 | SignalSuccess(handler); | |
|
249 | break; | |
|
250 | case CANCELLED_STATE: | |
|
251 | SignalCancelled(handler, m_error); | |
|
252 | break; | |
|
253 | case REJECTED_STATE: | |
|
254 | SignalError(handler, m_error); | |
|
255 | break; | |
|
256 | default: | |
|
257 | throw new Exception(String.Format("Invalid promise state {0}", m_state)); | |
|
258 | } | |
|
259 | } | |
|
260 | ||
|
261 | #endregion | |
|
262 | ||
|
263 | #region IPromise implementation | |
|
264 | ||
|
265 | public void Join(int timeout) { | |
|
266 | WaitResult(timeout); | |
|
118 | public IPromise<T> Cast<T>() { | |
|
119 | throw new InvalidCastException(); | |
|
267 | 120 | } |
|
268 | 121 | |
|
269 | 122 | public void Join() { |
|
270 | 123 | WaitResult(-1); |
|
271 | 124 | } |
|
272 | 125 | |
|
273 | public bool IsResolved { | |
|
274 | get { | |
|
275 | Thread.MemoryBarrier(); | |
|
276 | return m_state > 1; | |
|
277 | } | |
|
126 | public void Join(int timeout) { | |
|
127 | WaitResult(timeout); | |
|
278 | 128 | } |
|
279 | 129 | |
|
280 | public bool IsCancelled { | |
|
281 |
|
|
|
282 | Thread.MemoryBarrier(); | |
|
283 | return m_state == CANCELLED_STATE; | |
|
284 | } | |
|
285 | } | |
|
286 | ||
|
287 | #endregion | |
|
288 | ||
|
289 | public Exception Error { | |
|
290 | get { | |
|
291 | return m_error; | |
|
292 | } | |
|
130 | protected void SetResult() { | |
|
131 | BeginSetResult(); | |
|
132 | EndSetResult(); | |
|
293 | 133 | } |
|
294 | 134 | } |
|
295 | 135 | } |
@@ -22,14 +22,14 namespace Implab { | |||
|
22 | 22 | /// Sets the token to cancelled state. |
|
23 | 23 | /// </summary> |
|
24 | 24 | /// <param name="reason">The reason why the operation was cancelled.</param> |
|
25 |
void |
|
|
25 | void CancelOperation(Exception reason); | |
|
26 | 26 | |
|
27 | 27 | /// <summary> |
|
28 | 28 | /// Adds the listener for the cancellation request, is the cancellation was requested the <paramref name="handler"/> |
|
29 | 29 | /// is executed immediatelly. |
|
30 | 30 | /// </summary> |
|
31 | 31 | /// <param name="handler">The handler which will be executed if the cancel occurs.</param> |
|
32 |
void Cancel |
|
|
32 | void CancelationRequested(Action<Exception> handler); | |
|
33 | 33 | |
|
34 | 34 | } |
|
35 | 35 | } |
@@ -58,13 +58,13 namespace Implab { | |||
|
58 | 58 | /// exception it will be passed to the dependent promise. |
|
59 | 59 | /// </para> |
|
60 | 60 | /// </remarks> |
|
61 | IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel); | |
|
61 | /* IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel); | |
|
62 | 62 | IPromise Then(Action success, Action<Exception> error); |
|
63 | 63 | IPromise Then(Action success); |
|
64 | 64 |
|
|
65 | 65 | IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel); |
|
66 | 66 | IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error); |
|
67 |
|
|
|
67 | IPromise Chain(Func<IPromise> chained);*/ | |
|
68 | 68 | |
|
69 | 69 | /// <summary> |
|
70 | 70 | /// Adds specified listeners to the current promise. |
@@ -3,28 +3,23 | |||
|
3 | 3 | namespace Implab { |
|
4 | 4 | public interface IPromise<out T> : IPromise { |
|
5 | 5 | |
|
6 | new T Join(); | |
|
7 | ||
|
8 | new T Join(int timeout); | |
|
9 | ||
|
10 | 6 | IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel); |
|
11 | 7 | |
|
12 | 8 | IPromise<T> On(Action<T> success, Action<Exception> error); |
|
13 | 9 | |
|
14 | 10 | IPromise<T> On(Action<T> success); |
|
15 | 11 | |
|
12 | new T Join(); | |
|
13 | ||
|
14 | new T Join(int timeout); | |
|
15 | ||
|
16 | new IPromise<T> On(Action success, Action<Exception> error, Action<Exception> cancel); | |
|
17 | ||
|
18 | new IPromise<T> On(Action success, Action<Exception> error); | |
|
19 | ||
|
20 | new IPromise<T> On(Action success); | |
|
21 | ||
|
16 | 22 | new IPromise<T> On(Action handler, PromiseEventType events); |
|
17 | 23 | |
|
18 | IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel); | |
|
19 | ||
|
20 | IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error); | |
|
21 | ||
|
22 | IPromise<T2> Then<T2>(Func<T, T2> mapper); | |
|
23 | ||
|
24 | IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel); | |
|
25 | ||
|
26 | IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error); | |
|
27 | ||
|
28 | IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained); | |
|
29 | 24 | } |
|
30 | 25 | } |
@@ -150,7 +150,6 | |||
|
150 | 150 | <Compile Include="PromiseT.cs" /> |
|
151 | 151 | <Compile Include="IDeferred.cs" /> |
|
152 | 152 | <Compile Include="IDeferredT.cs" /> |
|
153 | <Compile Include="AbstractPromise.cs" /> | |
|
154 | 153 | <Compile Include="Promise.cs" /> |
|
155 | 154 | <Compile Include="PromiseTransientException.cs" /> |
|
156 | 155 | <Compile Include="Parallels\Signal.cs" /> |
@@ -159,6 +158,13 | |||
|
159 | 158 | <Compile Include="Diagnostics\ListenerBase.cs" /> |
|
160 | 159 | <Compile Include="Parallels\BlockingQueue.cs" /> |
|
161 | 160 | <Compile Include="ICancelationToken.cs" /> |
|
161 | <Compile Include="AbstractEvent.cs" /> | |
|
162 | <Compile Include="AbstractPromise.cs" /> | |
|
163 | <Compile Include="AbstractPromiseT.cs" /> | |
|
164 | <Compile Include="FuncTask.cs" /> | |
|
165 | <Compile Include="FuncTaskBase.cs" /> | |
|
166 | <Compile Include="FuncTaskT.cs" /> | |
|
167 | <Compile Include="ChainTask.cs" /> | |
|
162 | 168 | </ItemGroup> |
|
163 | 169 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
164 | 170 | <ItemGroup /> |
@@ -1,222 +1,22 | |||
|
1 | 1 | using System; |
|
2 | using System.Diagnostics; | |
|
2 | using Implab.Parallels; | |
|
3 | 3 | |
|
4 | 4 | namespace Implab { |
|
5 |
public class Promise : AbstractPromise |
|
|
6 | ||
|
7 | public struct HandlerDescriptor { | |
|
8 | readonly Action m_success; | |
|
9 | readonly Action<Exception> m_error; | |
|
10 | readonly Action<Exception> m_cancel; | |
|
11 | readonly IDeferred m_deferred; | |
|
12 | ||
|
13 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel, IDeferred deferred) { | |
|
14 | m_success = success; | |
|
15 | m_error = error; | |
|
16 | m_cancel = cancel; | |
|
17 | m_deferred = deferred; | |
|
18 | } | |
|
19 | ||
|
20 | public void SignalSuccess() { | |
|
21 | if (m_success != null) { | |
|
22 | try { | |
|
23 | m_success(); | |
|
24 | if (m_deferred != null) | |
|
25 | m_deferred.Resolve(); | |
|
26 | } catch (Exception err) { | |
|
27 | SignalError(err); | |
|
28 | } | |
|
29 | } | |
|
30 | } | |
|
5 | public class Promise : AbstractPromise, IDeferred { | |
|
6 | public static readonly Promise SUCCESS; | |
|
31 | 7 | |
|
32 | public void SignalError(Exception err) { | |
|
33 | if (m_error != null) { | |
|
34 | try { | |
|
35 | m_error(err); | |
|
36 | if (m_deferred != null) | |
|
37 | m_deferred.Resolve(); | |
|
38 | } catch (Exception err2) { | |
|
39 | if (m_deferred != null) | |
|
40 | m_deferred.Reject(err2); | |
|
41 | } | |
|
42 | } else { | |
|
43 | if (m_deferred != null) | |
|
44 | m_deferred.Reject(err); | |
|
45 | } | |
|
46 | } | |
|
47 | ||
|
48 | public void SignalCancel(Exception reason) { | |
|
49 | if (m_cancel != null) { | |
|
50 | try { | |
|
51 | m_cancel(reason); | |
|
52 | if (m_deferred != null) | |
|
53 | m_deferred.Resolve(); | |
|
54 | } catch (Exception err) { | |
|
55 | SignalError(err); | |
|
56 | } | |
|
57 | } else if (reason != null && m_error != null) { | |
|
58 | try { | |
|
59 | m_error(new OperationCanceledException("The operation was canceled.", reason)); | |
|
60 | if (m_deferred != null) | |
|
61 | m_deferred.Resolve(); | |
|
62 | } catch (Exception err) { | |
|
63 | SignalError(err); | |
|
64 | } | |
|
65 | } else { | |
|
66 | if (m_deferred != null) | |
|
67 | m_deferred.Cancel(reason); | |
|
68 | } | |
|
69 | } | |
|
8 | static Promise() { | |
|
9 | SUCCESS = new Promise(); | |
|
10 | SUCCESS.Resolve(); | |
|
70 | 11 | } |
|
71 | 12 | |
|
72 | 13 | public void Resolve() { |
|
73 |
|
|
|
74 | EndSetResult(); | |
|
14 | SetResult(); | |
|
75 | 15 | } |
|
76 | 16 | |
|
77 | 17 | public void Reject(Exception error) { |
|
78 | 18 | SetError(error); |
|
79 | 19 | } |
|
80 | ||
|
81 | #region implemented abstract members of AbstractPromise | |
|
82 | ||
|
83 | protected override void SignalSuccess(HandlerDescriptor handler) { | |
|
84 | handler.SignalSuccess(); | |
|
85 | } | |
|
86 | ||
|
87 | protected override void SignalError(HandlerDescriptor handler, Exception error) { | |
|
88 | handler.SignalError(error); | |
|
89 | } | |
|
90 | ||
|
91 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | |
|
92 | handler.SignalCancel(reason); | |
|
93 | } | |
|
94 | ||
|
95 | protected override void Listen(PromiseEventType events, Action handler) { | |
|
96 | AddHandler(new HandlerDescriptor( | |
|
97 | events.HasFlag(PromiseEventType.Success) ? handler : null, | |
|
98 | events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null, | |
|
99 | events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null, | |
|
100 | null | |
|
101 | )); | |
|
102 | } | |
|
103 | ||
|
104 | #endregion | |
|
105 | ||
|
106 | ||
|
107 | public Type PromiseType { | |
|
108 | get { | |
|
109 | return typeof(void); | |
|
110 | 20 | } |
|
111 | 21 | } |
|
112 | 22 | |
|
113 | public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
114 | var promise = new Promise(); | |
|
115 | if (success != null) | |
|
116 | promise.On(Cancel, PromiseEventType.Cancelled); | |
|
117 | ||
|
118 | AddHandler(new HandlerDescriptor(success, error, cancel, promise)); | |
|
119 | ||
|
120 | return promise; | |
|
121 | } | |
|
122 | ||
|
123 | public IPromise Then(Action success, Action<Exception> error) { | |
|
124 | return Then(success, error, null); | |
|
125 | } | |
|
126 | ||
|
127 | public IPromise Then(Action success) { | |
|
128 | return Then(success, null, null); | |
|
129 | } | |
|
130 | ||
|
131 | public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
132 | AddHandler(new HandlerDescriptor(success, error, cancel, null)); | |
|
133 | return this; | |
|
134 | } | |
|
135 | ||
|
136 | public IPromise On(Action success, Action<Exception> error) { | |
|
137 | return On(success, error, null); | |
|
138 | } | |
|
139 | ||
|
140 | public IPromise On(Action success) { | |
|
141 | return On(success, null, null); | |
|
142 | } | |
|
143 | ||
|
144 | public IPromise On(Action handler, PromiseEventType events) { | |
|
145 | return On( | |
|
146 | events.HasFlag(PromiseEventType.Success) ? handler : null, | |
|
147 | events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null, | |
|
148 | events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null | |
|
149 | ); | |
|
150 | } | |
|
151 | ||
|
152 | public IPromise<T> Cast<T>() { | |
|
153 | throw new InvalidCastException(); | |
|
154 | } | |
|
155 | ||
|
156 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception,IPromise> cancel) { | |
|
157 | var medium = new Promise(); | |
|
158 | ||
|
159 | On( | |
|
160 | () => { | |
|
161 | if (medium.IsCancelled) | |
|
162 | return; | |
|
163 | if (chained != null) | |
|
164 | ConnectPromise(chained(), medium); | |
|
165 | }, | |
|
166 | ex => { | |
|
167 | if (medium.IsCancelled) | |
|
168 | return; | |
|
169 | if (error != null) { | |
|
170 | try { | |
|
171 | ConnectPromise(error(ex), medium); | |
|
172 | } catch (Exception ex2) { | |
|
173 | medium.Reject(ex2); | |
|
174 | } | |
|
175 | } else { | |
|
176 | medium.Reject(ex); | |
|
177 | } | |
|
178 | }, | |
|
179 | reason => { | |
|
180 | if (medium.IsCancelled) | |
|
181 | return; | |
|
182 | if (cancel != null) | |
|
183 | ConnectPromise(cancel(reason), medium); | |
|
184 | else | |
|
185 | medium.Cancel(reason); | |
|
186 | } | |
|
187 | ); | |
|
188 | ||
|
189 | if (chained != null) | |
|
190 | medium.On(Cancel, PromiseEventType.Cancelled); | |
|
191 | ||
|
192 | return medium; | |
|
193 | } | |
|
194 | ||
|
195 | static void ConnectPromise(IPromise result, Promise medium) { | |
|
196 | if (result != null) { | |
|
197 | result.On( | |
|
198 | medium.Resolve, | |
|
199 | medium.Reject, | |
|
200 | medium.Cancel | |
|
201 | ); | |
|
202 | medium.On(null,null,result.Cancel); | |
|
203 | } else { | |
|
204 | medium.Reject( | |
|
205 | new NullReferenceException( | |
|
206 | "The chained asynchronous operation returned" + | |
|
207 | " 'null' where the promise instance is expected" | |
|
208 | ) | |
|
209 | ); | |
|
210 | } | |
|
211 | } | |
|
212 | ||
|
213 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) { | |
|
214 | return Chain(chained, error, null); | |
|
215 | } | |
|
216 | ||
|
217 | public IPromise Chain(Func<IPromise> chained) { | |
|
218 | return Chain(chained, null, null); | |
|
219 | } | |
|
220 | } | |
|
221 | } | |
|
222 |
This diff has been collapsed as it changes many lines, (533 lines changed) Show them Hide them | |||
@@ -1,5 +1,6 | |||
|
1 | 1 | using System; |
|
2 | 2 | using System.Diagnostics; |
|
3 | using Implab.Parallels; | |
|
3 | 4 | |
|
4 | 5 | namespace Implab { |
|
5 | 6 | |
@@ -37,538 +38,26 namespace Implab { | |||
|
37 | 38 | /// ΡΠΎΠ»ΡΠΊΠΎ ΠΈΠ½ΠΈΡΠΈΠ°ΡΠΎΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ ΠΈΠ½Π°ΡΠ΅ ΠΌΠΎΠ³ΡΡ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡΡΡ ΠΏΡΠΎΡΠΈΠ²ΠΎΡΠ΅ΡΠΈΡ. |
|
38 | 39 | /// </para> |
|
39 | 40 | /// </remarks> |
|
40 |
public class Promise<T> : AbstractPromise< |
|
|
41 | ||
|
42 | class StubDeferred : IDeferred, IDeferred<T> { | |
|
43 | public static readonly StubDeferred instance = new StubDeferred(); | |
|
44 | ||
|
45 | StubDeferred() { | |
|
46 | } | |
|
47 | ||
|
48 | #region IDeferred implementation | |
|
49 | ||
|
50 | public void Resolve(T value) { | |
|
51 | } | |
|
52 | ||
|
53 | public void Resolve() { | |
|
54 | } | |
|
55 | ||
|
56 | public void Reject(Exception error) { | |
|
57 | } | |
|
58 | ||
|
59 | #endregion | |
|
60 | ||
|
61 | #region ICancellable implementation | |
|
62 | ||
|
63 | public void Cancel() { | |
|
64 | } | |
|
65 | ||
|
66 | public void Cancel(Exception reason) { | |
|
67 | } | |
|
68 | ||
|
69 | #endregion | |
|
70 | ||
|
71 | ||
|
72 | } | |
|
73 | ||
|
74 | class RemapDescriptor<T2> : IDeferred<T> { | |
|
75 | readonly Func<T,T2> m_remap; | |
|
76 | readonly Func<Exception, T2> m_failed; | |
|
77 | readonly Func<Exception, T2> m_cancel; | |
|
78 | readonly IDeferred<T2> m_deferred; | |
|
79 | ||
|
80 | public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<Exception, T2> cancel, IDeferred<T2> deferred ) { | |
|
81 | Debug.Assert(deferred != null); | |
|
82 | m_remap = remap; | |
|
83 | m_failed = failed; | |
|
84 | m_cancel = cancel; | |
|
85 | m_deferred = deferred; | |
|
86 | } | |
|
87 | ||
|
88 | ||
|
89 | ||
|
90 | #region IDeferred implementation | |
|
91 | ||
|
92 | public void Resolve(T value) { | |
|
93 | if (m_remap != null) { | |
|
94 | try { | |
|
95 | m_deferred.Resolve(m_remap(value)); | |
|
96 | } catch (Exception ex) { | |
|
97 | Reject(ex); | |
|
98 | } | |
|
99 | } | |
|
100 | } | |
|
41 | public class Promise<T> : AbstractPromise<T>, IDeferred<T> { | |
|
101 | 42 | |
|
102 | public void Reject(Exception error) { | |
|
103 | if (m_failed != null) { | |
|
104 | try { | |
|
105 | m_deferred.Resolve(m_failed(error)); | |
|
106 | } catch (Exception ex) { | |
|
107 | m_deferred.Reject(ex); | |
|
108 | } | |
|
109 | } else { | |
|
110 | m_deferred.Reject(error); | |
|
111 | } | |
|
112 | } | |
|
113 | ||
|
114 | ||
|
115 | #endregion | |
|
116 | ||
|
117 | #region ICancellable implementation | |
|
118 | ||
|
119 | public void Cancel(Exception reason) { | |
|
120 | if (m_cancel != null) { | |
|
121 | try { | |
|
122 | m_deferred.Resolve(m_cancel(reason)); | |
|
123 | } catch (Exception ex) { | |
|
124 | Reject(ex); | |
|
125 | } | |
|
126 | } else { | |
|
127 | m_deferred.Cancel(reason); | |
|
128 | } | |
|
129 | } | |
|
130 | ||
|
131 | public void Cancel() { | |
|
132 | Cancel(null); | |
|
133 | } | |
|
134 | #endregion | |
|
135 | } | |
|
136 | ||
|
137 | class ListenerDescriptor : IDeferred<T> { | |
|
138 | readonly Action m_handler; | |
|
139 | readonly PromiseEventType m_events; | |
|
140 | ||
|
141 | public ListenerDescriptor(Action handler, PromiseEventType events) { | |
|
142 | Debug.Assert(handler != null); | |
|
143 | ||
|
144 | m_handler = handler; | |
|
145 | m_events = events; | |
|
146 | } | |
|
147 | ||
|
148 | #region IDeferred implementation | |
|
149 | ||
|
150 | public void Resolve(T value) { | |
|
151 | if (m_events.HasFlag(PromiseEventType.Success)) { | |
|
152 | try { | |
|
153 | m_handler(); | |
|
154 | // Analysis disable once EmptyGeneralCatchClause | |
|
155 | } catch { | |
|
156 | } | |
|
157 | } | |
|
158 | } | |
|
159 | ||
|
160 | public void Reject(Exception error) { | |
|
161 | if (m_events.HasFlag(PromiseEventType.Error)){ | |
|
162 | try { | |
|
163 | m_handler(); | |
|
164 | // Analysis disable once EmptyGeneralCatchClause | |
|
165 | } catch { | |
|
166 | } | |
|
167 | } | |
|
168 | } | |
|
169 | ||
|
170 | #endregion | |
|
171 | ||
|
172 | #region ICancellable implementation | |
|
173 | ||
|
174 | public void Cancel() { | |
|
175 | Cancel(null); | |
|
43 | public static IPromise<T> FromResult(T value) { | |
|
44 | var p = new Promise<T>(); | |
|
45 | p.Resolve(value); | |
|
46 | return p; | |
|
176 | 47 |
|
|
177 | 48 | |
|
178 |
|
|
|
179 | if (m_events.HasFlag(PromiseEventType.Cancelled)){ | |
|
180 | try { | |
|
181 | m_handler(); | |
|
182 | // Analysis disable once EmptyGeneralCatchClause | |
|
183 | } catch { | |
|
184 | } | |
|
185 | } | |
|
186 | } | |
|
187 | ||
|
188 | #endregion | |
|
189 | } | |
|
190 | ||
|
191 | class ValueEventDescriptor : IDeferred<T> { | |
|
192 | readonly Action<T> m_success; | |
|
193 | readonly Action<Exception> m_failed; | |
|
194 | readonly Action<Exception> m_cancelled; | |
|
195 | readonly IDeferred<T> m_deferred; | |
|
196 | ||
|
197 | public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action<Exception> cancelled, IDeferred<T> deferred) { | |
|
198 | Debug.Assert(deferred != null); | |
|
199 | ||
|
200 | m_success = success; | |
|
201 | m_failed = failed; | |
|
202 | m_cancelled = cancelled; | |
|
203 | m_deferred = deferred; | |
|
204 | } | |
|
205 | ||
|
206 | #region IDeferred implementation | |
|
207 | ||
|
208 | public void Resolve(T value) { | |
|
209 | if (m_success != null) { | |
|
210 | try { | |
|
211 | m_success(value); | |
|
212 | m_deferred.Resolve(value); | |
|
213 | } catch (Exception ex) { | |
|
214 | Reject(ex); | |
|
215 | } | |
|
216 | } | |
|
217 | } | |
|
218 | ||
|
219 | public void Reject(Exception error) { | |
|
220 | if (m_failed != null) { | |
|
221 | try { | |
|
222 | m_failed(error); | |
|
223 | m_deferred.Resolve(default(T)); | |
|
224 | } catch(Exception ex) { | |
|
225 | m_deferred.Reject(ex); | |
|
226 | } | |
|
227 | } else { | |
|
228 | m_deferred.Reject(error); | |
|
229 | } | |
|
230 | } | |
|
231 | ||
|
232 | #endregion | |
|
233 | ||
|
234 | #region ICancellable implementation | |
|
235 | ||
|
236 | public void Cancel(Exception reason) { | |
|
237 | if (m_cancelled != null) { | |
|
238 | try { | |
|
239 | m_cancelled(reason); | |
|
240 | m_deferred.Resolve(default(T)); | |
|
241 | } catch (Exception ex) { | |
|
242 | Reject(ex); | |
|
243 | } | |
|
244 | } else { | |
|
245 | m_deferred.Cancel(reason); | |
|
246 | } | |
|
247 | } | |
|
248 | ||
|
249 | public void Cancel() { | |
|
250 | Cancel(null); | |
|
49 | public static IPromise<T> FromException(Exception error) { | |
|
50 | var p = new Promise<T>(); | |
|
51 | p.Reject(error); | |
|
52 | return p; | |
|
251 | 53 |
|
|
252 | 54 | |
|
253 | #endregion | |
|
254 | } | |
|
255 | ||
|
256 | public class EventDescriptor : IDeferred<T> { | |
|
257 | readonly Action m_success; | |
|
258 | readonly Action<Exception> m_failed; | |
|
259 | readonly Action<Exception> m_cancelled; | |
|
260 | readonly IDeferred m_deferred; | |
|
261 | ||
|
262 | public EventDescriptor(Action success, Action<Exception> failed, Action<Exception> cancelled, IDeferred deferred) { | |
|
263 | Debug.Assert(deferred != null); | |
|
264 | ||
|
265 | m_success = success; | |
|
266 | m_failed = failed; | |
|
267 | m_cancelled = cancelled; | |
|
268 | m_deferred = deferred; | |
|
269 | } | |
|
270 | ||
|
271 | #region IDeferred implementation | |
|
272 | ||
|
273 | public void Resolve(T value) { | |
|
274 | if (m_success != null) { | |
|
275 | try { | |
|
276 | m_success(); | |
|
277 | m_deferred.Resolve(); | |
|
278 | } catch (Exception ex) { | |
|
279 | Reject(ex); | |
|
280 | } | |
|
281 | } | |
|
282 | } | |
|
283 | ||
|
284 | public void Reject(Exception error) { | |
|
285 | if (m_failed != null) { | |
|
286 | try { | |
|
287 | m_failed(error); | |
|
288 | m_deferred.Resolve(); | |
|
289 | } catch (Exception ex) { | |
|
290 | m_deferred.Reject(ex); | |
|
291 | } | |
|
292 | } else { | |
|
293 | m_deferred.Reject(error); | |
|
294 | } | |
|
295 | } | |
|
296 | ||
|
297 | #endregion | |
|
298 | ||
|
299 | #region ICancellable implementation | |
|
300 | ||
|
301 | public void Cancel(Exception reason) { | |
|
302 | if (m_cancelled != null) { | |
|
303 | try { | |
|
304 | m_cancelled(reason); | |
|
305 | m_deferred.Resolve(); | |
|
306 | } catch (Exception ex) { | |
|
307 | Reject(ex); | |
|
308 | } | |
|
309 | } else { | |
|
310 | m_deferred.Cancel(reason); | |
|
311 | } | |
|
312 | } | |
|
313 | ||
|
314 | public void Cancel() { | |
|
315 | Cancel(null); | |
|
316 | } | |
|
317 | ||
|
318 | #endregion | |
|
319 | } | |
|
320 | ||
|
321 | T m_result; | |
|
322 | ||
|
323 | 55 | public virtual void Resolve(T value) { |
|
324 |
|
|
|
325 | m_result = value; | |
|
326 | EndSetResult(); | |
|
327 | } | |
|
56 | SetResult(value); | |
|
328 | 57 | } |
|
329 | 58 | |
|
330 | 59 | public void Reject(Exception error) { |
|
331 | 60 | SetError(error); |
|
332 | 61 | } |
|
333 | ||
|
334 | public Type PromiseType { | |
|
335 | get { | |
|
336 | return typeof(T); | |
|
337 | } | |
|
338 | } | |
|
339 | ||
|
340 | public new T Join() { | |
|
341 | WaitResult(-1); | |
|
342 | return m_result; | |
|
343 | } | |
|
344 | public new T Join(int timeout) { | |
|
345 | WaitResult(timeout); | |
|
346 | return m_result; | |
|
347 | } | |
|
348 | ||
|
349 | public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) { | |
|
350 | AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance)); | |
|
351 | return this; | |
|
352 | } | |
|
353 | ||
|
354 | public IPromise<T> On(Action<T> success, Action<Exception> error) { | |
|
355 | AddHandler(new ValueEventDescriptor(success, error, null, StubDeferred.instance)); | |
|
356 | return this; | |
|
357 | } | |
|
358 | ||
|
359 | public IPromise<T> On(Action<T> success) { | |
|
360 | AddHandler(new ValueEventDescriptor(success, null, null, StubDeferred.instance)); | |
|
361 | return this; | |
|
362 | } | |
|
363 | ||
|
364 | public IPromise<T> On(Action handler, PromiseEventType events) { | |
|
365 | Listen(events, handler); | |
|
366 | return this; | |
|
367 | } | |
|
368 | ||
|
369 | public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel) { | |
|
370 | var promise = new Promise<T2>(); | |
|
371 | if (mapper != null) | |
|
372 | promise.On((Action)null, null, Cancel); | |
|
373 | AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise)); | |
|
374 | return promise; | |
|
375 | } | |
|
376 | ||
|
377 | public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) { | |
|
378 | var promise = new Promise<T2>(); | |
|
379 | if (mapper != null) | |
|
380 | promise.On((Action)null, null, Cancel); | |
|
381 | AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise)); | |
|
382 | return promise; | |
|
383 | } | |
|
384 | ||
|
385 | public IPromise<T2> Then<T2>(Func<T, T2> mapper) { | |
|
386 | var promise = new Promise<T2>(); | |
|
387 | if (mapper != null) | |
|
388 | promise.On((Action)null, null, Cancel); | |
|
389 | AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise)); | |
|
390 | return promise; | |
|
391 | } | |
|
392 | ||
|
393 | public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) { | |
|
394 | // this promise will be resolved when an asyc operation is started | |
|
395 | var promise = new Promise<IPromise<T2>>(); | |
|
396 | ||
|
397 | AddHandler(new RemapDescriptor<IPromise<T2>>( | |
|
398 | chained, | |
|
399 | error, | |
|
400 | cancel, | |
|
401 | promise | |
|
402 | )); | |
|
403 | ||
|
404 | var medium = new Promise<T2>(); | |
|
405 | ||
|
406 | if (chained != null) | |
|
407 | medium.On(Cancel, PromiseEventType.Cancelled); | |
|
408 | ||
|
409 | // we need to connect started async operation with the medium | |
|
410 | // if the async operation hasn't been started by the some reason | |
|
411 | // report is to the medium | |
|
412 | promise.On( | |
|
413 | result => ConnectPromise<T2>(result, medium), | |
|
414 | medium.Reject, | |
|
415 | medium.Cancel | |
|
416 | ); | |
|
417 | ||
|
418 | return medium; | |
|
419 | } | |
|
420 | ||
|
421 | static void ConnectPromise<T2>(IPromise<T2> result, Promise<T2> medium) { | |
|
422 | if (result != null) { | |
|
423 | result.On( | |
|
424 | medium.Resolve, | |
|
425 | medium.Reject, | |
|
426 | medium.Cancel | |
|
427 | ); | |
|
428 | medium.On(result.Cancel, PromiseEventType.Cancelled); | |
|
429 | } else { | |
|
430 | medium.Reject( | |
|
431 | new NullReferenceException( | |
|
432 | "The chained asynchronous operation returned" + | |
|
433 | " 'null' where the promise instance is expected" | |
|
434 | ) | |
|
435 | ); | |
|
436 | 62 | } |
|
437 | 63 | } |
|
438 | ||
|
439 | public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error) { | |
|
440 | return Chain(chained, error, null); | |
|
441 | } | |
|
442 | ||
|
443 | public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained) { | |
|
444 | return Chain(chained, null, null); | |
|
445 | } | |
|
446 | ||
|
447 | public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
448 | var promise = new Promise(); | |
|
449 | if (success != null) | |
|
450 | promise.On(null, null, Cancel); | |
|
451 | ||
|
452 | AddHandler(new EventDescriptor(success, error, cancel, promise)); | |
|
453 | ||
|
454 | return promise; | |
|
455 | } | |
|
456 | ||
|
457 | public IPromise Then(Action success, Action<Exception> error) { | |
|
458 | return Then(success, error, null); | |
|
459 | } | |
|
460 | ||
|
461 | public IPromise Then(Action success) { | |
|
462 | return Then(success, null, null); | |
|
463 | } | |
|
464 | ||
|
465 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) { | |
|
466 | var promise = new Promise<IPromise>(); | |
|
467 | ||
|
468 | AddHandler( | |
|
469 | new RemapDescriptor<IPromise>( | |
|
470 | x => chained(), | |
|
471 | error, | |
|
472 | cancel, | |
|
473 | promise | |
|
474 | ) | |
|
475 | ); | |
|
476 | ||
|
477 | var medium = new Promise(); | |
|
478 | if (chained != null) | |
|
479 | medium.On(null, null, Cancel); | |
|
480 | ||
|
481 | promise.On( | |
|
482 | result => ConnectPromise(result, medium), | |
|
483 | medium.Reject, | |
|
484 | medium.Cancel | |
|
485 | ); | |
|
486 | ||
|
487 | return medium; | |
|
488 | } | |
|
489 | ||
|
490 | static void ConnectPromise(IPromise result, Promise medium) { | |
|
491 | if (result != null) { | |
|
492 | result.On( | |
|
493 | medium.Resolve, | |
|
494 | medium.Reject, | |
|
495 | medium.Cancel | |
|
496 | ); | |
|
497 | medium.On(null, null, result.Cancel); | |
|
498 | } else { | |
|
499 | medium.Reject( | |
|
500 | new NullReferenceException( | |
|
501 | "The chained asynchronous operation returned" + | |
|
502 | " 'null' where the promise instance is expected" | |
|
503 | ) | |
|
504 | ); | |
|
505 | } | |
|
506 | } | |
|
507 | ||
|
508 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) { | |
|
509 | return Chain(chained, error, null); | |
|
510 | } | |
|
511 | ||
|
512 | public IPromise Chain(Func<IPromise> chained) { | |
|
513 | return Chain(chained, null, null); | |
|
514 | } | |
|
515 | ||
|
516 | public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
517 | AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance)); | |
|
518 | return this; | |
|
519 | } | |
|
520 | ||
|
521 | public IPromise On(Action success, Action<Exception> error) { | |
|
522 | AddHandler(new EventDescriptor(success, error, null, StubDeferred.instance)); | |
|
523 | return this; | |
|
524 | } | |
|
525 | ||
|
526 | public IPromise On(Action success) { | |
|
527 | Listen(PromiseEventType.Success, success); | |
|
528 | return this; | |
|
529 | } | |
|
530 | ||
|
531 | IPromise IPromise.On(Action handler, PromiseEventType events) { | |
|
532 | Listen(events,handler); | |
|
533 | return this; | |
|
534 | } | |
|
535 | ||
|
536 | public IPromise<T2> Cast<T2>() { | |
|
537 | return (IPromise<T2>)this; | |
|
538 | } | |
|
539 | ||
|
540 | #region implemented abstract members of AbstractPromise | |
|
541 | ||
|
542 | protected override void SignalSuccess(IDeferred<T> handler) { | |
|
543 | handler.Resolve(m_result); | |
|
544 | } | |
|
545 | ||
|
546 | protected override void SignalError(IDeferred<T> handler, Exception error) { | |
|
547 | handler.Reject(error); | |
|
548 | } | |
|
549 | ||
|
550 | protected override void SignalCancelled(IDeferred<T> handler, Exception reason) { | |
|
551 | handler.Cancel(reason); | |
|
552 | } | |
|
553 | ||
|
554 | protected override void Listen(PromiseEventType events, Action handler) { | |
|
555 | if (handler != null) | |
|
556 | AddHandler(new ListenerDescriptor(handler, events)); | |
|
557 | } | |
|
558 | ||
|
559 | #endregion | |
|
560 | ||
|
561 | public static IPromise<T> ResultToPromise(T value) { | |
|
562 | var p = new Promise<T>(); | |
|
563 | p.Resolve(value); | |
|
564 | return p; | |
|
565 | } | |
|
566 | ||
|
567 | public static IPromise<T> ExceptionToPromise(Exception error) { | |
|
568 | var p = new Promise<T>(); | |
|
569 | p.Reject(error); | |
|
570 | return p; | |
|
571 | } | |
|
572 | ||
|
573 | } | |
|
574 | } |
General Comments 0
You need to be logged in to leave comments.
Login now