Mercurial > pub > ImplabNet
comparison Implab/Promise.cs @ 106:d4e38929ce36 v2
promises refactoring
author | cin |
---|---|
date | Mon, 10 Nov 2014 18:00:28 +0300 |
parents | 4d308952fd5e |
children | f5220e5472ef |
comparison
equal
deleted
inserted
replaced
105:4d308952fd5e | 106:d4e38929ce36 |
---|---|
40 /// только инициатор обещания иначе могут возникнуть противоречия. | 40 /// только инициатор обещания иначе могут возникнуть противоречия. |
41 /// </para> | 41 /// </para> |
42 /// </remarks> | 42 /// </remarks> |
43 public class Promise<T> : IPromise<T> { | 43 public class Promise<T> : IPromise<T> { |
44 | 44 |
45 protected struct HandlerDescriptor { | 45 protected abstract class AbstractHandler : MTCustomQueueNode<AbstractHandler> { |
46 public Action<T> resultHandler; | 46 public abstract void Resolve(T result); |
47 public Func<Exception,T> errorHandler; | 47 public abstract void Reject(Exception error); |
48 public Action cancellHandler; | 48 public abstract void Cancel(); |
49 public Promise<T> medium; | 49 } |
50 | 50 |
51 public void Resolve(T result) { | 51 protected class HandlerDescriptor<T2> : AbstractHandler { |
52 if (resultHandler != null) { | 52 |
53 readonly Func<T,T2> m_resultHandler; | |
54 readonly Func<Exception,T2> m_errorHandler; | |
55 readonly Action m_cancellHandler; | |
56 readonly Promise<T2> m_medium; | |
57 | |
58 public HandlerDescriptor(Func<T,T2> resultHandler, Func<Exception,T2> errorHandler, Action cancelHandler, Promise<T2> medium) { | |
59 m_resultHandler = resultHandler; | |
60 m_errorHandler = errorHandler; | |
61 m_cancellHandler = cancelHandler; | |
62 m_medium = medium; | |
63 } | |
64 | |
65 public override void Resolve(T result) { | |
66 if (m_resultHandler != null) { | |
53 try { | 67 try { |
54 resultHandler(result); | 68 if (m_medium != null) |
69 m_medium.Resolve(m_resultHandler(result)); | |
70 else | |
71 m_resultHandler(result); | |
55 } catch (Exception e) { | 72 } catch (Exception e) { |
56 Reject(e); | 73 Reject(e); |
57 return; | |
58 } | 74 } |
59 } | 75 } else if(m_medium != null) |
60 if (medium != null) | 76 m_medium.Resolve(default(T2)); |
61 medium.Resolve(result); | 77 } |
62 } | 78 |
63 | 79 public override void Reject(Exception error) { |
64 public void Reject(Exception err) { | 80 if (m_errorHandler != null) { |
65 if (errorHandler != null) { | |
66 try { | 81 try { |
67 var res = errorHandler(err); | 82 var res = m_errorHandler(error); |
68 if (medium != null) | 83 if (m_medium != null) |
69 medium.Resolve(res); | 84 m_medium.Resolve(res); |
70 /*} catch (TransientPromiseException err2) { | 85 /*} catch (TransientPromiseException err2) { |
71 if (medium != null) | 86 if (medium != null) |
72 medium.Reject(err2.InnerException);*/ | 87 medium.Reject(err2.InnerException);*/ |
73 } catch (Exception err2) { | 88 } catch (Exception err2) { |
74 if (medium != null) | 89 if (m_medium != null) |
75 medium.Reject(err2); | 90 m_medium.Reject(err2); |
76 } | 91 } |
77 } else if (medium != null) | 92 } else if (m_medium != null) |
78 medium.Reject(err); | 93 m_medium.Reject(error); |
79 } | 94 } |
80 | 95 |
81 public void Cancel() { | 96 public override void Cancel() { |
82 if (cancellHandler != null) { | 97 if (m_cancellHandler != null) { |
83 try { | 98 try { |
84 cancellHandler(); | 99 m_cancellHandler(); |
85 } catch (Exception err) { | 100 } catch (Exception err) { |
86 Reject(err); | 101 Reject(err); |
87 return; | 102 return; |
88 } | 103 } |
89 } | 104 } |
90 if (medium != null) | 105 if (m_medium != null) |
91 medium.Cancel(); | 106 m_medium.Cancel(); |
92 } | 107 } |
93 } | 108 } |
94 | 109 |
95 const int UNRESOLVED_SATE = 0; | 110 const int UNRESOLVED_SATE = 0; |
96 const int TRANSITIONAL_STATE = 1; | 111 const int TRANSITIONAL_STATE = 1; |
101 int m_childrenCount; | 116 int m_childrenCount; |
102 int m_state; | 117 int m_state; |
103 T m_result; | 118 T m_result; |
104 Exception m_error; | 119 Exception m_error; |
105 | 120 |
106 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>(); | 121 readonly MTCustomQueue<AbstractHandler> m_handlers = new MTCustomQueue<AbstractHandler>(); |
122 //readonly MTQueue<AbstractHandler> m_handlers = new MTQueue<AbstractHandler>(); | |
107 | 123 |
108 public Promise() { | 124 public Promise() { |
109 } | 125 } |
110 | 126 |
111 public Promise(IPromise parent) { | 127 public Promise(IPromise parent) { |
112 if (parent != null) | 128 if (parent != null) |
113 AddHandler( | 129 AddHandler<T>( |
114 null, | 130 null, |
115 null, | 131 null, |
116 () => { | 132 () => { |
117 if (parent.IsExclusive) | 133 if (parent.IsExclusive) |
118 parent.Cancel(); | 134 parent.Cancel(); |
211 public void Cancel() { | 227 public void Cancel() { |
212 if (BeginTransit()) { | 228 if (BeginTransit()) { |
213 CompleteTransit(CANCELLED_STATE); | 229 CompleteTransit(CANCELLED_STATE); |
214 OnStateChanged(); | 230 OnStateChanged(); |
215 } | 231 } |
216 } | |
217 | |
218 public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) { | |
219 if (success == null && error == null && cancel == null) | |
220 return this; | |
221 | |
222 var medium = new Promise<T>(this); | |
223 | |
224 AddHandler(success, error, cancel, medium, true); | |
225 | |
226 return medium; | |
227 } | |
228 | |
229 /// <summary> | |
230 /// Adds new handlers to this promise. | |
231 /// </summary> | |
232 /// <param name="success">The handler of the successfully completed operation. | |
233 /// This handler will recieve an operation result as a parameter.</param> | |
234 /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param> | |
235 /// <returns>The new promise chained to this one.</returns> | |
236 public IPromise<T> Then(Action<T> success, Func<Exception,T> error) { | |
237 if (success == null && error == null) | |
238 return this; | |
239 | |
240 var medium = new Promise<T>(this); | |
241 | |
242 AddHandler(success, error, null, medium, true); | |
243 | |
244 return medium; | |
245 } | |
246 | |
247 | |
248 | |
249 | |
250 public IPromise<T> Then(Action<T> success) { | |
251 if (success == null) | |
252 return this; | |
253 | |
254 var medium = new Promise<T>(this); | |
255 | |
256 AddHandler(success, null, null, medium, true); | |
257 | |
258 return medium; | |
259 } | 232 } |
260 | 233 |
261 /// <summary> | 234 /// <summary> |
262 /// Последний обработчик в цепочки обещаний. | 235 /// Последний обработчик в цепочки обещаний. |
263 /// </summary> | 236 /// </summary> |
277 /// </remarks> | 250 /// </remarks> |
278 public void On(Action<T> success, Action<Exception> error, Action cancel) { | 251 public void On(Action<T> success, Action<Exception> error, Action cancel) { |
279 if (success == null && error == null && cancel == null) | 252 if (success == null && error == null && cancel == null) |
280 return; | 253 return; |
281 | 254 |
282 Func<Exception,T> errorHandler = null; | 255 AddHandler( |
283 if (error != null) | 256 success != null ? new Func<T,T>(x => { |
284 errorHandler = err => { | 257 success(x); |
285 error(err); | 258 return x; |
286 return default(T); | 259 }) : null, |
287 }; | 260 error != null ? new Func<Exception,T>(e => { |
288 AddHandler(success, errorHandler, cancel, null, false); | 261 error(e); |
262 return default(T); | |
263 }) : null, | |
264 cancel, | |
265 null, | |
266 false | |
267 ); | |
289 } | 268 } |
290 | 269 |
291 public void On(Action<T> success, Action<Exception> error) { | 270 public void On(Action<T> success, Action<Exception> error) { |
292 On(success, error, null); | 271 On(success, error, null); |
293 } | 272 } |
297 } | 276 } |
298 | 277 |
299 public void On(Action handler, PromiseEventType events) { | 278 public void On(Action handler, PromiseEventType events) { |
300 Safe.ArgumentNotNull(handler, "handler"); | 279 Safe.ArgumentNotNull(handler, "handler"); |
301 | 280 |
302 Action<T> success = events.HasFlag(PromiseEventType.Success) ? new Action<T>(x => handler()) : null; | 281 Func<T,T> success = events.HasFlag(PromiseEventType.Success) ? new Func<T,T>(x => { |
282 handler(); | |
283 return x; | |
284 }) : null; | |
303 Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => { | 285 Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => { |
304 handler(); | 286 handler(); |
305 return default(T); | 287 return default(T); |
306 }) : null; | 288 }) : null; |
307 Action cancel = events.HasFlag(PromiseEventType.Cancelled) ? handler : null; | 289 Action cancel = events.HasFlag(PromiseEventType.Cancelled) ? handler : null; |
361 Safe.ArgumentNotNull(mapper, "mapper"); | 343 Safe.ArgumentNotNull(mapper, "mapper"); |
362 | 344 |
363 // создаем прицепленное обещание | 345 // создаем прицепленное обещание |
364 var medium = new Promise<TNew>(this); | 346 var medium = new Promise<TNew>(this); |
365 | 347 |
366 Action<T> resultHandler = result => medium.Resolve(mapper(result)); | |
367 Func<Exception,T> errorHandler; | |
368 if (error != null) | |
369 errorHandler = e => { | |
370 try { | |
371 medium.Resolve(error(e)); | |
372 } catch (Exception e2) { | |
373 // в случае ошибки нужно передать исключение дальше по цепочке | |
374 medium.Reject(e2); | |
375 } | |
376 return default(T); | |
377 }; | |
378 else | |
379 errorHandler = e => { | |
380 medium.Reject(e); | |
381 return default(T); | |
382 }; | |
383 | |
384 Action cancelHandler; | |
385 if (cancel != null) | |
386 cancelHandler = () => { | |
387 cancel(); | |
388 medium.Cancel(); | |
389 }; | |
390 else | |
391 cancelHandler = medium.Cancel; | |
392 | |
393 | |
394 AddHandler( | 348 AddHandler( |
395 resultHandler, | 349 mapper, |
396 errorHandler, | 350 error, |
397 cancelHandler, | 351 cancel, |
398 null, | 352 medium, |
399 true | 353 true |
400 ); | 354 ); |
401 | 355 |
402 return medium; | 356 return medium; |
403 } | 357 } |
429 // создать посредника, к которому будут подвызяваться следующие обработчики. | 383 // создать посредника, к которому будут подвызяваться следующие обработчики. |
430 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы | 384 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы |
431 // передать через него результаты работы. | 385 // передать через него результаты работы. |
432 var medium = new Promise<TNew>(this); | 386 var medium = new Promise<TNew>(this); |
433 | 387 |
434 Action<T> resultHandler = delegate(T result) { | 388 Func<T,T> resultHandler = delegate(T result) { |
435 if (medium.IsCancelled) | 389 if (medium.IsCancelled) |
436 return; | 390 return default(T); |
437 | 391 |
438 var promise = chained(result); | 392 var promise = chained(result); |
439 | 393 |
440 promise.On( | 394 promise.On( |
441 medium.Resolve, | 395 medium.Resolve, |
452 () => { | 406 () => { |
453 if (promise.IsExclusive) | 407 if (promise.IsExclusive) |
454 promise.Cancel(); | 408 promise.Cancel(); |
455 } | 409 } |
456 ); | 410 ); |
411 | |
412 return default(T); | |
457 }; | 413 }; |
458 | 414 |
459 Func<Exception,T> errorHandler; | 415 Func<Exception,T> errorHandler; |
460 | 416 |
461 if (error != null) | 417 if (error != null) |
532 Safe.ArgumentNotNull(handler, "handler"); | 488 Safe.ArgumentNotNull(handler, "handler"); |
533 | 489 |
534 var medium = new Promise<T>(this); | 490 var medium = new Promise<T>(this); |
535 | 491 |
536 AddHandler( | 492 AddHandler( |
537 x => handler(), | 493 x => { |
494 handler(); | |
495 return x; | |
496 }, | |
538 e => { | 497 e => { |
539 handler(); | 498 handler(); |
540 throw new TransientPromiseException(e); | 499 throw new TransientPromiseException(e); |
541 }, | 500 }, |
542 handler, | 501 handler, |
598 | 557 |
599 public T Join() { | 558 public T Join() { |
600 return Join(Timeout.Infinite); | 559 return Join(Timeout.Infinite); |
601 } | 560 } |
602 | 561 |
603 void AddHandler(Action<T> success, Func<Exception,T> error, Action cancel, Promise<T> medium, bool inc) { | 562 void AddHandler<T2>(Func<T,T2> success, Func<Exception,T2> error, Action cancel, Promise<T2> medium, bool inc) { |
604 if (inc) | 563 if (inc) |
605 Interlocked.Increment(ref m_childrenCount); | 564 Interlocked.Increment(ref m_childrenCount); |
606 | 565 |
607 var handler = new HandlerDescriptor { | 566 AbstractHandler handler = new HandlerDescriptor<T2>(success, error, cancel, medium); |
608 resultHandler = success, | |
609 errorHandler = error, | |
610 cancellHandler = cancel, | |
611 medium = medium | |
612 }; | |
613 | 567 |
614 bool queued; | 568 bool queued; |
615 | 569 |
616 if (!IsResolved) { | 570 if (!IsResolved) { |
617 m_handlers.Enqueue(handler); | 571 m_handlers.Enqueue(handler); |
629 // note that fetched handler may be not the one that we have added | 583 // note that fetched handler may be not the one that we have added |
630 // even we can fetch no handlers at all :) | 584 // even we can fetch no handlers at all :) |
631 InvokeHandler(handler); | 585 InvokeHandler(handler); |
632 } | 586 } |
633 | 587 |
634 protected virtual void InvokeHandler(HandlerDescriptor handler) { | 588 protected virtual void InvokeHandler(AbstractHandler handler) { |
635 switch (m_state) { | 589 switch (m_state) { |
636 case SUCCEEDED_STATE: | 590 case SUCCEEDED_STATE: |
637 handler.Resolve(m_result); | 591 handler.Resolve(m_result); |
638 break; | 592 break; |
639 case REJECTED_STATE: | 593 case REJECTED_STATE: |
647 return; | 601 return; |
648 } | 602 } |
649 } | 603 } |
650 | 604 |
651 void OnStateChanged() { | 605 void OnStateChanged() { |
652 HandlerDescriptor handler; | 606 AbstractHandler handler; |
653 while (m_handlers.TryDequeue(out handler)) | 607 while (m_handlers.TryDequeue(out handler)) |
654 InvokeHandler(handler); | 608 InvokeHandler(handler); |
655 } | 609 } |
656 | 610 |
657 public bool IsExclusive { | 611 public bool IsExclusive { |
686 | 640 |
687 for (int i = 0; i < promises.Count; i++) { | 641 for (int i = 0; i < promises.Count; i++) { |
688 var dest = i; | 642 var dest = i; |
689 | 643 |
690 if (promises[i] != null) { | 644 if (promises[i] != null) { |
691 promises[i].Then( | 645 promises[i].On( |
692 x => { | 646 x => { |
693 result[dest] = x; | 647 result[dest] = x; |
694 if (Interlocked.Decrement(ref pending) == 0) | 648 if (Interlocked.Decrement(ref pending) == 0) |
695 promise.Resolve(result); | 649 promise.Resolve(result); |
696 }, | 650 }, |
697 e => { | 651 promise.Reject |
698 promise.Reject(e); | |
699 return default(T); | |
700 } | |
701 ); | 652 ); |
702 } else { | 653 } else { |
703 if (Interlocked.Decrement(ref pending) == 0) | 654 if (Interlocked.Decrement(ref pending) == 0) |
704 promise.Resolve(result); | 655 promise.Resolve(result); |
705 } | 656 } |
774 | 725 |
775 #region IPromiseBase explicit implementation | 726 #region IPromiseBase explicit implementation |
776 | 727 |
777 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) { | 728 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) { |
778 return Then( | 729 return Then( |
779 success != null ? new Action<T>(x => success()) : null, | 730 success != null ? new Func<T,T>(x => { |
731 success(); | |
732 return x; | |
733 }) : null, | |
780 error != null ? new Func<Exception,T>(e => { | 734 error != null ? new Func<Exception,T>(e => { |
781 error(e); | 735 error(e); |
782 return default(T); | 736 return default(T); |
783 }) : null, | 737 }) : null, |
784 cancel | 738 cancel |
785 ); | 739 ); |
786 } | 740 } |
787 | 741 |
788 IPromise IPromise.Then(Action success, Action<Exception> error) { | 742 IPromise IPromise.Then(Action success, Action<Exception> error) { |
789 return Then( | 743 return Then( |
790 success != null ? new Action<T>(x => success()) : null, | 744 success != null ? new Func<T,T>(x => { |
745 success(); | |
746 return x; | |
747 }) : null, | |
791 error != null ? new Func<Exception,T>(e => { | 748 error != null ? new Func<Exception,T>(e => { |
792 error(e); | 749 error(e); |
793 return default(T); | 750 return default(T); |
794 }) : null | 751 }) : null |
795 ); | 752 ); |
796 } | 753 } |
797 | 754 |
798 IPromise IPromise.Then(Action success) { | 755 IPromise IPromise.Then(Action success) { |
799 Safe.ArgumentNotNull(success, "success"); | 756 Safe.ArgumentNotNull(success, "success"); |
800 return Then(x => success()); | 757 return Then(x => { |
758 success(); | |
759 return x; | |
760 }); | |
801 } | 761 } |
802 | 762 |
803 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { | 763 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { |
804 return ChainNoResult(chained, error, cancel); | 764 return ChainNoResult(chained, error, cancel); |
805 } | 765 } |
807 IPromise ChainNoResult(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { | 767 IPromise ChainNoResult(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { |
808 Safe.ArgumentNotNull(chained, "chained"); | 768 Safe.ArgumentNotNull(chained, "chained"); |
809 | 769 |
810 var medium = new Promise<object>(this); | 770 var medium = new Promise<object>(this); |
811 | 771 |
812 Action<T> resultHandler = delegate { | 772 Func<T,T> resultHandler = delegate { |
813 if (medium.IsCancelled) | 773 if (medium.IsCancelled) |
814 return; | 774 return default(T); |
815 | 775 |
816 var promise = chained(); | 776 var promise = chained(); |
817 | 777 |
818 promise.On( | 778 promise.On( |
819 medium.Resolve, | 779 medium.Resolve, |
826 // зависит IsExclusive | 786 // зависит IsExclusive |
827 medium.Cancelled(() => { | 787 medium.Cancelled(() => { |
828 if (promise.IsExclusive) | 788 if (promise.IsExclusive) |
829 promise.Cancel(); | 789 promise.Cancel(); |
830 }); | 790 }); |
791 | |
792 return default(T); | |
831 }; | 793 }; |
832 | 794 |
833 Func<Exception,T> errorHandler; | 795 Func<Exception,T> errorHandler; |
834 | 796 |
835 if (error != null) | 797 if (error != null) |