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 }