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 |