Mercurial > pub > ImplabNet
annotate Implab/AbstractPromise.cs @ 243:b1e0ffdf3451 v3
working on promises
| author | cin |
|---|---|
| date | Wed, 24 Jan 2018 19:24:10 +0300 |
| parents | cbe10ac0731e |
| children | eee3e49dd1ff |
| rev | line source |
|---|---|
| 119 | 1 using System; |
| 243 | 2 using System.Diagnostics; |
| 3 using System.Reflection; | |
| 119 | 4 using Implab.Parallels; |
| 5 | |
| 6 namespace Implab { | |
| 144 | 7 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { |
| 242 | 8 public class HandlerDescriptor { |
| 243 | 9 readonly Action m_resolve; |
| 10 readonly Action<Exception> m_reject; | |
| 11 | |
| 12 readonly IDeferred m_deferred; | |
| 242 | 13 public HandlerDescriptor(Action success, Action<Exception> error) { |
| 243 | 14 m_resolve = success; |
| 15 m_reject = error; | |
| 144 | 16 } |
| 119 | 17 |
| 144 | 18 public void SignalSuccess() { |
| 243 | 19 try { |
| 20 if (m_resolve != null) | |
| 21 m_resolve(); | |
| 22 m_deferred.Resolve(); | |
| 23 } catch (Exception ex) { | |
| 24 m_deferred.Reject(ex); | |
| 144 | 25 } |
| 26 } | |
| 119 | 27 |
| 144 | 28 public void SignalError(Exception err) { |
| 243 | 29 if (m_reject != null) { |
| 144 | 30 try { |
| 243 | 31 m_reject(err); |
| 32 m_deferred.Resolve(); | |
| 33 } catch (Exception ex) { | |
| 34 m_deferred.Reject(ex); | |
| 144 | 35 } |
| 36 } | |
| 119 | 37 } |
| 38 } | |
| 39 | |
| 243 | 40 PromiseState m_state; |
| 41 | |
| 42 Exception m_error; | |
| 43 | |
| 44 public bool IsRejected { | |
| 45 get { | |
| 46 return m_state == PromiseState.Rejected; | |
| 47 } | |
| 48 } | |
| 49 | |
| 50 public bool IsResolved { | |
| 51 get { | |
| 52 return m_state == PromiseState.Resolved; | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 public Exception RejectReason { | |
| 57 get { | |
| 58 return m_error; | |
| 59 } | |
| 60 } | |
| 61 | |
| 119 | 62 |
| 144 | 63 #region implemented abstract members of AbstractPromise |
| 119 | 64 |
| 243 | 65 protected override void SignalHandler(HandlerDescriptor handler) { |
| 66 switch (m_state) { | |
| 67 case PromiseState.Resolved: | |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
145
diff
changeset
|
68 handler.SignalSuccess(); |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
145
diff
changeset
|
69 break; |
| 243 | 70 case PromiseState.Rejected: |
| 242 | 71 handler.SignalError(RejectReason); |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
145
diff
changeset
|
72 break; |
|
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
145
diff
changeset
|
73 default: |
| 243 | 74 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); |
|
156
97fbbf816844
Promises: SignalXXX methods merged into SignalHandler method.
cin
parents:
145
diff
changeset
|
75 } |
| 119 | 76 } |
| 77 | |
| 242 | 78 protected override Signal GetFulfillSignal() { |
| 144 | 79 var signal = new Signal(); |
| 242 | 80 On(signal.Set, e => signal.Set()); |
| 145 | 81 return signal; |
| 119 | 82 } |
| 83 | |
| 84 #endregion | |
| 85 | |
| 243 | 86 protected void CompleteResolve() { |
| 87 m_state = PromiseState.Resolved; | |
| 88 CompleteTransit(); | |
| 89 } | |
| 90 | |
| 242 | 91 public Type ResultType { |
| 144 | 92 get { |
| 93 return typeof(void); | |
| 119 | 94 } |
| 95 } | |
| 96 | |
| 243 | 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 | |
| 119 protected void Rethrow() { | |
| 120 Debug.Assert(m_error != null); | |
| 121 if (m_error is OperationCanceledException) | |
| 122 throw new OperationCanceledException("Operation cancelled", m_error); | |
| 123 else | |
| 124 throw new TargetInvocationException(m_error); | |
| 125 } | |
| 126 | |
| 242 | 127 public void On(Action success, Action<Exception> error) { |
| 128 AddHandler(new HandlerDescriptor(success, error)); | |
| 144 | 129 } |
| 119 | 130 |
| 144 | 131 public IPromise<T> Cast<T>() { |
| 132 throw new InvalidCastException(); | |
| 119 | 133 } |
| 134 | |
| 135 public void Join() { | |
| 136 WaitResult(-1); | |
| 243 | 137 if (IsRejected) |
| 138 Rethrow(); | |
| 119 | 139 } |
| 140 | |
| 144 | 141 public void Join(int timeout) { |
| 142 WaitResult(timeout); | |
| 119 | 143 } |
| 144 } | |
| 145 } | |
| 146 |
