@@ -0,0 +1,350 | |||
|
1 | using System; | |
|
2 | using Implab.Parallels; | |
|
3 | using System.Threading; | |
|
4 | using System.Reflection; | |
|
5 | ||
|
6 | namespace Implab { | |
|
7 | public abstract class AbstractEvent<THandler> : ICancelationToken, ICancellable { | |
|
8 | ||
|
9 | const int UNRESOLVED_SATE = 0; | |
|
10 | const int TRANSITIONAL_STATE = 1; | |
|
11 | const int SUCCEEDED_STATE = 2; | |
|
12 | const int REJECTED_STATE = 3; | |
|
13 | const int CANCELLED_STATE = 4; | |
|
14 | ||
|
15 | const int CANCEL_NOT_REQUESTED = 0; | |
|
16 | const int CANCEL_REQUESTING = 1; | |
|
17 | const int CANCEL_REQUESTED = 2; | |
|
18 | ||
|
19 | const int RESERVED_HANDLERS_COUNT = 4; | |
|
20 | ||
|
21 | int m_state; | |
|
22 | Exception m_error; | |
|
23 | int m_handlersCount; | |
|
24 | ||
|
25 | readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; | |
|
26 | MTQueue<THandler> m_extraHandlers; | |
|
27 | int m_handlerPointer = -1; | |
|
28 | int m_handlersCommited; | |
|
29 | ||
|
30 | int m_cancelRequest; | |
|
31 | Exception m_cancelationReason; | |
|
32 | MTQueue<Action<Exception>> m_cancelationHandlers; | |
|
33 | ||
|
34 | ||
|
35 | #region state managment | |
|
36 | bool BeginTransit() { | |
|
37 | return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); | |
|
38 | } | |
|
39 | ||
|
40 | void CompleteTransit(int state) { | |
|
41 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) | |
|
42 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |
|
43 | } | |
|
44 | ||
|
45 | void WaitTransition() { | |
|
46 | while (m_state == TRANSITIONAL_STATE) { | |
|
47 | Thread.MemoryBarrier(); | |
|
48 | } | |
|
49 | } | |
|
50 | ||
|
51 | protected bool BeginSetResult() { | |
|
52 | if (!BeginTransit()) { | |
|
53 | WaitTransition(); | |
|
54 | if (m_state != CANCELLED_STATE) | |
|
55 | throw new InvalidOperationException("The promise is already resolved"); | |
|
56 | return false; | |
|
57 | } | |
|
58 | return true; | |
|
59 | } | |
|
60 | ||
|
61 | protected void EndSetResult() { | |
|
62 | CompleteTransit(SUCCEEDED_STATE); | |
|
63 | OnSuccess(); | |
|
64 | } | |
|
65 | ||
|
66 | ||
|
67 | ||
|
68 | /// <summary> | |
|
69 | /// ΠΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅, ΡΠΎΠΎΠ±ΡΠ°Ρ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅ | |
|
70 | /// </summary> | |
|
71 | /// <remarks> | |
|
72 | /// ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡΠΎΡΠ½ΠΎΠΉ ΡΡΠ΅Π΄Π΅, ΠΏΡΠΈ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠΎΠΊΠΎΠ² | |
|
73 | /// ΠΌΠΎΠ³Ρ Π²Π΅ΡΠ½ΡΡΡ ΠΎΡΠΈΠ±ΠΊΡ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ²Π°Ρ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ | |
|
74 | /// Π±ΡΠ΄ΡΡ ΠΏΡΠΎΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Ρ. | |
|
75 | /// </remarks> | |
|
76 | /// <param name="error">ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ</param> | |
|
77 | /// <exception cref="InvalidOperationException">ΠΠ°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠΆΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception> | |
|
78 | protected void SetError(Exception error) { | |
|
79 | if (BeginTransit()) { | |
|
80 | if (error is OperationCanceledException) { | |
|
81 | CompleteTransit(CANCELLED_STATE); | |
|
82 | m_error = error.InnerException; | |
|
83 | OnCancelled(); | |
|
84 | } else { | |
|
85 | m_error = error is PromiseTransientException ? error.InnerException : error; | |
|
86 | CompleteTransit(REJECTED_STATE); | |
|
87 | OnError(); | |
|
88 | } | |
|
89 | } else { | |
|
90 | WaitTransition(); | |
|
91 | if (m_state == SUCCEEDED_STATE) | |
|
92 | throw new InvalidOperationException("The promise is already resolved"); | |
|
93 | } | |
|
94 | } | |
|
95 | ||
|
96 | /// <summary> | |
|
97 | /// ΠΡΠΌΠ΅Π½ΡΠ΅Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ, Π΅ΡΠ»ΠΈ ΡΡΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. | |
|
98 | /// </summary> | |
|
99 | /// <remarks>ΠΠ»Ρ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π±ΡΠ»Π° Π»ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ ΠΎΡΠΌΠ΅Π½Π΅Π½Π° ΡΠ»Π΅Π΄ΡΠ΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠ²ΠΎΠΉΡΡΠ²ΠΎ <see cref="IsCancelled"/>.</remarks> | |
|
100 | protected void SetCancelled(Exception reason) { | |
|
101 | if (BeginTransit()) { | |
|
102 | m_error = reason; | |
|
103 | CompleteTransit(CANCELLED_STATE); | |
|
104 | OnCancelled(); | |
|
105 | } | |
|
106 | } | |
|
107 | ||
|
108 | protected abstract void SignalSuccess(THandler handler); | |
|
109 | ||
|
110 | protected abstract void SignalError(THandler handler, Exception error); | |
|
111 | ||
|
112 | protected abstract void SignalCancelled(THandler handler, Exception reason); | |
|
113 | ||
|
114 | void OnSuccess() { | |
|
115 | var hp = m_handlerPointer; | |
|
116 | var slot = hp +1 ; | |
|
117 | while (slot < m_handlersCommited) { | |
|
118 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
119 | SignalSuccess(m_handlers[slot]); | |
|
120 | } | |
|
121 | hp = m_handlerPointer; | |
|
122 | slot = hp +1 ; | |
|
123 | } | |
|
124 | ||
|
125 | ||
|
126 | if (m_extraHandlers != null) { | |
|
127 | THandler handler; | |
|
128 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
129 | SignalSuccess(handler); | |
|
130 | } | |
|
131 | } | |
|
132 | ||
|
133 | void OnError() { | |
|
134 | var hp = m_handlerPointer; | |
|
135 | var slot = hp +1 ; | |
|
136 | while (slot < m_handlersCommited) { | |
|
137 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
138 | SignalError(m_handlers[slot],m_error); | |
|
139 | } | |
|
140 | hp = m_handlerPointer; | |
|
141 | slot = hp +1 ; | |
|
142 | } | |
|
143 | ||
|
144 | if (m_extraHandlers != null) { | |
|
145 | THandler handler; | |
|
146 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
147 | SignalError(handler, m_error); | |
|
148 | } | |
|
149 | } | |
|
150 | ||
|
151 | void OnCancelled() { | |
|
152 | var hp = m_handlerPointer; | |
|
153 | var slot = hp +1 ; | |
|
154 | while (slot < m_handlersCommited) { | |
|
155 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
156 | SignalCancelled(m_handlers[slot], m_error); | |
|
157 | } | |
|
158 | hp = m_handlerPointer; | |
|
159 | slot = hp +1 ; | |
|
160 | } | |
|
161 | ||
|
162 | if (m_extraHandlers != null) { | |
|
163 | THandler handler; | |
|
164 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
165 | SignalCancelled(handler, m_error); | |
|
166 | } | |
|
167 | } | |
|
168 | ||
|
169 | #endregion | |
|
170 | ||
|
171 | protected abstract Signal GetResolveSignal(); | |
|
172 | ||
|
173 | #region synchronization traits | |
|
174 | protected void WaitResult(int timeout) { | |
|
175 | if (!IsResolved) | |
|
176 | GetResolveSignal().Wait(timeout); | |
|
177 | ||
|
178 | switch (m_state) { | |
|
179 | case SUCCEEDED_STATE: | |
|
180 | return; | |
|
181 | case CANCELLED_STATE: | |
|
182 | throw new OperationCanceledException(); | |
|
183 | case REJECTED_STATE: | |
|
184 | throw new TargetInvocationException(m_error); | |
|
185 | default: | |
|
186 | throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); | |
|
187 | } | |
|
188 | } | |
|
189 | #endregion | |
|
190 | ||
|
191 | #region handlers managment | |
|
192 | ||
|
193 | protected void AddHandler(THandler handler) { | |
|
194 | ||
|
195 | if (m_state > 1) { | |
|
196 | // the promise is in the resolved state, just invoke the handler | |
|
197 | InvokeHandler(handler); | |
|
198 | } else { | |
|
199 | var slot = Interlocked.Increment(ref m_handlersCount) - 1; | |
|
200 | ||
|
201 | if (slot < RESERVED_HANDLERS_COUNT) { | |
|
202 | ||
|
203 | m_handlers[slot] = handler; | |
|
204 | ||
|
205 | while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) { | |
|
206 | } | |
|
207 | ||
|
208 | if (m_state > 1) { | |
|
209 | do { | |
|
210 | var hp = m_handlerPointer; | |
|
211 | slot = hp + 1; | |
|
212 | if (slot < m_handlersCommited) { | |
|
213 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp) | |
|
214 | continue; | |
|
215 | InvokeHandler(m_handlers[slot]); | |
|
216 | } | |
|
217 | break; | |
|
218 | } while(true); | |
|
219 | } | |
|
220 | } else { | |
|
221 | if (slot == RESERVED_HANDLERS_COUNT) { | |
|
222 | m_extraHandlers = new MTQueue<THandler>(); | |
|
223 | } else { | |
|
224 | while (m_extraHandlers == null) | |
|
225 | Thread.MemoryBarrier(); | |
|
226 | } | |
|
227 | ||
|
228 | m_extraHandlers.Enqueue(handler); | |
|
229 | ||
|
230 | if (m_state > 1 && m_extraHandlers.TryDequeue(out handler)) | |
|
231 | // if the promise have been resolved while we was adding the handler to the queue | |
|
232 | // we can't guarantee that someone is still processing it | |
|
233 | // therefore we need to fetch a handler from the queue and execute it | |
|
234 | // note that fetched handler may be not the one that we have added | |
|
235 | // even we can fetch no handlers at all :) | |
|
236 | InvokeHandler(handler); | |
|
237 | } | |
|
238 | } | |
|
239 | } | |
|
240 | ||
|
241 | protected void InvokeHandler(THandler handler) { | |
|
242 | switch (m_state) { | |
|
243 | case SUCCEEDED_STATE: | |
|
244 | SignalSuccess(handler); | |
|
245 | break; | |
|
246 | case CANCELLED_STATE: | |
|
247 | SignalCancelled(handler, m_error); | |
|
248 | break; | |
|
249 | case REJECTED_STATE: | |
|
250 | SignalError(handler, m_error); | |
|
251 | break; | |
|
252 | default: | |
|
253 | throw new Exception(String.Format("Invalid promise state {0}", m_state)); | |
|
254 | } | |
|
255 | } | |
|
256 | ||
|
257 | #endregion | |
|
258 | ||
|
259 | #region IPromise implementation | |
|
260 | ||
|
261 | public bool IsResolved { | |
|
262 | get { | |
|
263 | Thread.MemoryBarrier(); | |
|
264 | return m_state > 1; | |
|
265 | } | |
|
266 | } | |
|
267 | ||
|
268 | public bool IsCancelled { | |
|
269 | get { | |
|
270 | Thread.MemoryBarrier(); | |
|
271 | return m_state == CANCELLED_STATE; | |
|
272 | } | |
|
273 | } | |
|
274 | ||
|
275 | #endregion | |
|
276 | ||
|
277 | public Exception Error { | |
|
278 | get { | |
|
279 | return m_error; | |
|
280 | } | |
|
281 | } | |
|
282 | ||
|
283 | public bool AcceptIfRequested() { | |
|
284 | if (IsCancelRequested) | |
|
285 | CancelOperation(CancelReason); | |
|
286 | } | |
|
287 | ||
|
288 | public virtual void CancelOperation(Exception reason) { | |
|
289 | SetCancelled(reason); | |
|
290 | } | |
|
291 | ||
|
292 | public void CancelationRequested(Action<Exception> handler) { | |
|
293 | Safe.ArgumentNotNull(handler, "handler"); | |
|
294 | if (IsCancelRequested) | |
|
295 | handler(CancelReason); | |
|
296 | ||
|
297 | if (m_cancelationHandlers == null) | |
|
298 | Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null); | |
|
299 | ||
|
300 | m_cancelationHandlers.Enqueue(handler); | |
|
301 | ||
|
302 | if (IsCancelRequested && m_cancelationHandlers.TryDequeue(out handler)) | |
|
303 | // TryDeque implies MemoryBarrier() | |
|
304 | handler(m_cancelationReason); | |
|
305 | } | |
|
306 | ||
|
307 | public bool IsCancelRequested { | |
|
308 | get { | |
|
309 | do { | |
|
310 | if (m_cancelRequest == CANCEL_NOT_REQUESTED) | |
|
311 | return false; | |
|
312 | if (m_cancelRequest == CANCEL_REQUESTED) | |
|
313 | return true; | |
|
314 | Thread.MemoryBarrier(); | |
|
315 | } while(true); | |
|
316 | } | |
|
317 | } | |
|
318 | ||
|
319 | public Exception CancelReason { | |
|
320 | get { | |
|
321 | do { | |
|
322 | Thread.MemoryBarrier(); | |
|
323 | } while(m_cancelRequest == CANCEL_REQUESTING); | |
|
324 | ||
|
325 | return m_cancelationReason; | |
|
326 | } | |
|
327 | } | |
|
328 | ||
|
329 | #region ICancellable implementation | |
|
330 | ||
|
331 | public void Cancel() { | |
|
332 | Cancel(null); | |
|
333 | } | |
|
334 | ||
|
335 | public void Cancel(Exception reason) { | |
|
336 | if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING)) { | |
|
337 | m_cancelationReason = reason; | |
|
338 | m_cancelRequest = CANCEL_REQUESTED; | |
|
339 | if (m_cancelationHandlers != null) { | |
|
340 | Action<Exception> handler; | |
|
341 | while (m_cancelationHandlers.TryDequeue(out handler)) | |
|
342 | handler(m_cancelationReason); | |
|
343 | } | |
|
344 | } | |
|
345 | } | |
|
346 | ||
|
347 | #endregion | |
|
348 | } | |
|
349 | } | |
|
350 |
@@ -0,0 +1,185 | |||
|
1 | using System; | |
|
2 | using Implab.Parallels; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public abstract class AbstractPromise<T> : AbstractEvent<AbstractPromise<T>.HandlerDescriptor>, IPromise<T> { | |
|
6 | public struct HandlerDescriptor { | |
|
7 | readonly Action m_handler; | |
|
8 | readonly Action<T> m_success; | |
|
9 | readonly Action<Exception> m_error; | |
|
10 | readonly Action<Exception> m_cancel; | |
|
11 | readonly PromiseEventType m_mask; | |
|
12 | ||
|
13 | public HandlerDescriptor(Action<T> success, Action<Exception> error, Action<Exception> cancel) { | |
|
14 | m_success = success; | |
|
15 | m_error = error; | |
|
16 | m_cancel = cancel; | |
|
17 | } | |
|
18 | ||
|
19 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
20 | m_handler = success; | |
|
21 | m_error = error; | |
|
22 | m_cancel = cancel; | |
|
23 | m_mask = PromiseEventType.Success; | |
|
24 | } | |
|
25 | ||
|
26 | public HandlerDescriptor(Action handler, PromiseEventType mask) { | |
|
27 | m_handler = handler; | |
|
28 | m_mask = mask; | |
|
29 | } | |
|
30 | ||
|
31 | public void SignalSuccess(T result) { | |
|
32 | if (m_success != null) { | |
|
33 | try { | |
|
34 | m_success(result); | |
|
35 | } catch(Exception err) { | |
|
36 | SignalError(err); | |
|
37 | } | |
|
38 | } else if (m_mask & PromiseEventType.Success && m_handler != null) { | |
|
39 | try { | |
|
40 | m_handler(); | |
|
41 | } catch(Exception err) { | |
|
42 | // avoid calling handler twice in case of error | |
|
43 | if (m_error != null) | |
|
44 | SignalError(err); | |
|
45 | } | |
|
46 | } | |
|
47 | } | |
|
48 | ||
|
49 | public void SignalError(Exception err) { | |
|
50 | if (m_error != null) { | |
|
51 | try { | |
|
52 | m_error(err); | |
|
53 | // Analysis disable once EmptyGeneralCatchClause | |
|
54 | } catch { | |
|
55 | } | |
|
56 | } else if (m_mask & PromiseEventType.Error && m_handler != null) { | |
|
57 | try { | |
|
58 | m_handler(); | |
|
59 | // Analysis disable once EmptyGeneralCatchClause | |
|
60 | } catch { | |
|
61 | } | |
|
62 | } | |
|
63 | } | |
|
64 | ||
|
65 | public void SignalCancel(Exception reason) { | |
|
66 | if (m_cancel != null) { | |
|
67 | try { | |
|
68 | m_cancel(reason); | |
|
69 | } catch (Exception err) { | |
|
70 | SignalError(err); | |
|
71 | } | |
|
72 | } else if (m_mask & PromiseEventType.Cancelled && m_handler != null) { | |
|
73 | try { | |
|
74 | m_handler(); | |
|
75 | // Analysis disable once EmptyGeneralCatchClause | |
|
76 | } catch { | |
|
77 | } | |
|
78 | } | |
|
79 | } | |
|
80 | } | |
|
81 | ||
|
82 | ||
|
83 | ||
|
84 | public Type PromiseType { | |
|
85 | get { | |
|
86 | return typeof(T); | |
|
87 | } | |
|
88 | } | |
|
89 | ||
|
90 | public new T Join() { | |
|
91 | WaitResult(-1); | |
|
92 | return m_result; | |
|
93 | } | |
|
94 | public new T Join(int timeout) { | |
|
95 | WaitResult(timeout); | |
|
96 | return m_result; | |
|
97 | } | |
|
98 | ||
|
99 | public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) { | |
|
100 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
101 | return this; | |
|
102 | } | |
|
103 | ||
|
104 | public IPromise<T> On(Action<T> success, Action<Exception> error) { | |
|
105 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
106 | return this; | |
|
107 | } | |
|
108 | ||
|
109 | public IPromise<T> On(Action<T> success) { | |
|
110 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
111 | return this; | |
|
112 | } | |
|
113 | ||
|
114 | public IPromise<T> On(Action handler, PromiseEventType events) { | |
|
115 | AddHandler(new HandlerDescriptor(handler, events)); | |
|
116 | return this; | |
|
117 | } | |
|
118 | ||
|
119 | public IPromise<T> On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
120 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
121 | return this; | |
|
122 | } | |
|
123 | ||
|
124 | public IPromise<T> On(Action success, Action<Exception> error) { | |
|
125 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
126 | return this; | |
|
127 | } | |
|
128 | ||
|
129 | public IPromise<T> On(Action success) { | |
|
130 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
131 | return this; | |
|
132 | } | |
|
133 | ||
|
134 | IPromise IPromise.On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
135 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
136 | return this; | |
|
137 | } | |
|
138 | ||
|
139 | IPromise IPromise.On(Action success, Action<Exception> error) { | |
|
140 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
141 | return this; | |
|
142 | } | |
|
143 | ||
|
144 | IPromise IPromise.On(Action success) { | |
|
145 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
146 | return this; | |
|
147 | } | |
|
148 | ||
|
149 | public IPromise<T2> Cast<T2>() { | |
|
150 | return (IPromise<T2>)this; | |
|
151 | } | |
|
152 | ||
|
153 | #region implemented abstract members of AbstractPromise | |
|
154 | ||
|
155 | protected override Signal GetResolveSignal() { | |
|
156 | var signal = new Signal(); | |
|
157 | AddHandler(new HandlerDescriptor(signal.Set, PromiseEventType.All)); | |
|
158 | return signal; | |
|
159 | } | |
|
160 | ||
|
161 | protected override void SignalSuccess(HandlerDescriptor handler) { | |
|
162 | handler.SignalSuccess(m_result); | |
|
163 | } | |
|
164 | ||
|
165 | protected override void SignalError(HandlerDescriptor handler, Exception error) { | |
|
166 | handler.SignalError(error); | |
|
167 | } | |
|
168 | ||
|
169 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | |
|
170 | handler.SignalCancel(reason); | |
|
171 | } | |
|
172 | ||
|
173 | #endregion | |
|
174 | ||
|
175 | T m_result; | |
|
176 | ||
|
177 | protected void SetResult(T value) { | |
|
178 | if (BeginSetResult()) { | |
|
179 | m_result = value; | |
|
180 | EndSetResult(); | |
|
181 | } | |
|
182 | } | |
|
183 | } | |
|
184 | } | |
|
185 |
@@ -0,0 +1,54 | |||
|
1 | using System; | |
|
2 | using System.Threading; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public class ChainTask : AbstractPromise, IDeferred { | |
|
6 | readonly Func<IPromise> m_task; | |
|
7 | readonly Action<Exception> m_error; | |
|
8 | readonly Action<Exception> m_cancel; | |
|
9 | ||
|
10 | int m_cancelationLock; | |
|
11 | ||
|
12 | public ChainTask(Func<IPromise> task, Func<Exception> error, Func<Exception> cancel) { | |
|
13 | m_task = task; | |
|
14 | } | |
|
15 | ||
|
16 | public void Resolve() { | |
|
17 | if (m_task != null && LockCancelation()) { | |
|
18 | try { | |
|
19 | var operation = m_task(); | |
|
20 | if (operation == null) | |
|
21 | throw new NullReferenceException("The task returned null promise"); | |
|
22 | ||
|
23 | operation.On(SetResult, SetError, SetCancelled); | |
|
24 | ||
|
25 | CancelationRequested(operation.Cancel); | |
|
26 | } catch(Exception err) { | |
|
27 | HandleErrorInternal(err); | |
|
28 | } | |
|
29 | } | |
|
30 | } | |
|
31 | ||
|
32 | public void Reject(Exception error) { | |
|
33 | throw new NotImplementedException(); | |
|
34 | } | |
|
35 | ||
|
36 | protected void HandleErrorInternal(Exception error) { | |
|
37 | if (m_error != null) { | |
|
38 | try { | |
|
39 | m_error(error); | |
|
40 | SetResult(); | |
|
41 | } catch(Exception err) { | |
|
42 | SetError(err); | |
|
43 | } | |
|
44 | } else { | |
|
45 | SetError(error); | |
|
46 | } | |
|
47 | } | |
|
48 | ||
|
49 | protected bool LockCancelation() { | |
|
50 | return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0); | |
|
51 | } | |
|
52 | } | |
|
53 | } | |
|
54 |
@@ -0,0 +1,23 | |||
|
1 | using System; | |
|
2 | using System.Threading; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public class FuncTask<T> : FuncTaskBase<T>, IDeferred { | |
|
6 | readonly Func<T> m_task; | |
|
7 | ||
|
8 | public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel) : base(error,cancel) { | |
|
9 | m_task = task; | |
|
10 | } | |
|
11 | ||
|
12 | public void Resolve() { | |
|
13 | if (m_task != null && LockCancelation()) { | |
|
14 | try { | |
|
15 | SetResult(m_task()); | |
|
16 | } catch(Exception err) { | |
|
17 | HandleErrorInternal(err); | |
|
18 | } | |
|
19 | } | |
|
20 | } | |
|
21 | } | |
|
22 | } | |
|
23 |
@@ -0,0 +1,53 | |||
|
1 | using System; | |
|
2 | using System.Threading; | |
|
3 | ||
|
4 | namespace Implab { | |
|
5 | public class FuncTaskBase<TResult> : AbstractPromise<TResult> { | |
|
6 | readonly Func<Exception, TResult> m_cancel; | |
|
7 | readonly Func<Exception, TResult> m_error; | |
|
8 | ||
|
9 | int m_cancelationLock; | |
|
10 | ||
|
11 | protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel) { | |
|
12 | m_error = error; | |
|
13 | m_cancel = cancel; | |
|
14 | } | |
|
15 | ||
|
16 | public void Reject(Exception error) { | |
|
17 | Safe.ArgumentNotNull(error, "error"); | |
|
18 | if (LockCancelation()) | |
|
19 | HandleErrorInternal(error); | |
|
20 | } | |
|
21 | ||
|
22 | protected void HandleErrorInternal(Exception error) { | |
|
23 | if (m_error != null) { | |
|
24 | try { | |
|
25 | SetResult(m_error(error)); | |
|
26 | } catch(Exception err) { | |
|
27 | SetError(err); | |
|
28 | } | |
|
29 | } else { | |
|
30 | SetError(error); | |
|
31 | } | |
|
32 | } | |
|
33 | ||
|
34 | public override void CancelOperation(Exception reason) { | |
|
35 | if (LockCancelation()) { | |
|
36 | if (m_cancel != null) { | |
|
37 | try { | |
|
38 | SetResult(m_cancel(reason)); | |
|
39 | } catch (Exception err) { | |
|
40 | HandleErrorInternal(err); | |
|
41 | } | |
|
42 | } else { | |
|
43 | SetCancelled(reason); | |
|
44 | } | |
|
45 | } | |
|
46 | } | |
|
47 | ||
|
48 | protected bool LockCancelation() { | |
|
49 | return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0); | |
|
50 | } | |
|
51 | } | |
|
52 | } | |
|
53 |
@@ -0,0 +1,22 | |||
|
1 | using System; | |
|
2 | ||
|
3 | namespace Implab { | |
|
4 | public class FuncTask<TArg, TResult> : FuncTaskBase<TResult>, IDeferred<TArg> { | |
|
5 | readonly Func<TArg, TResult> m_task; | |
|
6 | ||
|
7 | public FuncTask(Func<TArg, TResult> task, Func<Exception, TResult> error,Func<Exception, TResult> cancel) : base(error,cancel) { | |
|
8 | m_task = task; | |
|
9 | } | |
|
10 | ||
|
11 | public void Resolve(TArg value) { | |
|
12 | if (m_task != null && LockCancelation()) { | |
|
13 | try { | |
|
14 | SetResult(m_task(value)); | |
|
15 | } catch (Exception err) { | |
|
16 | HandleErrorInternal(err); | |
|
17 | } | |
|
18 | } | |
|
19 | } | |
|
20 | } | |
|
21 | } | |
|
22 |
@@ -1,296 +1,136 | |||
|
1 | 1 | using System; |
|
2 | 2 | using Implab.Parallels; |
|
3 | using System.Threading; | |
|
4 | using System.Reflection; | |
|
5 | 3 | |
|
6 | 4 | namespace Implab { |
|
7 |
public abstract class AbstractPromise< |
|
|
5 | public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | |
|
6 | public struct HandlerDescriptor { | |
|
7 | readonly Action m_handler; | |
|
8 | readonly Action<Exception> m_error; | |
|
9 | readonly Action<Exception> m_cancel; | |
|
10 | readonly PromiseEventType m_mask; | |
|
8 | 11 | |
|
9 | const int UNRESOLVED_SATE = 0; | |
|
10 | const int TRANSITIONAL_STATE = 1; | |
|
11 | const int SUCCEEDED_STATE = 2; | |
|
12 | const int REJECTED_STATE = 3; | |
|
13 | const int CANCELLED_STATE = 4; | |
|
14 | ||
|
15 | const int RESERVED_HANDLERS_COUNT = 4; | |
|
12 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
13 | m_handler = success; | |
|
14 | m_error = error; | |
|
15 | m_cancel = cancel; | |
|
16 | m_mask = PromiseEventType.Success; | |
|
17 | } | |
|
16 | 18 | |
|
17 | int m_state; | |
|
18 | Exception m_error; | |
|
19 | int m_handlersCount; | |
|
19 | public HandlerDescriptor(Action handler, PromiseEventType mask) { | |
|
20 | m_handler = handler; | |
|
21 | m_mask = mask; | |
|
22 | } | |
|
20 | 23 | |
|
21 | readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT]; | |
|
22 | MTQueue<THandler> m_extraHandlers; | |
|
23 | int m_handlerPointer = -1; | |
|
24 | int m_handlersCommited; | |
|
25 | ||
|
26 | #region state managment | |
|
27 | bool BeginTransit() { | |
|
28 | return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); | |
|
29 | } | |
|
24 | public void SignalSuccess() { | |
|
25 | if (m_mask & PromiseEventType.Success && m_handler != null) { | |
|
26 | try { | |
|
27 | m_handler(); | |
|
28 | } catch (Exception err) { | |
|
29 | // avoid calling handler twice in case of error | |
|
30 | if (m_error != null) | |
|
31 | SignalError(err); | |
|
32 | } | |
|
33 | } | |
|
34 | } | |
|
30 | 35 | |
|
31 | void CompleteTransit(int state) { | |
|
32 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) | |
|
33 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | |
|
34 | } | |
|
35 | ||
|
36 | void WaitTransition() { | |
|
37 | while (m_state == TRANSITIONAL_STATE) { | |
|
38 | Thread.MemoryBarrier(); | |
|
36 | public void SignalError(Exception err) { | |
|
37 | if (m_error != null) { | |
|
38 | try { | |
|
39 | m_error(err); | |
|
40 | // Analysis disable once EmptyGeneralCatchClause | |
|
41 | } catch { | |
|
42 | } | |
|
43 | } else if (m_mask & PromiseEventType.Error && m_handler != null) { | |
|
44 | try { | |
|
45 | m_handler(); | |
|
46 | // Analysis disable once EmptyGeneralCatchClause | |
|
47 | } catch { | |
|
48 | } | |
|
49 | } | |
|
39 | 50 | } |
|
40 | } | |
|
41 | 51 | |
|
42 | protected bool BeginSetResult() { | |
|
43 | if (!BeginTransit()) { | |
|
44 |
|
|
|
45 | if (m_state != CANCELLED_STATE) | |
|
46 | throw new InvalidOperationException("The promise is already resolved"); | |
|
47 |
|
|
|
52 | public void SignalCancel(Exception reason) { | |
|
53 | if (m_cancel != null) { | |
|
54 | try { | |
|
55 | m_cancel(reason); | |
|
56 | } catch (Exception err) { | |
|
57 | SignalError(err); | |
|
58 | } | |
|
59 | } else if (m_mask & PromiseEventType.Cancelled && m_handler != null) { | |
|
60 | try { | |
|
61 | m_handler(); | |
|
62 | // Analysis disable once EmptyGeneralCatchClause | |
|
63 | } catch { | |
|
64 | } | |
|
65 | } | |
|
48 | 66 | } |
|
49 | return true; | |
|
50 | } | |
|
51 | ||
|
52 | protected void EndSetResult() { | |
|
53 | CompleteTransit(SUCCEEDED_STATE); | |
|
54 | OnSuccess(); | |
|
55 | 67 | } |
|
56 | 68 | |
|
57 | 69 | |
|
70 | #region implemented abstract members of AbstractPromise | |
|
58 | 71 | |
|
59 | /// <summary> | |
|
60 | /// ΠΡΠΏΠΎΠ»Π½ΡΠ΅Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅, ΡΠΎΠΎΠ±ΡΠ°Ρ ΠΎΠ± ΠΎΡΠΈΠ±ΠΊΠ΅ | |
|
61 | /// </summary> | |
|
62 | /// <remarks> | |
|
63 | /// ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡΠΎΡΠ½ΠΎΠΉ ΡΡΠ΅Π΄Π΅, ΠΏΡΠΈ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠΎΠΊΠΎΠ² | |
|
64 | /// ΠΌΠΎΠ³Ρ Π²Π΅ΡΠ½ΡΡΡ ΠΎΡΠΈΠ±ΠΊΡ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΠ²Π°Ρ Π±ΡΠ΄Π΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π° Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ | |
|
65 | /// Π±ΡΠ΄ΡΡ ΠΏΡΠΎΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°Π½Ρ. | |
|
66 | /// </remarks> | |
|
67 | /// <param name="error">ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ</param> | |
|
68 | /// <exception cref="InvalidOperationException">ΠΠ°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠΆΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception> | |
|
69 | protected void SetError(Exception error) { | |
|
70 | if (BeginTransit()) { | |
|
71 | if (error is OperationCanceledException) { | |
|
72 | CompleteTransit(CANCELLED_STATE); | |
|
73 | m_error = error.InnerException; | |
|
74 | OnCancelled(); | |
|
75 | } else { | |
|
76 | m_error = error is PromiseTransientException ? error.InnerException : error; | |
|
77 | CompleteTransit(REJECTED_STATE); | |
|
78 | OnError(); | |
|
79 | } | |
|
80 | } else { | |
|
81 | WaitTransition(); | |
|
82 | if (m_state == SUCCEEDED_STATE) | |
|
83 | throw new InvalidOperationException("The promise is already resolved"); | |
|
84 | } | |
|
85 | } | |
|
86 | ||
|
87 | /// <summary> | |
|
88 | /// ΠΡΠΌΠ΅Π½ΡΠ΅Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ, Π΅ΡΠ»ΠΈ ΡΡΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. | |
|
89 | /// </summary> | |
|
90 | /// <remarks>ΠΠ»Ρ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ Π±ΡΠ»Π° Π»ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ ΠΎΡΠΌΠ΅Π½Π΅Π½Π° ΡΠ»Π΅Π΄ΡΠ΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠ²ΠΎΠΉΡΡΠ²ΠΎ <see cref="IsCancelled"/>.</remarks> | |
|
91 | protected void SetCancelled(Exception reason) { | |
|
92 | if (BeginTransit()) { | |
|
93 | m_error = reason; | |
|
94 | CompleteTransit(CANCELLED_STATE); | |
|
95 | OnCancelled(); | |
|
96 | } | |
|
72 | protected override void SignalSuccess(HandlerDescriptor handler) { | |
|
73 | handler.SignalSuccess(); | |
|
97 | 74 | } |
|
98 | 75 | |
|
99 |
protected |
|
|
100 | ||
|
101 | protected abstract void SignalError(THandler handler, Exception error); | |
|
102 | ||
|
103 | protected abstract void SignalCancelled(THandler handler, Exception reason); | |
|
104 | ||
|
105 | void OnSuccess() { | |
|
106 | var hp = m_handlerPointer; | |
|
107 | var slot = hp +1 ; | |
|
108 | while (slot < m_handlersCommited) { | |
|
109 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
110 | SignalSuccess(m_handlers[slot]); | |
|
111 | } | |
|
112 | hp = m_handlerPointer; | |
|
113 | slot = hp +1 ; | |
|
114 | } | |
|
115 | ||
|
116 | ||
|
117 | if (m_extraHandlers != null) { | |
|
118 | THandler handler; | |
|
119 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
120 | SignalSuccess(handler); | |
|
121 | } | |
|
76 | protected override void SignalError(HandlerDescriptor handler, Exception error) { | |
|
77 | handler.SignalError(error); | |
|
122 | 78 | } |
|
123 | 79 | |
|
124 | void OnError() { | |
|
125 | var hp = m_handlerPointer; | |
|
126 | var slot = hp +1 ; | |
|
127 | while (slot < m_handlersCommited) { | |
|
128 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
129 | SignalError(m_handlers[slot],m_error); | |
|
130 | } | |
|
131 | hp = m_handlerPointer; | |
|
132 | slot = hp +1 ; | |
|
133 | } | |
|
134 | ||
|
135 | if (m_extraHandlers != null) { | |
|
136 | THandler handler; | |
|
137 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
138 | SignalError(handler, m_error); | |
|
139 | } | |
|
80 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | |
|
81 | handler.SignalCancel(reason); | |
|
140 | 82 | } |
|
141 | 83 | |
|
142 | void OnCancelled() { | |
|
143 | var hp = m_handlerPointer; | |
|
144 | var slot = hp +1 ; | |
|
145 | while (slot < m_handlersCommited) { | |
|
146 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) { | |
|
147 | SignalCancelled(m_handlers[slot], m_error); | |
|
148 | } | |
|
149 | hp = m_handlerPointer; | |
|
150 | slot = hp +1 ; | |
|
151 | } | |
|
152 | ||
|
153 | if (m_extraHandlers != null) { | |
|
154 | THandler handler; | |
|
155 | while (m_extraHandlers.TryDequeue(out handler)) | |
|
156 | SignalCancelled(handler, m_error); | |
|
157 | } | |
|
84 | protected override Signal GetResolveSignal() { | |
|
85 | var signal = new Signal(); | |
|
86 | On(signal.Set, PromiseEventType.All); | |
|
158 | 87 | } |
|
159 | 88 | |
|
160 | 89 | #endregion |
|
161 | 90 | |
|
162 | protected abstract void Listen(PromiseEventType events, Action handler); | |
|
163 | 91 | |
|
164 | #region synchronization traits | |
|
165 | protected void WaitResult(int timeout) { | |
|
166 | if (!IsResolved) { | |
|
167 | var lk = new object(); | |
|
168 | ||
|
169 | Listen(PromiseEventType.All, () => { | |
|
170 | lock(lk) { | |
|
171 | Monitor.Pulse(lk); | |
|
172 | } | |
|
173 | }); | |
|
174 | ||
|
175 | lock (lk) { | |
|
176 | while(!IsResolved) { | |
|
177 | if(!Monitor.Wait(lk,timeout)) | |
|
178 | throw new TimeoutException(); | |
|
179 | } | |
|
180 | } | |
|
181 | ||
|
182 | } | |
|
183 | switch (m_state) { | |
|
184 | case SUCCEEDED_STATE: | |
|
185 | return; | |
|
186 | case CANCELLED_STATE: | |
|
187 | throw new OperationCanceledException(); | |
|
188 | case REJECTED_STATE: | |
|
189 | throw new TargetInvocationException(m_error); | |
|
190 | default: | |
|
191 | throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); | |
|
192 | } | |
|
193 | } | |
|
194 | #endregion | |
|
195 | ||
|
196 | #region handlers managment | |
|
197 | ||
|
198 | protected void AddHandler(THandler handler) { | |
|
199 | ||
|
200 | if (m_state > 1) { | |
|
201 | // the promise is in the resolved state, just invoke the handler | |
|
202 | InvokeHandler(handler); | |
|
203 | } else { | |
|
204 | var slot = Interlocked.Increment(ref m_handlersCount) - 1; | |
|
205 | ||
|
206 | if (slot < RESERVED_HANDLERS_COUNT) { | |
|
207 | m_handlers[slot] = handler; | |
|
208 | ||
|
209 | while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) { | |
|
210 | } | |
|
211 | ||
|
212 | if (m_state > 1) { | |
|
213 | do { | |
|
214 | var hp = m_handlerPointer; | |
|
215 | slot = hp + 1; | |
|
216 | if (slot < m_handlersCommited) { | |
|
217 | if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp) | |
|
218 | continue; | |
|
219 | InvokeHandler(m_handlers[slot]); | |
|
220 | } | |
|
221 | break; | |
|
222 | } while(true); | |
|
223 | } | |
|
224 | } else { | |
|
225 | if (slot == RESERVED_HANDLERS_COUNT) { | |
|
226 | m_extraHandlers = new MTQueue<THandler>(); | |
|
227 | } else { | |
|
228 | while (m_extraHandlers == null) | |
|
229 | Thread.MemoryBarrier(); | |
|
230 | } | |
|
231 | ||
|
232 | m_extraHandlers.Enqueue(handler); | |
|
233 | ||
|
234 | if (m_state > 1 && m_extraHandlers.TryDequeue(out handler)) | |
|
235 | // if the promise have been resolved while we was adding the handler to the queue | |
|
236 | // we can't guarantee that someone is still processing it | |
|
237 | // therefore we need to fetch a handler from the queue and execute it | |
|
238 | // note that fetched handler may be not the one that we have added | |
|
239 | // even we can fetch no handlers at all :) | |
|
240 | InvokeHandler(handler); | |
|
241 | } | |
|
92 | public Type PromiseType { | |
|
93 | get { | |
|
94 | return typeof(void); | |
|
242 | 95 | } |
|
243 | 96 | } |
|
244 | 97 | |
|
245 | protected void InvokeHandler(THandler handler) { | |
|
246 | switch (m_state) { | |
|
247 | case SUCCEEDED_STATE: | |
|
248 | SignalSuccess(handler); | |
|
249 | break; | |
|
250 | case CANCELLED_STATE: | |
|
251 | SignalCancelled(handler, m_error); | |
|
252 |
|
|
|
253 | case REJECTED_STATE: | |
|
254 | SignalError(handler, m_error); | |
|
255 | break; | |
|
256 | default: | |
|
257 | throw new Exception(String.Format("Invalid promise state {0}", m_state)); | |
|
258 | } | |
|
98 | public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
99 | AddHandler(new HandlerDescriptor(success, error, cancel)); | |
|
100 | return this; | |
|
101 | } | |
|
102 | ||
|
103 | public IPromise On(Action success, Action<Exception> error) { | |
|
104 | AddHandler(new HandlerDescriptor(success, error, null)); | |
|
105 | return this; | |
|
259 | 106 | } |
|
260 | 107 | |
|
261 | #endregion | |
|
108 | public IPromise On(Action success) { | |
|
109 | AddHandler(new HandlerDescriptor(success, null, null)); | |
|
110 | return this; | |
|
111 | } | |
|
262 | 112 | |
|
263 | #region IPromise implementation | |
|
113 | public IPromise On(Action handler, PromiseEventType events) { | |
|
114 | AddHandler(new HandlerDescriptor(handler,events)); | |
|
115 | return this; | |
|
116 | } | |
|
264 | 117 | |
|
265 | public void Join(int timeout) { | |
|
266 | WaitResult(timeout); | |
|
118 | public IPromise<T> Cast<T>() { | |
|
119 | throw new InvalidCastException(); | |
|
267 | 120 | } |
|
268 | 121 | |
|
269 | 122 | public void Join() { |
|
270 | 123 | WaitResult(-1); |
|
271 | 124 | } |
|
272 | 125 | |
|
273 | public bool IsResolved { | |
|
274 | get { | |
|
275 | Thread.MemoryBarrier(); | |
|
276 | return m_state > 1; | |
|
277 | } | |
|
126 | public void Join(int timeout) { | |
|
127 | WaitResult(timeout); | |
|
278 | 128 | } |
|
279 | 129 | |
|
280 | public bool IsCancelled { | |
|
281 |
|
|
|
282 | Thread.MemoryBarrier(); | |
|
283 | return m_state == CANCELLED_STATE; | |
|
284 | } | |
|
285 | } | |
|
286 | ||
|
287 | #endregion | |
|
288 | ||
|
289 | public Exception Error { | |
|
290 | get { | |
|
291 | return m_error; | |
|
292 | } | |
|
130 | protected void SetResult() { | |
|
131 | BeginSetResult(); | |
|
132 | EndSetResult(); | |
|
293 | 133 | } |
|
294 | 134 | } |
|
295 | 135 | } |
|
296 | 136 |
@@ -1,36 +1,36 | |||
|
1 | 1 | using System; |
|
2 | 2 | |
|
3 | 3 | namespace Implab { |
|
4 | 4 | public interface ICancelationToken { |
|
5 | 5 | /// <summary> |
|
6 | 6 | /// Indicates wherther the cancellation was requested. |
|
7 | 7 | /// </summary> |
|
8 | 8 | bool IsCancelRequested { get ; } |
|
9 | 9 | |
|
10 | 10 | /// <summary> |
|
11 | 11 | /// The reason why the operation should be cancelled. |
|
12 | 12 | /// </summary> |
|
13 | 13 | Exception CancelReason { get ; } |
|
14 | 14 | |
|
15 | 15 | /// <summary> |
|
16 | 16 | /// Accepts if requested. |
|
17 | 17 | /// </summary> |
|
18 | 18 | /// <returns><c>true</c>, if if requested was accepted, <c>false</c> otherwise.</returns> |
|
19 | 19 | bool AcceptIfRequested(); |
|
20 | 20 | |
|
21 | 21 | /// <summary> |
|
22 | 22 | /// Sets the token to cancelled state. |
|
23 | 23 | /// </summary> |
|
24 | 24 | /// <param name="reason">The reason why the operation was cancelled.</param> |
|
25 |
void |
|
|
25 | void CancelOperation(Exception reason); | |
|
26 | 26 | |
|
27 | 27 | /// <summary> |
|
28 | 28 | /// Adds the listener for the cancellation request, is the cancellation was requested the <paramref name="handler"/> |
|
29 | 29 | /// is executed immediatelly. |
|
30 | 30 | /// </summary> |
|
31 | 31 | /// <param name="handler">The handler which will be executed if the cancel occurs.</param> |
|
32 |
void Cancel |
|
|
32 | void CancelationRequested(Action<Exception> handler); | |
|
33 | 33 | |
|
34 | 34 | } |
|
35 | 35 | } |
|
36 | 36 |
@@ -1,106 +1,106 | |||
|
1 | 1 | using System; |
|
2 | 2 | using System.Collections.Generic; |
|
3 | 3 | using System.Linq; |
|
4 | 4 | using System.Text; |
|
5 | 5 | |
|
6 | 6 | namespace Implab { |
|
7 | 7 | public interface IPromise: ICancellable { |
|
8 | 8 | |
|
9 | 9 | /// <summary> |
|
10 | 10 | /// Π’ΠΈΠΏ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°, ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌΠΎΠ³ΠΎ ΡΠ΅ΡΠ΅Π· Π΄Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅. |
|
11 | 11 | /// </summary> |
|
12 | 12 | Type PromiseType { get; } |
|
13 | 13 | |
|
14 | 14 | /// <summary> |
|
15 | 15 | /// ΠΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΡΠ²Π»ΡΠ΅ΡΡΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΡΠΌ, Π»ΠΈΠ±ΠΎ ΡΡΠΏΠ΅ΡΠ½ΠΎ, Π»ΠΈΠ±ΠΎ Ρ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ, Π»ΠΈΠ±ΠΎ ΠΎΡΠΌΠ΅Π½Π΅Π½ΠΎ. |
|
16 | 16 | /// </summary> |
|
17 | 17 | bool IsResolved { get; } |
|
18 | 18 | |
|
19 | 19 | /// <summary> |
|
20 | 20 | /// ΠΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π±ΡΠ»ΠΎ ΠΎΡΠΌΠ΅Π½Π΅Π½ΠΎ. |
|
21 | 21 | /// </summary> |
|
22 | 22 | bool IsCancelled { get; } |
|
23 | 23 | |
|
24 | 24 | /// <summary> |
|
25 | 25 | /// ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π²ΠΎΠ·Π½ΠΈΠΊΡΠ΅Π΅ Π² ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ, Π»ΠΈΠ±ΠΎ ΠΏΡΠΈΡΠΈΠ½Π° ΠΎΡΠΌΠ΅Π½Ρ. |
|
26 | 26 | /// </summary> |
|
27 | 27 | Exception Error { get; } |
|
28 | 28 | |
|
29 | 29 | /// <summary> |
|
30 | 30 | /// Creates a new promise dependend on the current one and resolved on |
|
31 | 31 | /// executing the specified handlers. |
|
32 | 32 | /// </summary> |
|
33 | 33 | /// <param name="success">The handler called on the successful promise completion.</param> |
|
34 | 34 | /// <param name="error">The handler is called if an error while completing the promise occurred.</param> |
|
35 | 35 | /// <param name="cancel">The handler is called in case of promise cancellation.</param> |
|
36 | 36 | /// <returns>The newly created dependant promise.</returns> |
|
37 | 37 | /// <remarks> |
|
38 | 38 | /// <para> |
|
39 | 39 | /// If the success handler is specified the dependend promise will be resolved after the handler is |
|
40 | 40 | /// executed and the dependent promise will be linked to the current one, i.e. the cancellation |
|
41 | 41 | /// of the dependent property will lead to the cancellation of the current promise. If the |
|
42 | 42 | /// success handler isn't specified the dependent promise will not be linked to and |
|
43 | 43 | /// will not be resolved after the successfull resolution of the current one. |
|
44 | 44 | /// </para> |
|
45 | 45 | /// <para> |
|
46 | 46 | /// When the error handler is specified, the exception raised during the current promise completion |
|
47 | 47 | /// will be passed to it as the parameter. If the error handler returns without raising an |
|
48 | 48 | /// exception then the dependant promise will be resolved successfully, otherwise the exception |
|
49 | 49 | /// raised by the handler will be transmitted to the dependent promise. If the handler wants |
|
50 | 50 | /// to passthrough the original exception it needs to wrap the exception with |
|
51 | 51 | /// the <see cref="PromiseTransientException"/>. The handler may raise <see cref="OperationCanceledException"/> |
|
52 | 52 | /// to cancel the dependant promise, the innner exception specifies the reason why the promise |
|
53 | 53 | /// is canceled. |
|
54 | 54 | /// </para> |
|
55 | 55 | /// <para> |
|
56 | 56 | /// If the cancelation handler is specified and the current promise is cancelled then the dependent |
|
57 | 57 | /// promise will be resolved after the handler is executed. If the cancelation handler raises the |
|
58 | 58 | /// exception it will be passed to the dependent promise. |
|
59 | 59 | /// </para> |
|
60 | 60 | /// </remarks> |
|
61 | IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel); | |
|
61 | /* IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel); | |
|
62 | 62 | IPromise Then(Action success, Action<Exception> error); |
|
63 | 63 | IPromise Then(Action success); |
|
64 | 64 |
|
|
65 | 65 | IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel); |
|
66 | 66 | IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error); |
|
67 |
|
|
|
67 | IPromise Chain(Func<IPromise> chained);*/ | |
|
68 | 68 | |
|
69 | 69 | /// <summary> |
|
70 | 70 | /// Adds specified listeners to the current promise. |
|
71 | 71 | /// </summary> |
|
72 | 72 | /// <param name="success">The handler called on the successful promise completion.</param> |
|
73 | 73 | /// <param name="error">The handler is called if an error while completing the promise occurred.</param> |
|
74 | 74 | /// <param name="cancel">The handler is called in case of promise cancellation.</param> |
|
75 | 75 | /// <returns>The current promise.</returns> |
|
76 | 76 | IPromise On(Action success, Action<Exception> error, Action<Exception> cancel); |
|
77 | 77 | IPromise On(Action success, Action<Exception> error); |
|
78 | 78 | IPromise On(Action success); |
|
79 | 79 | |
|
80 | 80 | /// <summary> |
|
81 | 81 | /// Adds specified listeners to the current promise. |
|
82 | 82 | /// </summary> |
|
83 | 83 | /// <param name="handler">The handler called on the specified events.</param> |
|
84 | 84 | /// <param name = "events">The combination of flags denoting the events for which the |
|
85 | 85 | /// handler shoud be called.</param> |
|
86 | 86 | /// <returns>The current promise.</returns> |
|
87 | 87 | IPromise On(Action handler, PromiseEventType events); |
|
88 | 88 | |
|
89 | 89 | /// <summary> |
|
90 | 90 | /// ΠΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ΅Ρ ΡΠ΅Π·ΡΠ»ΡΡΠ°Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ ΠΊ Π·Π°Π΄Π°Π½Π½ΠΎΠΌΡ ΡΠΈΠΏΡ ΠΈ Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅. |
|
91 | 91 | /// </summary> |
|
92 | 92 | IPromise<T> Cast<T>(); |
|
93 | 93 | |
|
94 | 94 | /// <summary> |
|
95 | 95 | /// Π‘ΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·ΠΈΡΡΠ΅Ρ ΡΠ΅ΠΊΡΡΠΈΠΉ ΠΏΠΎΡΠΎΠΊ Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ΠΌ. |
|
96 | 96 | /// </summary> |
|
97 | 97 | void Join(); |
|
98 | 98 | /// <summary> |
|
99 | 99 | /// Π‘ΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·ΠΈΡΡΠ΅Ρ ΡΠ΅ΠΊΡΡΠΈΠΉ ΠΏΠΎΡΠΎΠΊ Ρ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ΠΌ. |
|
100 | 100 | /// </summary> |
|
101 | 101 | /// <param name="timeout">ΠΡΠ΅ΠΌΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ, ΠΏΠΎ Π΅Π³ΠΎ ΠΈΡΡΠ΅ΡΠ΅Π½ΠΈΡ Π²ΠΎΠ·Π½ΠΈΠΊΠ½Π΅Ρ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅.</param> |
|
102 | 102 | /// <exception cref="TimeoutException">ΠΡΠ΅Π²ΡΡΠ΅Π½ΠΎ Π²ΡΠ΅ΠΌΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΡ.</exception> |
|
103 | 103 | void Join(int timeout); |
|
104 | 104 | |
|
105 | 105 | } |
|
106 | 106 | } |
@@ -1,30 +1,25 | |||
|
1 | 1 | using System; |
|
2 | 2 | |
|
3 | 3 | namespace Implab { |
|
4 | 4 | public interface IPromise<out T> : IPromise { |
|
5 | 5 | |
|
6 | new T Join(); | |
|
7 | ||
|
8 | new T Join(int timeout); | |
|
9 | ||
|
10 | 6 | IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel); |
|
11 | 7 | |
|
12 | 8 | IPromise<T> On(Action<T> success, Action<Exception> error); |
|
13 | 9 | |
|
14 | 10 | IPromise<T> On(Action<T> success); |
|
15 | 11 | |
|
12 | new T Join(); | |
|
13 | ||
|
14 | new T Join(int timeout); | |
|
15 | ||
|
16 | new IPromise<T> On(Action success, Action<Exception> error, Action<Exception> cancel); | |
|
17 | ||
|
18 | new IPromise<T> On(Action success, Action<Exception> error); | |
|
19 | ||
|
20 | new IPromise<T> On(Action success); | |
|
21 | ||
|
16 | 22 | new IPromise<T> On(Action handler, PromiseEventType events); |
|
17 | 23 | |
|
18 | IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel); | |
|
19 | ||
|
20 | IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error); | |
|
21 | ||
|
22 | IPromise<T2> Then<T2>(Func<T, T2> mapper); | |
|
23 | ||
|
24 | IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel); | |
|
25 | ||
|
26 | IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error); | |
|
27 | ||
|
28 | IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained); | |
|
29 | 24 | } |
|
30 | 25 | } |
@@ -1,234 +1,240 | |||
|
1 | 1 | ο»Ώ<?xml version="1.0" encoding="utf-8"?> |
|
2 | 2 | <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|
3 | 3 | <PropertyGroup> |
|
4 | 4 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|
5 | 5 | <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|
6 | 6 | <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid> |
|
7 | 7 | <OutputType>Library</OutputType> |
|
8 | 8 | <RootNamespace>Implab</RootNamespace> |
|
9 | 9 | <AssemblyName>Implab</AssemblyName> |
|
10 | 10 | <ProductVersion>8.0.30703</ProductVersion> |
|
11 | 11 | <SchemaVersion>2.0</SchemaVersion> |
|
12 | 12 | </PropertyGroup> |
|
13 | 13 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|
14 | 14 | <DebugSymbols>true</DebugSymbols> |
|
15 | 15 | <DebugType>full</DebugType> |
|
16 | 16 | <Optimize>false</Optimize> |
|
17 | 17 | <OutputPath>bin\Debug</OutputPath> |
|
18 | 18 | <DefineConstants>TRACE;DEBUG;</DefineConstants> |
|
19 | 19 | <ErrorReport>prompt</ErrorReport> |
|
20 | 20 | <WarningLevel>4</WarningLevel> |
|
21 | 21 | <ConsolePause>false</ConsolePause> |
|
22 | 22 | <RunCodeAnalysis>true</RunCodeAnalysis> |
|
23 | 23 | </PropertyGroup> |
|
24 | 24 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|
25 | 25 | <DebugType>full</DebugType> |
|
26 | 26 | <Optimize>true</Optimize> |
|
27 | 27 | <OutputPath>bin\Release</OutputPath> |
|
28 | 28 | <ErrorReport>prompt</ErrorReport> |
|
29 | 29 | <WarningLevel>4</WarningLevel> |
|
30 | 30 | <ConsolePause>false</ConsolePause> |
|
31 | 31 | </PropertyGroup> |
|
32 | 32 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' "> |
|
33 | 33 | <DebugSymbols>true</DebugSymbols> |
|
34 | 34 | <DebugType>full</DebugType> |
|
35 | 35 | <Optimize>false</Optimize> |
|
36 | 36 | <OutputPath>bin\Debug</OutputPath> |
|
37 | 37 | <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants> |
|
38 | 38 | <ErrorReport>prompt</ErrorReport> |
|
39 | 39 | <WarningLevel>4</WarningLevel> |
|
40 | 40 | <RunCodeAnalysis>true</RunCodeAnalysis> |
|
41 | 41 | <ConsolePause>false</ConsolePause> |
|
42 | 42 | </PropertyGroup> |
|
43 | 43 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' "> |
|
44 | 44 | <Optimize>true</Optimize> |
|
45 | 45 | <OutputPath>bin\Release</OutputPath> |
|
46 | 46 | <ErrorReport>prompt</ErrorReport> |
|
47 | 47 | <WarningLevel>4</WarningLevel> |
|
48 | 48 | <ConsolePause>false</ConsolePause> |
|
49 | 49 | <DefineConstants>NET_4_5</DefineConstants> |
|
50 | 50 | </PropertyGroup> |
|
51 | 51 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' "> |
|
52 | 52 | <DebugSymbols>true</DebugSymbols> |
|
53 | 53 | <DebugType>full</DebugType> |
|
54 | 54 | <Optimize>false</Optimize> |
|
55 | 55 | <OutputPath>bin\Debug</OutputPath> |
|
56 | 56 | <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants> |
|
57 | 57 | <ErrorReport>prompt</ErrorReport> |
|
58 | 58 | <WarningLevel>4</WarningLevel> |
|
59 | 59 | <RunCodeAnalysis>true</RunCodeAnalysis> |
|
60 | 60 | <ConsolePause>false</ConsolePause> |
|
61 | 61 | </PropertyGroup> |
|
62 | 62 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' "> |
|
63 | 63 | <Optimize>true</Optimize> |
|
64 | 64 | <OutputPath>bin\Release</OutputPath> |
|
65 | 65 | <DefineConstants>NET_4_5;MONO;</DefineConstants> |
|
66 | 66 | <ErrorReport>prompt</ErrorReport> |
|
67 | 67 | <WarningLevel>4</WarningLevel> |
|
68 | 68 | <ConsolePause>false</ConsolePause> |
|
69 | 69 | </PropertyGroup> |
|
70 | 70 | <ItemGroup> |
|
71 | 71 | <Reference Include="System" /> |
|
72 | 72 | <Reference Include="System.Xml" /> |
|
73 | 73 | </ItemGroup> |
|
74 | 74 | <ItemGroup> |
|
75 | 75 | <Compile Include="Component.cs" /> |
|
76 | 76 | <Compile Include="CustomEqualityComparer.cs" /> |
|
77 | 77 | <Compile Include="Diagnostics\ConsoleTraceListener.cs" /> |
|
78 | 78 | <Compile Include="Diagnostics\EventText.cs" /> |
|
79 | 79 | <Compile Include="Diagnostics\LogChannel.cs" /> |
|
80 | 80 | <Compile Include="Diagnostics\LogicalOperation.cs" /> |
|
81 | 81 | <Compile Include="Diagnostics\TextFileListener.cs" /> |
|
82 | 82 | <Compile Include="Diagnostics\TraceLog.cs" /> |
|
83 | 83 | <Compile Include="Diagnostics\TraceEvent.cs" /> |
|
84 | 84 | <Compile Include="Diagnostics\TraceEventType.cs" /> |
|
85 | 85 | <Compile Include="Disposable.cs" /> |
|
86 | 86 | <Compile Include="ICancellable.cs" /> |
|
87 | 87 | <Compile Include="IProgressHandler.cs" /> |
|
88 | 88 | <Compile Include="IProgressNotifier.cs" /> |
|
89 | 89 | <Compile Include="IPromiseT.cs" /> |
|
90 | 90 | <Compile Include="IPromise.cs" /> |
|
91 | 91 | <Compile Include="IServiceLocator.cs" /> |
|
92 | 92 | <Compile Include="ITaskController.cs" /> |
|
93 | 93 | <Compile Include="JSON\JSONElementContext.cs" /> |
|
94 | 94 | <Compile Include="JSON\JSONElementType.cs" /> |
|
95 | 95 | <Compile Include="JSON\JSONGrammar.cs" /> |
|
96 | 96 | <Compile Include="JSON\JSONParser.cs" /> |
|
97 | 97 | <Compile Include="JSON\JSONScanner.cs" /> |
|
98 | 98 | <Compile Include="JSON\JsonTokenType.cs" /> |
|
99 | 99 | <Compile Include="JSON\JSONWriter.cs" /> |
|
100 | 100 | <Compile Include="JSON\JSONXmlReader.cs" /> |
|
101 | 101 | <Compile Include="JSON\JSONXmlReaderOptions.cs" /> |
|
102 | 102 | <Compile Include="JSON\StringTranslator.cs" /> |
|
103 | 103 | <Compile Include="Parallels\DispatchPool.cs" /> |
|
104 | 104 | <Compile Include="Parallels\ArrayTraits.cs" /> |
|
105 | 105 | <Compile Include="Parallels\MTQueue.cs" /> |
|
106 | 106 | <Compile Include="Parallels\WorkerPool.cs" /> |
|
107 | 107 | <Compile Include="Parsing\Alphabet.cs" /> |
|
108 | 108 | <Compile Include="Parsing\AlphabetBase.cs" /> |
|
109 | 109 | <Compile Include="Parsing\AltToken.cs" /> |
|
110 | 110 | <Compile Include="Parsing\BinaryToken.cs" /> |
|
111 | 111 | <Compile Include="Parsing\CatToken.cs" /> |
|
112 | 112 | <Compile Include="Parsing\CDFADefinition.cs" /> |
|
113 | 113 | <Compile Include="Parsing\DFABuilder.cs" /> |
|
114 | 114 | <Compile Include="Parsing\DFADefinitionBase.cs" /> |
|
115 | 115 | <Compile Include="Parsing\DFAStateDescriptor.cs" /> |
|
116 | 116 | <Compile Include="Parsing\DFAutomaton.cs" /> |
|
117 | 117 | <Compile Include="Parsing\EDFADefinition.cs" /> |
|
118 | 118 | <Compile Include="Parsing\EmptyToken.cs" /> |
|
119 | 119 | <Compile Include="Parsing\EndToken.cs" /> |
|
120 | 120 | <Compile Include="Parsing\EnumAlphabet.cs" /> |
|
121 | 121 | <Compile Include="Parsing\Grammar.cs" /> |
|
122 | 122 | <Compile Include="Parsing\IAlphabet.cs" /> |
|
123 | 123 | <Compile Include="Parsing\IDFADefinition.cs" /> |
|
124 | 124 | <Compile Include="Parsing\IVisitor.cs" /> |
|
125 | 125 | <Compile Include="Parsing\ParserException.cs" /> |
|
126 | 126 | <Compile Include="Parsing\Scanner.cs" /> |
|
127 | 127 | <Compile Include="Parsing\StarToken.cs" /> |
|
128 | 128 | <Compile Include="Parsing\SymbolToken.cs" /> |
|
129 | 129 | <Compile Include="Parsing\Token.cs" /> |
|
130 | 130 | <Compile Include="ServiceLocator.cs" /> |
|
131 | 131 | <Compile Include="TaskController.cs" /> |
|
132 | 132 | <Compile Include="ProgressInitEventArgs.cs" /> |
|
133 | 133 | <Compile Include="Properties\AssemblyInfo.cs" /> |
|
134 | 134 | <Compile Include="Parallels\AsyncPool.cs" /> |
|
135 | 135 | <Compile Include="Safe.cs" /> |
|
136 | 136 | <Compile Include="ValueEventArgs.cs" /> |
|
137 | 137 | <Compile Include="PromiseExtensions.cs" /> |
|
138 | 138 | <Compile Include="SyncContextPromise.cs" /> |
|
139 | 139 | <Compile Include="Diagnostics\OperationContext.cs" /> |
|
140 | 140 | <Compile Include="Diagnostics\TraceContext.cs" /> |
|
141 | 141 | <Compile Include="Diagnostics\LogEventArgs.cs" /> |
|
142 | 142 | <Compile Include="Diagnostics\LogEventArgsT.cs" /> |
|
143 | 143 | <Compile Include="Diagnostics\Extensions.cs" /> |
|
144 | 144 | <Compile Include="IComponentContainer.cs" /> |
|
145 | 145 | <Compile Include="PromiseEventType.cs" /> |
|
146 | 146 | <Compile Include="ComponentContainer.cs" /> |
|
147 | 147 | <Compile Include="DisposablePool.cs" /> |
|
148 | 148 | <Compile Include="ObjectPool.cs" /> |
|
149 | 149 | <Compile Include="Parallels\AsyncQueue.cs" /> |
|
150 | 150 | <Compile Include="PromiseT.cs" /> |
|
151 | 151 | <Compile Include="IDeferred.cs" /> |
|
152 | 152 | <Compile Include="IDeferredT.cs" /> |
|
153 | <Compile Include="AbstractPromise.cs" /> | |
|
154 | 153 | <Compile Include="Promise.cs" /> |
|
155 | 154 | <Compile Include="PromiseTransientException.cs" /> |
|
156 | 155 | <Compile Include="Parallels\Signal.cs" /> |
|
157 | 156 | <Compile Include="Parallels\SharedLock.cs" /> |
|
158 | 157 | <Compile Include="Diagnostics\ILogWriter.cs" /> |
|
159 | 158 | <Compile Include="Diagnostics\ListenerBase.cs" /> |
|
160 | 159 | <Compile Include="Parallels\BlockingQueue.cs" /> |
|
161 | 160 | <Compile Include="ICancelationToken.cs" /> |
|
161 | <Compile Include="AbstractEvent.cs" /> | |
|
162 | <Compile Include="AbstractPromise.cs" /> | |
|
163 | <Compile Include="AbstractPromiseT.cs" /> | |
|
164 | <Compile Include="FuncTask.cs" /> | |
|
165 | <Compile Include="FuncTaskBase.cs" /> | |
|
166 | <Compile Include="FuncTaskT.cs" /> | |
|
167 | <Compile Include="ChainTask.cs" /> | |
|
162 | 168 | </ItemGroup> |
|
163 | 169 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
164 | 170 | <ItemGroup /> |
|
165 | 171 | <ProjectExtensions> |
|
166 | 172 | <MonoDevelop> |
|
167 | 173 | <Properties> |
|
168 | 174 | <Policies> |
|
169 | 175 | <CSharpFormattingPolicy IndentSwitchBody="True" NamespaceBraceStyle="EndOfLine" ClassBraceStyle="EndOfLine" InterfaceBraceStyle="EndOfLine" StructBraceStyle="EndOfLine" EnumBraceStyle="EndOfLine" MethodBraceStyle="EndOfLine" ConstructorBraceStyle="EndOfLine" DestructorBraceStyle="EndOfLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeIndexerDeclarationBracket="False" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" /> |
|
170 | 176 | <TextStylePolicy FileWidth="120" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" /> |
|
171 | 177 | <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" /> |
|
172 | 178 | <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="application/xml" /> |
|
173 | 179 | <XmlFormattingPolicy inheritsSet="Mono" inheritsScope="application/xml" scope="application/xml" /> |
|
174 | 180 | <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" /> |
|
175 | 181 | <NameConventionPolicy> |
|
176 | 182 | <Rules> |
|
177 | 183 | <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
178 | 184 | <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
179 | 185 | <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
180 | 186 | <RequiredPrefixes> |
|
181 | 187 | <String>I</String> |
|
182 | 188 | </RequiredPrefixes> |
|
183 | 189 | </NamingRule> |
|
184 | 190 | <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
185 | 191 | <RequiredSuffixes> |
|
186 | 192 | <String>Attribute</String> |
|
187 | 193 | </RequiredSuffixes> |
|
188 | 194 | </NamingRule> |
|
189 | 195 | <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
190 | 196 | <RequiredSuffixes> |
|
191 | 197 | <String>EventArgs</String> |
|
192 | 198 | </RequiredSuffixes> |
|
193 | 199 | </NamingRule> |
|
194 | 200 | <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
195 | 201 | <RequiredSuffixes> |
|
196 | 202 | <String>Exception</String> |
|
197 | 203 | </RequiredSuffixes> |
|
198 | 204 | </NamingRule> |
|
199 | 205 | <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
200 | 206 | <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" /> |
|
201 | 207 | <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
202 | 208 | <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" /> |
|
203 | 209 | <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False"> |
|
204 | 210 | <RequiredPrefixes> |
|
205 | 211 | <String>m_</String> |
|
206 | 212 | </RequiredPrefixes> |
|
207 | 213 | </NamingRule> |
|
208 | 214 | <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True"> |
|
209 | 215 | <RequiredPrefixes> |
|
210 | 216 | <String>_</String> |
|
211 | 217 | </RequiredPrefixes> |
|
212 | 218 | </NamingRule> |
|
213 | 219 | <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False"> |
|
214 | 220 | <RequiredPrefixes> |
|
215 | 221 | <String>m_</String> |
|
216 | 222 | </RequiredPrefixes> |
|
217 | 223 | </NamingRule> |
|
218 | 224 | <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
219 | 225 | <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
220 | 226 | <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
221 | 227 | <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
222 | 228 | <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" /> |
|
223 | 229 | <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True"> |
|
224 | 230 | <RequiredPrefixes> |
|
225 | 231 | <String>T</String> |
|
226 | 232 | </RequiredPrefixes> |
|
227 | 233 | </NamingRule> |
|
228 | 234 | </Rules> |
|
229 | 235 | </NameConventionPolicy> |
|
230 | 236 | </Policies> |
|
231 | 237 | </Properties> |
|
232 | 238 | </MonoDevelop> |
|
233 | 239 | </ProjectExtensions> |
|
234 | 240 | </Project> No newline at end of file |
@@ -1,222 +1,22 | |||
|
1 | 1 | using System; |
|
2 | using System.Diagnostics; | |
|
2 | using Implab.Parallels; | |
|
3 | 3 | |
|
4 | 4 | namespace Implab { |
|
5 |
public class Promise : AbstractPromise |
|
|
6 | ||
|
7 | public struct HandlerDescriptor { | |
|
8 | readonly Action m_success; | |
|
9 | readonly Action<Exception> m_error; | |
|
10 | readonly Action<Exception> m_cancel; | |
|
11 | readonly IDeferred m_deferred; | |
|
12 | ||
|
13 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel, IDeferred deferred) { | |
|
14 | m_success = success; | |
|
15 | m_error = error; | |
|
16 | m_cancel = cancel; | |
|
17 | m_deferred = deferred; | |
|
18 | } | |
|
19 | ||
|
20 | public void SignalSuccess() { | |
|
21 | if (m_success != null) { | |
|
22 | try { | |
|
23 | m_success(); | |
|
24 | if (m_deferred != null) | |
|
25 | m_deferred.Resolve(); | |
|
26 | } catch (Exception err) { | |
|
27 | SignalError(err); | |
|
28 | } | |
|
29 | } | |
|
30 | } | |
|
5 | public class Promise : AbstractPromise, IDeferred { | |
|
6 | public static readonly Promise SUCCESS; | |
|
31 | 7 | |
|
32 | public void SignalError(Exception err) { | |
|
33 | if (m_error != null) { | |
|
34 | try { | |
|
35 | m_error(err); | |
|
36 | if (m_deferred != null) | |
|
37 | m_deferred.Resolve(); | |
|
38 | } catch (Exception err2) { | |
|
39 | if (m_deferred != null) | |
|
40 | m_deferred.Reject(err2); | |
|
41 | } | |
|
42 | } else { | |
|
43 | if (m_deferred != null) | |
|
44 | m_deferred.Reject(err); | |
|
45 | } | |
|
46 | } | |
|
47 | ||
|
48 | public void SignalCancel(Exception reason) { | |
|
49 | if (m_cancel != null) { | |
|
50 | try { | |
|
51 | m_cancel(reason); | |
|
52 | if (m_deferred != null) | |
|
53 | m_deferred.Resolve(); | |
|
54 | } catch (Exception err) { | |
|
55 | SignalError(err); | |
|
56 | } | |
|
57 | } else if (reason != null && m_error != null) { | |
|
58 | try { | |
|
59 | m_error(new OperationCanceledException("The operation was canceled.", reason)); | |
|
60 | if (m_deferred != null) | |
|
61 | m_deferred.Resolve(); | |
|
62 | } catch (Exception err) { | |
|
63 | SignalError(err); | |
|
64 | } | |
|
65 | } else { | |
|
66 | if (m_deferred != null) | |
|
67 | m_deferred.Cancel(reason); | |
|
68 | } | |
|
69 | } | |
|
8 | static Promise() { | |
|
9 | SUCCESS = new Promise(); | |
|
10 | SUCCESS.Resolve(); | |
|
70 | 11 | } |
|
71 | 12 | |
|
72 | 13 | public void Resolve() { |
|
73 |
|
|
|
74 | EndSetResult(); | |
|
14 | SetResult(); | |
|
75 | 15 | } |
|
76 | 16 | |
|
77 | 17 | public void Reject(Exception error) { |
|
78 | 18 | SetError(error); |
|
79 | 19 | } |
|
80 | ||
|
81 | #region implemented abstract members of AbstractPromise | |
|
82 | ||
|
83 | protected override void SignalSuccess(HandlerDescriptor handler) { | |
|
84 | handler.SignalSuccess(); | |
|
85 | } | |
|
86 | ||
|
87 | protected override void SignalError(HandlerDescriptor handler, Exception error) { | |
|
88 | handler.SignalError(error); | |
|
89 | } | |
|
90 | ||
|
91 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | |
|
92 | handler.SignalCancel(reason); | |
|
93 | } | |
|
94 | ||
|
95 | protected override void Listen(PromiseEventType events, Action handler) { | |
|
96 | AddHandler(new HandlerDescriptor( | |
|
97 | events.HasFlag(PromiseEventType.Success) ? handler : null, | |
|
98 | events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null, | |
|
99 | events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null, | |
|
100 | null | |
|
101 | )); | |
|
102 | } | |
|
103 | ||
|
104 | #endregion | |
|
105 | ||
|
106 | ||
|
107 | public Type PromiseType { | |
|
108 | get { | |
|
109 | return typeof(void); | |
|
110 | } | |
|
111 | } | |
|
112 | ||
|
113 | public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
114 | var promise = new Promise(); | |
|
115 | if (success != null) | |
|
116 | promise.On(Cancel, PromiseEventType.Cancelled); | |
|
117 | ||
|
118 | AddHandler(new HandlerDescriptor(success, error, cancel, promise)); | |
|
119 | ||
|
120 | return promise; | |
|
121 | } | |
|
122 | ||
|
123 | public IPromise Then(Action success, Action<Exception> error) { | |
|
124 | return Then(success, error, null); | |
|
125 | } | |
|
126 | ||
|
127 | public IPromise Then(Action success) { | |
|
128 | return Then(success, null, null); | |
|
129 | } | |
|
130 | ||
|
131 | public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
|
132 | AddHandler(new HandlerDescriptor(success, error, cancel, null)); | |
|
133 | return this; | |
|
134 | } | |
|
135 | ||
|
136 | public IPromise On(Action success, Action<Exception> error) { | |
|
137 | return On(success, error, null); | |
|
138 | } | |
|
139 | ||
|
140 | public IPromise On(Action success) { | |
|
141 | return On(success, null, null); | |
|
142 | } | |
|
143 | ||
|
144 | public IPromise On(Action handler, PromiseEventType events) { | |
|
145 | return On( | |
|
146 | events.HasFlag(PromiseEventType.Success) ? handler : null, | |
|
147 | events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null, | |
|
148 | events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null | |
|
149 | ); | |
|
150 | } | |
|
151 | ||
|
152 | public IPromise<T> Cast<T>() { | |
|
153 | throw new InvalidCastException(); | |
|
154 | } | |
|
155 | ||
|
156 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception,IPromise> cancel) { | |
|
157 | var medium = new Promise(); | |
|
158 | ||
|
159 | On( | |
|
160 | () => { | |
|
161 | if (medium.IsCancelled) | |
|
162 | return; | |
|
163 | if (chained != null) | |
|
164 | ConnectPromise(chained(), medium); | |
|
165 | }, | |
|
166 | ex => { | |
|
167 | if (medium.IsCancelled) | |
|
168 | return; | |
|
169 | if (error != null) { | |
|
170 | try { | |
|
171 | ConnectPromise(error(ex), medium); | |
|
172 | } catch (Exception ex2) { | |
|
173 | medium.Reject(ex2); | |
|
174 | } | |
|
175 | } else { | |
|
176 | medium.Reject(ex); | |
|
177 | } | |
|
178 | }, | |
|
179 | reason => { | |
|
180 | if (medium.IsCancelled) | |
|
181 | return; | |
|
182 | if (cancel != null) | |
|
183 | ConnectPromise(cancel(reason), medium); | |
|
184 | else | |
|
185 | medium.Cancel(reason); | |
|
186 | } | |
|
187 | ); | |
|
188 | ||
|
189 | if (chained != null) | |
|
190 | medium.On(Cancel, PromiseEventType.Cancelled); | |
|
191 | ||
|
192 | return medium; | |
|
193 | } | |
|
194 | ||
|
195 | static void ConnectPromise(IPromise result, Promise medium) { | |
|
196 | if (result != null) { | |
|
197 | result.On( | |
|
198 | medium.Resolve, | |
|
199 | medium.Reject, | |
|
200 | medium.Cancel | |
|
201 | ); | |
|
202 | medium.On(null,null,result.Cancel); | |
|
203 | } else { | |
|
204 | medium.Reject( | |
|
205 | new NullReferenceException( | |
|
206 | "The chained asynchronous operation returned" + | |
|
207 | " 'null' where the promise instance is expected" | |
|
208 | ) | |
|
209 | ); | |
|
210 | } | |
|
211 | } | |
|
212 | ||
|
213 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) { | |
|
214 | return Chain(chained, error, null); | |
|
215 | } | |
|
216 | ||
|
217 | public IPromise Chain(Func<IPromise> chained) { | |
|
218 | return Chain(chained, null, null); | |
|
219 | } | |
|
220 | 20 | } |
|
221 | 21 | } |
|
222 | 22 |
This diff has been collapsed as it changes many lines, (533 lines changed) Show them Hide them | |||
@@ -1,574 +1,63 | |||
|
1 | 1 | using System; |
|
2 | 2 | using System.Diagnostics; |
|
3 | using Implab.Parallels; | |
|
3 | 4 | |
|
4 | 5 | namespace Implab { |
|
5 | 6 | |
|
6 | 7 | /// <summary> |
|
7 | 8 | /// ΠΠ»Π°ΡΡ Π΄Π»Ρ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ². Π’Π°ΠΊ Π½Π°Π·ΡΠ²Π°Π΅ΠΌΠΎΠ΅ "ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅". |
|
8 | 9 | /// </summary> |
|
9 | 10 | /// <typeparam name="T">Π’ΠΈΠΏ ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌΠΎΠ³ΠΎ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°</typeparam> |
|
10 | 11 | /// <remarks> |
|
11 | 12 | /// <para>Π‘Π΅ΡΠ²ΠΈΡ ΠΏΡΠΈ ΠΎΠ±ΡΠ°ΡΠ΅Π½ΠΈΠΈ ΠΊ Π΅Π³ΠΎ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄Π°Π΅Ρ ΠΎΠ±Π΅ΡΠ°ΠΈΠ½ΠΈΠ΅ ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ, |
|
12 | 13 | /// ΠΊΠ»ΠΈΠ΅Π½Ρ ΠΏΠΎΠ»ΡΡΠΈΠ² ΡΠ°ΠΊΠΎΠ΅ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΡΠ΄ ΠΎΠ±ΡΠ°ΡΠ½ΡΡ Π²ΡΠ·ΠΎΠ²ΠΎ Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ |
|
13 | 14 | /// ΡΠΎΠ±ΡΡΠΈΠΉ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ, ΡΠΎΠ΅ΡΡΡ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»Π΅Π½ΠΈΠΈ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ².</para> |
|
14 | 15 | /// <para> |
|
15 | 16 | /// ΠΠ±Π΅ΡΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΊΠ°ΠΊ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ, ΡΠ°ΠΊ ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΎ Ρ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ. ΠΠ»Ρ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠΈ Π½Π° |
|
16 | 17 | /// Π΄Π°Π½Π½ΡΠ΅ ΡΠΎΠ±ΡΡΠΈΡ ΠΊΠ»ΠΈΠ΅Π½Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΌΠ΅ΡΠΎΠ΄Ρ <c>Then</c>. |
|
17 | 18 | /// </para> |
|
18 | 19 | /// <para> |
|
19 | 20 | /// Π‘Π΅ΡΠ²ΠΈΡ, Π² ΡΠ²ΠΎΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ, ΠΏΠΎ ΠΎΠΊΠΎΠ½ΡΠ°Π½ΠΈΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ (Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Ρ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ), |
|
20 | 21 | /// ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ ΠΌΠ΅ΡΠΎΠ΄Ρ <c>Resolve</c> Π»ΠΈΠ±ΠΎ <c>Reject</c> Π΄Π»Ρ ΠΎΠΏΠΎΠ²Π΅ΡΠ΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅ΡΠ½Π° ΠΎ |
|
21 | 22 | /// Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ. |
|
22 | 23 | /// </para> |
|
23 | 24 | /// <para> |
|
24 | 25 | /// ΠΡΠ»ΠΈ ΡΠ΅ΡΠ²Π΅Ρ ΡΡΠΏΠ΅Π» Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΠ΅ Π΅ΡΠ΅ Π΄ΠΎ ΡΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΊΠ»ΠΈΠ΅Π½Ρ Π½Π° Π½Π΅Π³ΠΎ ΠΏΠΎΠ΄ΠΏΠΈΡΠ°Π»ΡΡ, |
|
25 | 26 | /// ΡΠΎ Π² ΠΌΠΎΠΌΠ΅Π½Ρ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Π±ΡΠ΄ΡΡ Π²ΡΠ·Π²Π°Π½Ρ ΡΠΎΠΎΡΠ²Π΅ΡΡΠ²ΡΡΡΠΈΠ΅ ΡΠΎΠ±ΡΡΠΈΡ Π² ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠΌ |
|
26 | 27 | /// ΡΠ΅ΠΆΠΈΠΌΠ΅ ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ Π±ΡΠ΄Π΅Ρ ΠΎΠΏΠΎΠ²Π΅ΡΠ΅Π½ Π² Π»ΡΠ±ΠΎΠΌ ΡΠ»ΡΡΠ°Π΅. ΠΠ½Π°ΡΠ΅, ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡΡΡ Π² |
|
27 | 28 | /// ΡΠΏΠΈΡΠΎΠΊ Π² ΠΏΠΎΡΡΠ΄ΠΊΠ΅ ΠΏΠΎΠ΄ΠΏΠΈΡΠ°Π½ΠΈΡ ΠΈ Π² ΡΡΠΎΠΌ ΠΆΠ΅ ΠΏΠΎΡΡΠ΄ΠΊΠ΅ ΠΎΠ½ΠΈ Π±ΡΠ΄ΡΡ Π²ΡΠ·Π²Π°Π½Ρ ΠΏΡΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ |
|
28 | 29 | /// ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ. |
|
29 | 30 | /// </para> |
|
30 | 31 | /// <para> |
|
31 | 32 | /// ΠΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Ρ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²ΡΠ²Π°ΡΡ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ Π»ΠΈΠ±ΠΎ ΠΈΠ½ΠΈΡΠΈΠΈΡΠΎΠ²Π°ΡΡ |
|
32 | 33 | /// ΡΠ²ΡΠ·Π°Π½Π½ΡΠ΅ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ ΡΠ°ΠΊΠΆΠ΅ Π²ΠΎΠ·Π²ΡΠ°ΡΠ°ΡΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΡΠ»Π΅Π΄ΡΠ΅Ρ |
|
33 | 34 | /// ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΡΡ ΡΠΎΡΠΌΡ ΠΌΠ΅ΡΠΎΠ΄Π΅ <c>Then</c>. |
|
34 | 35 | /// </para> |
|
35 | 36 | /// <para> |
|
36 | 37 | /// Π’Π°ΠΊΠΆΠ΅ Ρ ΠΎΡΠΎΡΠΈΠΌ ΠΏΡΠ°Π²ΠΈΠ»ΠΎΠΌ ΡΠ²Π»ΡΠ΅ΡΡΡ ΡΠΎ, ΡΡΠΎ <c>Resolve</c> ΠΈ <c>Reject</c> Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²ΡΠ·ΡΠ²Π°ΡΡ |
|
37 | 38 | /// ΡΠΎΠ»ΡΠΊΠΎ ΠΈΠ½ΠΈΡΠΈΠ°ΡΠΎΡ ΠΎΠ±Π΅ΡΠ°Π½ΠΈΡ ΠΈΠ½Π°ΡΠ΅ ΠΌΠΎΠ³ΡΡ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΡΡΡ ΠΏΡΠΎΡΠΈΠ²ΠΎΡΠ΅ΡΠΈΡ. |
|
38 | 39 | /// </para> |
|
39 | 40 | /// </remarks> |
|
40 |
public class Promise<T> : AbstractPromise< |
|
|
41 | ||
|
42 | class StubDeferred : IDeferred, IDeferred<T> { | |
|
43 | public static readonly StubDeferred instance = new StubDeferred(); | |
|
44 | ||
|
45 | StubDeferred() { | |
|
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 | } | |
|
73 | ||
|
74 | class RemapDescriptor<T2> : IDeferred<T> { | |
|
75 | readonly Func<T,T2> m_remap; | |
|
76 | readonly Func<Exception, T2> m_failed; | |
|
77 | readonly Func<Exception, T2> m_cancel; | |
|
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 | } | |
|
41 | public class Promise<T> : AbstractPromise<T>, IDeferred<T> { | |
|
87 | 42 | |
|
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 | |
|
43 | public static IPromise<T> FromResult(T value) { | |
|
44 | var p = new Promise<T>(); | |
|
45 | p.Resolve(value); | |
|
46 | return p; | |
|
135 | 47 | } |
|
136 | 48 | |
|
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 | |
|
49 | public static IPromise<T> FromException(Exception error) { | |
|
50 | var p = new Promise<T>(); | |
|
51 | p.Reject(error); | |
|
52 | return p; | |
|
189 | 53 | } |
|
190 | 54 | |
|
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 | 55 | public virtual void Resolve(T value) { |
|
324 |
|
|
|
325 | m_result = value; | |
|
326 | EndSetResult(); | |
|
327 | } | |
|
56 | SetResult(value); | |
|
328 | 57 | } |
|
329 | 58 | |
|
330 | 59 | public void Reject(Exception error) { |
|
331 | 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 | } |
General Comments 0
You need to be logged in to leave comments.
Login now