Mercurial > pub > ImplabNet
comparison Implab/PromiseT.cs @ 144:8c0b95069066 v2
DRAFT: refactoring
author | cin |
---|---|
date | Fri, 06 Mar 2015 15:45:26 +0300 |
parents | f75cfa58e3d4 |
children | e03ccec4a08d |
comparison
equal
deleted
inserted
replaced
143:16f926ee499d | 144:8c0b95069066 |
---|---|
1 using System; | 1 using System; |
2 using System.Diagnostics; | 2 using System.Diagnostics; |
3 using Implab.Parallels; | |
3 | 4 |
4 namespace Implab { | 5 namespace Implab { |
5 | 6 |
6 /// <summary> | 7 /// <summary> |
7 /// Класс для асинхронного получения результатов. Так называемое "обещание". | 8 /// Класс для асинхронного получения результатов. Так называемое "обещание". |
35 /// <para> | 36 /// <para> |
36 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать | 37 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать |
37 /// только инициатор обещания иначе могут возникнуть противоречия. | 38 /// только инициатор обещания иначе могут возникнуть противоречия. |
38 /// </para> | 39 /// </para> |
39 /// </remarks> | 40 /// </remarks> |
40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> { | 41 public class Promise<T> : AbstractPromise<T>, IDeferred<T> { |
41 | 42 |
42 class StubDeferred : IDeferred, IDeferred<T> { | 43 public static IPromise<T> FromResult(T value) { |
43 public static readonly StubDeferred instance = new StubDeferred(); | 44 var p = new Promise<T>(); |
44 | 45 p.Resolve(value); |
45 StubDeferred() { | 46 return p; |
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 } | 47 } |
73 | 48 |
74 class RemapDescriptor<T2> : IDeferred<T> { | 49 public static IPromise<T> FromException(Exception error) { |
75 readonly Func<T,T2> m_remap; | 50 var p = new Promise<T>(); |
76 readonly Func<Exception, T2> m_failed; | 51 p.Reject(error); |
77 readonly Func<Exception, T2> m_cancel; | 52 return p; |
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 } | |
101 | |
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 } | 53 } |
136 | 54 |
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); | |
176 } | |
177 | |
178 public void Cancel(Exception reason) { | |
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); | |
251 } | |
252 | |
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 public virtual void Resolve(T value) { | 55 public virtual void Resolve(T value) { |
324 if (BeginSetResult()) { | 56 SetResult(value); |
325 m_result = value; | |
326 EndSetResult(); | |
327 } | |
328 } | 57 } |
329 | 58 |
330 public void Reject(Exception error) { | 59 public void Reject(Exception error) { |
331 SetError(error); | 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 } | |
437 } | |
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 } | 62 } |
574 } | 63 } |