comparison Implab/PromiseT.cs @ 144:8c0b95069066 v2

DRAFT: refactoring
author cin
date Fri, 06 Mar 2015 15:45:26 +0300
parents f75cfa58e3d4
children e03ccec4a08d
comparison
equal deleted inserted replaced
143:16f926ee499d 144:8c0b95069066
1 using System; 1 using System;
2 using System.Diagnostics; 2 using System.Diagnostics;
3 using Implab.Parallels;
3 4
4 namespace Implab { 5 namespace Implab {
5 6
6 /// <summary> 7 /// <summary>
7 /// Класс для асинхронного получения результатов. Так называемое "обещание". 8 /// Класс для асинхронного получения результатов. Так называемое "обещание".
35 /// <para> 36 /// <para>
36 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать 37 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать
37 /// только инициатор обещания иначе могут возникнуть противоречия. 38 /// только инициатор обещания иначе могут возникнуть противоречия.
38 /// </para> 39 /// </para>
39 /// </remarks> 40 /// </remarks>
40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> { 41 public class Promise<T> : AbstractPromise<T>, IDeferred<T> {
41 42
42 class StubDeferred : IDeferred, IDeferred<T> { 43 public static IPromise<T> FromResult(T value) {
43 public static readonly StubDeferred instance = new StubDeferred(); 44 var p = new Promise<T>();
44 45 p.Resolve(value);
45 StubDeferred() { 46 return p;
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 } 47 }
73 48
74 class RemapDescriptor<T2> : IDeferred<T> { 49 public static IPromise<T> FromException(Exception error) {
75 readonly Func<T,T2> m_remap; 50 var p = new Promise<T>();
76 readonly Func<Exception, T2> m_failed; 51 p.Reject(error);
77 readonly Func<Exception, T2> m_cancel; 52 return p;
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 }
87
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
135 } 53 }
136 54
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
189 }
190
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 public virtual void Resolve(T value) { 55 public virtual void Resolve(T value) {
324 if (BeginSetResult()) { 56 SetResult(value);
325 m_result = value;
326 EndSetResult();
327 }
328 } 57 }
329 58
330 public void Reject(Exception error) { 59 public void Reject(Exception error) {
331 SetError(error); 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 }