248
|
1 using System;
|
|
2 using System.Collections.Generic;
|
|
3 using System.Linq;
|
|
4 using System.Threading;
|
|
5
|
|
6 namespace Implab {
|
|
7 class PromiseAll<T> : IResolvable {
|
|
8
|
|
9 int m_count;
|
|
10
|
|
11 readonly List<IPromise<T>> m_promises = new List<IPromise<T>>();
|
|
12
|
|
13 readonly Deferred<T[]> m_deferred;
|
|
14
|
|
15 IPromise<T[]> m_result;
|
|
16
|
|
17 readonly Func<T, IPromise> m_cleanup;
|
|
18
|
|
19 readonly Action m_cancel;
|
|
20
|
|
21 public bool Done {
|
|
22 get { return m_deferred.Promise.IsResolved && m_cleanup == null; }
|
|
23 }
|
|
24
|
|
25 public IPromise<T[]> ResultPromise {
|
|
26 get { return m_result; }
|
|
27 }
|
|
28
|
|
29 public void AddPromise(IPromise<T> promise) {
|
|
30 Interlocked.Increment(ref m_count);
|
|
31 promise.Then(this);
|
|
32 }
|
|
33
|
|
34 public PromiseAll(Deferred<T[]> deferred, Func<T, IPromise> cleanup, Action cancel) {
|
|
35 m_deferred = deferred;
|
|
36 m_cancel = cancel;
|
|
37 m_cleanup = cleanup;
|
|
38 }
|
|
39
|
|
40 public void Resolve() {
|
|
41 if (Interlocked.Decrement(ref m_count) == 0)
|
|
42 m_deferred.Resolve(GetResults());
|
|
43 }
|
|
44
|
|
45 public void Reject(Exception error) {
|
|
46 m_deferred.Reject(error);
|
|
47 }
|
|
48
|
|
49 public void Complete() {
|
|
50 if (m_cancel != null || m_cleanup != null)
|
|
51 m_result = m_deferred.Promise.Catch(CleanupResults);
|
|
52 else
|
|
53 m_result = m_deferred.Promise;
|
|
54 }
|
|
55
|
|
56 IPromise<T[]> CleanupResults(Exception reason) {
|
|
57 var errors = new List<Exception>();
|
|
58 errors.Add(reason);
|
|
59
|
|
60 if (m_cancel != null)
|
|
61 try {
|
|
62 m_cancel();
|
|
63 } catch (Exception e) {
|
|
64 errors.Add(e);
|
|
65 }
|
|
66
|
|
67 if (m_cleanup != null) {
|
|
68 return Promise.All(
|
|
69 m_promises.Select(p => p
|
|
70 .Then(m_cleanup, e => { })
|
|
71 .Catch(e => {
|
|
72 errors.Add(e);
|
|
73 })
|
|
74 )
|
|
75 ).Then<T[]>(new Func<T[]>(() => {
|
|
76 throw new AggregateException(errors);
|
|
77 }), (Func<Exception, T[]>)null);
|
|
78 } else {
|
|
79 return Promise.Reject<T[]>(errors.Count > 1 ? new AggregateException(errors) : reason);
|
|
80 }
|
|
81 }
|
|
82
|
|
83 T[] GetResults() {
|
|
84 var results = new T[m_promises.Count];
|
|
85 for (var i = 0; i < results.Length; i++)
|
|
86 results[i] = m_promises[i].Join();
|
|
87 return results;
|
|
88 }
|
|
89 }
|
|
90 } |