Mercurial > pub > ImplabNet
comparison Implab/AbstractPromise.cs @ 244:eee3e49dd1ff v3
working on promises
| author | cin |
|---|---|
| date | Thu, 25 Jan 2018 19:09:16 +0300 |
| parents | b1e0ffdf3451 |
| children | fb70574741a1 |
comparison
equal
deleted
inserted
replaced
| 243:b1e0ffdf3451 | 244:eee3e49dd1ff |
|---|---|
| 2 using System.Diagnostics; | 2 using System.Diagnostics; |
| 3 using System.Reflection; | 3 using System.Reflection; |
| 4 using Implab.Parallels; | 4 using Implab.Parallels; |
| 5 | 5 |
| 6 namespace Implab { | 6 namespace Implab { |
| 7 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | 7 public class AbstractPromise : AbstractEvent<IResolvable>, IPromise { |
| 8 public class HandlerDescriptor { | |
| 9 readonly Action m_resolve; | |
| 10 readonly Action<Exception> m_reject; | |
| 11 | 8 |
| 12 readonly IDeferred m_deferred; | 9 class ResolvableSignal : IResolvable { |
| 13 public HandlerDescriptor(Action success, Action<Exception> error) { | 10 public Signal Signal { get; private set; } |
| 14 m_resolve = success; | 11 public ResolvableSignal() { |
| 15 m_reject = error; | 12 Signal = new Signal(); |
| 16 } | 13 } |
| 17 | 14 |
| 18 public void SignalSuccess() { | 15 |
| 19 try { | 16 public void Reject(Exception error) { |
| 20 if (m_resolve != null) | 17 Signal.Set(); |
| 21 m_resolve(); | |
| 22 m_deferred.Resolve(); | |
| 23 } catch (Exception ex) { | |
| 24 m_deferred.Reject(ex); | |
| 25 } | |
| 26 } | 18 } |
| 27 | 19 |
| 28 public void SignalError(Exception err) { | 20 public void Resolve() { |
| 29 if (m_reject != null) { | 21 Signal.Set(); |
| 30 try { | |
| 31 m_reject(err); | |
| 32 m_deferred.Resolve(); | |
| 33 } catch (Exception ex) { | |
| 34 m_deferred.Reject(ex); | |
| 35 } | |
| 36 } | |
| 37 } | 22 } |
| 38 } | 23 } |
| 39 | 24 |
| 40 PromiseState m_state; | 25 PromiseState m_state; |
| 41 | 26 |
| 45 get { | 30 get { |
| 46 return m_state == PromiseState.Rejected; | 31 return m_state == PromiseState.Rejected; |
| 47 } | 32 } |
| 48 } | 33 } |
| 49 | 34 |
| 50 public bool IsResolved { | 35 public bool IsFulfilled { |
| 51 get { | 36 get { |
| 52 return m_state == PromiseState.Resolved; | 37 return m_state == PromiseState.Fulfilled; |
| 53 } | 38 } |
| 54 } | 39 } |
| 55 | 40 |
| 56 public Exception RejectReason { | 41 public Exception RejectReason { |
| 57 get { | 42 get { |
| 58 return m_error; | 43 return m_error; |
| 59 } | 44 } |
| 60 } | 45 } |
| 61 | 46 |
| 62 | 47 |
| 48 internal void Resolve() { | |
| 49 if (BeginTransit()) | |
| 50 CompleteResolve(); | |
| 51 } | |
| 52 | |
| 53 internal void Reject(Exception reason) { | |
| 54 if (BeginTransit()) { | |
| 55 m_error = reason; | |
| 56 m_state = PromiseState.Rejected; | |
| 57 CompleteTransit(); | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 | |
| 63 #region implemented abstract members of AbstractPromise | 62 #region implemented abstract members of AbstractPromise |
| 64 | 63 |
| 65 protected override void SignalHandler(HandlerDescriptor handler) { | 64 protected override void SignalHandler(IResolvable handler) { |
| 66 switch (m_state) { | 65 switch (m_state) { |
| 67 case PromiseState.Resolved: | 66 case PromiseState.Fulfilled: |
| 68 handler.SignalSuccess(); | 67 handler.Resolve(); |
| 69 break; | 68 break; |
| 70 case PromiseState.Rejected: | 69 case PromiseState.Rejected: |
| 71 handler.SignalError(RejectReason); | 70 handler.Reject(RejectReason); |
| 72 break; | 71 break; |
| 73 default: | 72 default: |
| 74 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); | 73 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); |
| 75 } | 74 } |
| 76 } | 75 } |
| 77 | 76 |
| 78 protected override Signal GetFulfillSignal() { | 77 protected override Signal GetFulfillSignal() { |
| 79 var signal = new Signal(); | 78 var next = new ResolvableSignal(); |
| 80 On(signal.Set, e => signal.Set()); | 79 Then(next); |
| 81 return signal; | 80 return next.Signal; |
| 82 } | 81 } |
| 83 | 82 |
| 84 #endregion | 83 #endregion |
| 85 | 84 |
| 86 protected void CompleteResolve() { | 85 protected void CompleteResolve() { |
| 87 m_state = PromiseState.Resolved; | 86 m_state = PromiseState.Fulfilled; |
| 88 CompleteTransit(); | 87 CompleteTransit(); |
| 89 } | 88 } |
| 90 | 89 |
| 91 public Type ResultType { | 90 public Type ResultType { |
| 92 get { | 91 get { |
| 93 return typeof(void); | 92 return typeof(void); |
| 94 } | 93 } |
| 95 } | 94 } |
| 96 | 95 |
| 97 /// <summary> | |
| 98 /// Выполняет обещание, сообщая об ошибке | |
| 99 /// </summary> | |
| 100 /// <remarks> | |
| 101 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков | |
| 102 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные | |
| 103 /// будут проигнорированы. | |
| 104 /// </remarks> | |
| 105 /// <param name="error">Исключение возникшее при выполнении операции</param> | |
| 106 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> | |
| 107 protected void SetError(Exception error) { | |
| 108 if (BeginTransit()) { | |
| 109 m_error = error; | |
| 110 m_state = PromiseState.Rejected; | |
| 111 CompleteTransit(); | |
| 112 } else { | |
| 113 WaitTransition(); | |
| 114 if (m_state == PromiseState.Resolved) | |
| 115 throw new InvalidOperationException("The promise is already resolved"); | |
| 116 } | |
| 117 } | |
| 118 | 96 |
| 119 protected void Rethrow() { | 97 protected void Rethrow() { |
| 120 Debug.Assert(m_error != null); | 98 Debug.Assert(m_error != null); |
| 121 if (m_error is OperationCanceledException) | 99 if (m_error is OperationCanceledException) |
| 122 throw new OperationCanceledException("Operation cancelled", m_error); | 100 throw new OperationCanceledException("Operation cancelled", m_error); |
| 123 else | 101 else |
| 124 throw new TargetInvocationException(m_error); | 102 throw new TargetInvocationException(m_error); |
| 125 } | 103 } |
| 126 | 104 |
| 127 public void On(Action success, Action<Exception> error) { | 105 public void Then(IResolvable next) { |
| 128 AddHandler(new HandlerDescriptor(success, error)); | 106 AddHandler(next); |
| 129 } | 107 } |
| 130 | 108 |
| 131 public IPromise<T> Cast<T>() { | 109 public IPromise<T> Cast<T>() { |
| 132 throw new InvalidCastException(); | 110 throw new InvalidCastException(); |
| 133 } | 111 } |
