Mercurial > pub > ImplabNet
comparison Implab/PromiseT.cs @ 119:2573b562e328 v2
Promises rewritten, added improved version of AsyncQueue
author | cin |
---|---|
date | Sun, 11 Jan 2015 19:13:02 +0300 |
parents | |
children | 671f60cd0250 |
comparison
equal
deleted
inserted
replaced
118:e046a94eecb1 | 119:2573b562e328 |
---|---|
1 using System; | |
2 using System.Diagnostics; | |
3 | |
4 namespace Implab { | |
5 | |
6 /// <summary> | |
7 /// Класс для асинхронного получения результатов. Так называемое "обещание". | |
8 /// </summary> | |
9 /// <typeparam name="T">Тип получаемого результата</typeparam> | |
10 /// <remarks> | |
11 /// <para>Сервис при обращении к его методу дает обещаиние о выполнении операции, | |
12 /// клиент получив такое обещание может установить ряд обратных вызово для получения | |
13 /// событий выполнения обещания, тоесть завершения операции и предоставлении результатов.</para> | |
14 /// <para> | |
15 /// Обещение может быть как выполнено, так и выполнено с ошибкой. Для подписки на | |
16 /// данные события клиент должен использовать методы <c>Then</c>. | |
17 /// </para> | |
18 /// <para> | |
19 /// Сервис, в свою очередь, по окончанию выполнения операции (возможно с ошибкой), | |
20 /// использует методы <c>Resolve</c> либо <c>Reject</c> для оповещения клиетна о | |
21 /// выполнении обещания. | |
22 /// </para> | |
23 /// <para> | |
24 /// Если сервер успел выполнить обещание еще до того, как клиент на него подписался, | |
25 /// то в момент подписки клиента будут вызваны соответсвующие события в синхронном | |
26 /// режиме и клиент будет оповещен в любом случае. Иначе, обработчики добавляются в | |
27 /// список в порядке подписания и в этом же порядке они будут вызваны при выполнении | |
28 /// обещания. | |
29 /// </para> | |
30 /// <para> | |
31 /// Обрабатывая результаты обещания можно преобразовывать результаты либо инициировать | |
32 /// связанные асинхронные операции, которые также возвращают обещания. Для этого следует | |
33 /// использовать соответствующую форму методе <c>Then</c>. | |
34 /// </para> | |
35 /// <para> | |
36 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать | |
37 /// только инициатор обещания иначе могут возникнуть противоречия. | |
38 /// </para> | |
39 /// </remarks> | |
40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> { | |
41 | |
42 class StubDeferred : 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 Reject(Exception error) { | |
54 } | |
55 | |
56 #endregion | |
57 | |
58 #region ICancellable implementation | |
59 | |
60 public void Cancel() { | |
61 } | |
62 | |
63 #endregion | |
64 | |
65 | |
66 } | |
67 | |
68 class RemapDescriptor<T2> : IDeferred<T> { | |
69 readonly Func<T,T2> m_remap; | |
70 readonly Func<Exception,T2> m_failed; | |
71 readonly Func<T2> m_cancel; | |
72 readonly IDeferred<T2> m_deferred; | |
73 | |
74 public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<T2> cancel, IDeferred<T2> deferred ) { | |
75 Debug.Assert(deferred != null); | |
76 m_remap = remap; | |
77 m_failed = failed; | |
78 m_cancel = cancel; | |
79 m_deferred = deferred; | |
80 } | |
81 | |
82 | |
83 | |
84 #region IDeferred implementation | |
85 | |
86 public void Resolve(T value) { | |
87 if (m_remap != null) { | |
88 try { | |
89 m_deferred.Resolve(m_remap(value)); | |
90 } catch (Exception ex) { | |
91 Reject(ex); | |
92 } | |
93 } | |
94 } | |
95 | |
96 public void Reject(Exception error) { | |
97 if (m_failed != null) { | |
98 try { | |
99 m_deferred.Resolve(m_failed(error)); | |
100 } catch (Exception ex) { | |
101 m_deferred.Reject(ex); | |
102 } | |
103 } else { | |
104 m_deferred.Reject(error); | |
105 } | |
106 } | |
107 | |
108 | |
109 #endregion | |
110 | |
111 #region ICancellable implementation | |
112 | |
113 public void Cancel() { | |
114 if (m_cancel != null) { | |
115 try { | |
116 m_deferred.Resolve(m_cancel()); | |
117 } catch (Exception ex) { | |
118 Reject(ex); | |
119 } | |
120 } else { | |
121 m_deferred.Cancel(); | |
122 } | |
123 } | |
124 | |
125 #endregion | |
126 } | |
127 | |
128 class ListenerDescriptor : IDeferred<T> { | |
129 readonly Action m_handler; | |
130 readonly PromiseEventType m_events; | |
131 | |
132 public ListenerDescriptor(Action handler, PromiseEventType events) { | |
133 Debug.Assert(handler != null); | |
134 | |
135 m_handler = handler; | |
136 m_events = events; | |
137 } | |
138 | |
139 #region IDeferred implementation | |
140 | |
141 public void Resolve(T value) { | |
142 if (m_events.HasFlag(PromiseEventType.Success)) { | |
143 try { | |
144 m_handler(); | |
145 // Analysis disable once EmptyGeneralCatchClause | |
146 } catch { | |
147 } | |
148 } | |
149 } | |
150 | |
151 public void Reject(Exception error) { | |
152 if (m_events.HasFlag(PromiseEventType.Error)){ | |
153 try { | |
154 m_handler(); | |
155 // Analysis disable once EmptyGeneralCatchClause | |
156 } catch { | |
157 } | |
158 } | |
159 } | |
160 | |
161 #endregion | |
162 | |
163 #region ICancellable implementation | |
164 | |
165 public void Cancel() { | |
166 if (m_events.HasFlag(PromiseEventType.Cancelled)){ | |
167 try { | |
168 m_handler(); | |
169 // Analysis disable once EmptyGeneralCatchClause | |
170 } catch { | |
171 } | |
172 } | |
173 } | |
174 | |
175 #endregion | |
176 } | |
177 | |
178 class ValueEventDescriptor : IDeferred<T> { | |
179 readonly Action<T> m_success; | |
180 readonly Action<Exception> m_failed; | |
181 readonly Action m_cancelled; | |
182 readonly IDeferred<T> m_deferred; | |
183 | |
184 public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action cancelled, IDeferred<T> deferred) { | |
185 Debug.Assert(deferred != null); | |
186 | |
187 m_success = success; | |
188 m_failed = failed; | |
189 m_cancelled = cancelled; | |
190 m_deferred = deferred; | |
191 } | |
192 | |
193 #region IDeferred implementation | |
194 | |
195 public void Resolve(T value) { | |
196 if (m_success != null) { | |
197 try { | |
198 m_success(value); | |
199 m_deferred.Resolve(value); | |
200 } catch (Exception ex) { | |
201 Reject(ex); | |
202 } | |
203 } | |
204 } | |
205 | |
206 public void Reject(Exception error) { | |
207 if (m_failed != null) { | |
208 try { | |
209 m_failed(error); | |
210 m_deferred.Resolve(default(T)); | |
211 } catch(Exception ex) { | |
212 m_deferred.Reject(ex); | |
213 } | |
214 } else { | |
215 m_deferred.Reject(error); | |
216 } | |
217 } | |
218 | |
219 #endregion | |
220 | |
221 #region ICancellable implementation | |
222 | |
223 public void Cancel() { | |
224 if (m_cancelled != null) { | |
225 try { | |
226 m_cancelled(); | |
227 m_deferred.Resolve(default(T)); | |
228 } catch(Exception ex) { | |
229 Reject(ex); | |
230 } | |
231 } else { | |
232 m_deferred.Cancel(); | |
233 } | |
234 } | |
235 | |
236 #endregion | |
237 } | |
238 | |
239 public class EventDescriptor : IDeferred<T> { | |
240 readonly Action m_success; | |
241 readonly Action<Exception> m_failed; | |
242 readonly Action m_cancelled; | |
243 readonly IDeferred<T> m_deferred; | |
244 | |
245 public EventDescriptor(Action success, Action<Exception> failed, Action cancelled, IDeferred<T> deferred) { | |
246 Debug.Assert(deferred != null); | |
247 | |
248 m_success = success; | |
249 m_failed = failed; | |
250 m_cancelled = cancelled; | |
251 m_deferred = deferred; | |
252 } | |
253 | |
254 #region IDeferred implementation | |
255 | |
256 public void Resolve(T value) { | |
257 if (m_success != null) { | |
258 try { | |
259 m_success(); | |
260 m_deferred.Resolve(value); | |
261 } catch (Exception ex) { | |
262 Reject(ex); | |
263 } | |
264 } | |
265 } | |
266 | |
267 public void Reject(Exception error) { | |
268 if (m_failed != null) { | |
269 try { | |
270 m_failed(error); | |
271 m_deferred.Resolve(default(T)); | |
272 }catch (Exception ex) | |
273 { | |
274 m_deferred.Reject(ex); | |
275 } | |
276 } else { | |
277 m_deferred.Reject(error); | |
278 } | |
279 | |
280 } | |
281 | |
282 #endregion | |
283 | |
284 #region ICancellable implementation | |
285 | |
286 public void Cancel() { | |
287 if (m_cancelled != null) { | |
288 try { | |
289 m_cancelled(); | |
290 m_deferred.Resolve(default(T)); | |
291 } catch (Exception ex) { | |
292 Reject(ex); | |
293 } | |
294 } else { | |
295 m_deferred.Cancel(); | |
296 } | |
297 } | |
298 | |
299 #endregion | |
300 } | |
301 | |
302 T m_result; | |
303 | |
304 public virtual void Resolve(T value) { | |
305 BeginSetResult(); | |
306 m_result = value; | |
307 EndSetResult(); | |
308 } | |
309 | |
310 public void Reject(Exception error) { | |
311 SetError(error); | |
312 } | |
313 | |
314 public Type PromiseType { | |
315 get { | |
316 return typeof(T); | |
317 } | |
318 } | |
319 | |
320 public new T Join() { | |
321 WaitResult(-1); | |
322 return m_result; | |
323 } | |
324 public new T Join(int timeout) { | |
325 WaitResult(timeout); | |
326 return m_result; | |
327 } | |
328 | |
329 public IPromise<T> On(Action<T> success, Action<Exception> error, Action cancel) { | |
330 AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance)); | |
331 return this; | |
332 } | |
333 | |
334 public IPromise<T> On(Action<T> success, Action<Exception> error) { | |
335 AddHandler(new ValueEventDescriptor(success, error, null, StubDeferred.instance)); | |
336 return this; | |
337 } | |
338 | |
339 public IPromise<T> On(Action<T> success) { | |
340 AddHandler(new ValueEventDescriptor(success, null, null, StubDeferred.instance)); | |
341 return this; | |
342 } | |
343 | |
344 public IPromise<T> On(Action handler, PromiseEventType events) { | |
345 Listen(events, handler); | |
346 return this; | |
347 } | |
348 | |
349 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<T2> cancel) { | |
350 var promise = new Promise<T2>(); | |
351 AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise)); | |
352 return promise; | |
353 } | |
354 | |
355 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) { | |
356 var promise = new Promise<T2>(); | |
357 AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise)); | |
358 return promise; | |
359 } | |
360 | |
361 public IPromise<T2> Then<T2>(Func<T, T2> mapper) { | |
362 var promise = new Promise<T2>(); | |
363 AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise)); | |
364 return promise; | |
365 } | |
366 | |
367 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<IPromise<T2>> cancel) { | |
368 // this promise will be resolved when an asyc operation is started | |
369 var promise = new Promise<IPromise<T2>>(); | |
370 | |
371 AddHandler(new RemapDescriptor<IPromise<T2>>( | |
372 chained, | |
373 error, | |
374 cancel, | |
375 promise | |
376 )); | |
377 | |
378 var medium = new Promise<T2>(); | |
379 | |
380 if (chained != null) | |
381 medium.On(Cancel, PromiseEventType.Cancelled); | |
382 | |
383 // we need to connect started async operation with the medium | |
384 // if the async operation hasn't been started by the some reason | |
385 // report is to the medium | |
386 promise.On( | |
387 result => ConnectPromise<T2>(result, medium), | |
388 medium.Reject, | |
389 medium.Cancel | |
390 ); | |
391 | |
392 return medium; | |
393 } | |
394 | |
395 static void ConnectPromise<T2>(IPromise<T2> result, Promise<T2> medium) { | |
396 if (result != null) { | |
397 result.On( | |
398 medium.Resolve, | |
399 medium.Reject, | |
400 () => medium.Reject(new OperationCanceledException()) | |
401 ); | |
402 medium.On(result.Cancel, PromiseEventType.Cancelled); | |
403 } else { | |
404 medium.Reject( | |
405 new NullReferenceException( | |
406 "The chained asynchronous operation returned" + | |
407 " 'null' where the promise instance is expected" | |
408 ) | |
409 ); | |
410 } | |
411 } | |
412 | |
413 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error) { | |
414 return Chain(chained, error, null); | |
415 } | |
416 | |
417 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained) { | |
418 return Chain(chained, null, null); | |
419 } | |
420 | |
421 public IPromise<T2> Error<T2>(Func<Exception, T2> error) { | |
422 var promise = new Promise<T2>(); | |
423 if (error != null) | |
424 On( | |
425 (Action<T>)null, | |
426 ex => { | |
427 try { | |
428 promise.Resolve(error(ex)); | |
429 } catch (Exception ex2) { | |
430 promise.Reject(ex2); | |
431 } | |
432 } | |
433 ); | |
434 else | |
435 Listen(PromiseEventType.Error, () => promise.Resolve(default(T2))); | |
436 return promise; | |
437 } | |
438 | |
439 public IPromise<T2> Cancelled<T2>(Func<T2> handler) { | |
440 var promise = new Promise<T2>(); | |
441 if (handler != null) | |
442 On( | |
443 (Action<T>)null, | |
444 null, | |
445 () => { | |
446 try { | |
447 promise.Resolve(handler()); | |
448 } catch (Exception ex) { | |
449 promise.Reject(ex); | |
450 } | |
451 }); | |
452 else | |
453 Listen(PromiseEventType.Cancelled, () => promise.Resolve(default(T2))); | |
454 return promise; | |
455 } | |
456 | |
457 public IPromise Then(Action success, Action<Exception> error, Action cancel) { | |
458 var promise = new Promise<T>(); | |
459 if (success != null) | |
460 promise.On(Cancel, PromiseEventType.Cancelled); | |
461 | |
462 AddHandler(new EventDescriptor(success, error, cancel, promise)); | |
463 | |
464 return promise; | |
465 } | |
466 | |
467 public IPromise Then(Action success, Action<Exception> error) { | |
468 return Then(success, error, null); | |
469 } | |
470 | |
471 public IPromise Then(Action success) { | |
472 return Then(success, null, null); | |
473 } | |
474 | |
475 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<IPromise> cancel) { | |
476 var promise = new Promise<IPromise>(); | |
477 | |
478 AddHandler( | |
479 new RemapDescriptor<IPromise>( | |
480 x => chained(), | |
481 error, | |
482 cancel, | |
483 promise | |
484 ) | |
485 ); | |
486 | |
487 var medium = new Promise(); | |
488 if (chained != null) | |
489 medium.On(Cancel, PromiseEventType.Cancelled); | |
490 | |
491 promise.On( | |
492 result => ConnectPromise(result, medium), | |
493 medium.Reject, | |
494 medium.Cancel | |
495 ); | |
496 | |
497 return medium; | |
498 } | |
499 | |
500 static void ConnectPromise(IPromise result, Promise medium) { | |
501 if (result != null) { | |
502 result.On( | |
503 medium.Resolve, | |
504 medium.Reject, | |
505 () => medium.Reject(new OperationCanceledException()) | |
506 ); | |
507 medium.On(result.Cancel, PromiseEventType.Cancelled); | |
508 } else { | |
509 medium.Reject( | |
510 new NullReferenceException( | |
511 "The chained asynchronous operation returned" + | |
512 " 'null' where the promise instance is expected" | |
513 ) | |
514 ); | |
515 } | |
516 } | |
517 | |
518 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) { | |
519 return Chain(chained, error, null); | |
520 } | |
521 | |
522 public IPromise Chain(Func<IPromise> chained) { | |
523 return Chain(chained, null, null); | |
524 } | |
525 | |
526 public IPromise On(Action success, Action<Exception> error, Action cancel) { | |
527 AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance)); | |
528 return this; | |
529 } | |
530 | |
531 public IPromise On(Action success, Action<Exception> error) { | |
532 AddHandler(new EventDescriptor(success, error, null, StubDeferred.instance)); | |
533 return this; | |
534 } | |
535 | |
536 public IPromise On(Action success) { | |
537 Listen(PromiseEventType.Success, success); | |
538 return this; | |
539 } | |
540 | |
541 IPromise IPromise.On(Action handler, PromiseEventType events) { | |
542 Listen(events,handler); | |
543 return this; | |
544 } | |
545 | |
546 public IPromise Error(Action<Exception> error) { | |
547 var promise = new Promise(); | |
548 if (error != null) | |
549 On( | |
550 (Action<T>)null, | |
551 ex => { | |
552 try { | |
553 error(ex); | |
554 promise.Resolve(); | |
555 } catch (Exception ex2) { | |
556 promise.Reject(ex2); | |
557 } | |
558 }); | |
559 else | |
560 Listen(PromiseEventType.Error, promise.Resolve); | |
561 return promise; | |
562 } | |
563 | |
564 public IPromise Cancelled(Action handler) { | |
565 var promise = new Promise(); | |
566 if (handler != null) | |
567 On( | |
568 (Action<T>)null, | |
569 null, | |
570 () => { | |
571 try { | |
572 handler(); | |
573 promise.Resolve(); | |
574 } catch (Exception ex) { | |
575 promise.Reject(ex); | |
576 } | |
577 }); | |
578 else | |
579 Listen(PromiseEventType.Cancelled, promise.Resolve); | |
580 return promise; | |
581 } | |
582 | |
583 public IPromise<T2> Cast<T2>() { | |
584 return (IPromise<T2>)this; | |
585 } | |
586 | |
587 #region implemented abstract members of AbstractPromise | |
588 | |
589 protected override void SignalSuccess(IDeferred<T> handler) { | |
590 handler.Resolve(m_result); | |
591 } | |
592 | |
593 protected override void SignalError(IDeferred<T> handler, Exception error) { | |
594 handler.Reject(error); | |
595 } | |
596 | |
597 protected override void SignalCancelled(IDeferred<T> handler) { | |
598 handler.Cancel(); | |
599 } | |
600 | |
601 protected override void Listen(PromiseEventType events, Action handler) { | |
602 if (handler != null) | |
603 AddHandler(new ListenerDescriptor(handler, events)); | |
604 } | |
605 | |
606 #endregion | |
607 | |
608 public static IPromise<T> ResultToPromise(T value) { | |
609 var p = new Promise<T>(); | |
610 p.Resolve(value); | |
611 return p; | |
612 } | |
613 | |
614 public static IPromise<T> ExceptionToPromise(Exception error) { | |
615 var p = new Promise<T>(); | |
616 p.Reject(error); | |
617 return p; | |
618 } | |
619 | |
620 } | |
621 } |