248
|
1 using System;
|
|
2 using System.Collections.Generic;
|
|
3 using System.Diagnostics;
|
|
4 using System.Reflection;
|
|
5 using System.Threading.Tasks;
|
|
6 using Implab.Parallels;
|
|
7
|
|
8 namespace Implab {
|
|
9 public class Promise : AbstractEvent<IResolvable>, IPromise {
|
|
10 public static IDispatcher DefaultDispatcher {
|
|
11 get {
|
|
12 return ThreadPoolDispatcher.Instance;
|
|
13 }
|
|
14 }
|
|
15
|
|
16 class ResolvableSignal : IResolvable {
|
|
17 public Signal Signal { get; private set; }
|
|
18 public ResolvableSignal() {
|
|
19 Signal = new Signal();
|
|
20 }
|
|
21
|
|
22
|
|
23 public void Reject(Exception error) {
|
|
24 Signal.Set();
|
|
25 }
|
|
26
|
|
27 public void Resolve() {
|
|
28 Signal.Set();
|
|
29 }
|
|
30 }
|
|
31
|
|
32 PromiseState m_state;
|
|
33
|
|
34 Exception m_error;
|
|
35
|
|
36 public bool IsRejected {
|
|
37 get {
|
|
38 return m_state == PromiseState.Rejected;
|
|
39 }
|
|
40 }
|
|
41
|
|
42 public bool IsFulfilled {
|
|
43 get {
|
|
44 return m_state == PromiseState.Fulfilled;
|
|
45 }
|
|
46 }
|
|
47
|
|
48 public Exception RejectReason {
|
|
49 get {
|
|
50 return m_error;
|
|
51 }
|
|
52 }
|
|
53
|
|
54 internal Promise() {
|
|
55
|
|
56 }
|
|
57
|
|
58 internal void ResolvePromise() {
|
|
59 if (BeginTransit()) {
|
|
60 m_state = PromiseState.Fulfilled;
|
|
61 CompleteTransit();
|
|
62 }
|
|
63 }
|
|
64
|
|
65 internal void RejectPromise(Exception reason) {
|
|
66 if (BeginTransit()) {
|
|
67 m_error = reason;
|
|
68 m_state = PromiseState.Rejected;
|
|
69 CompleteTransit();
|
|
70 }
|
|
71 }
|
|
72
|
|
73
|
|
74 #region implemented abstract members of AbstractPromise
|
|
75
|
|
76 protected override void SignalHandler(IResolvable handler) {
|
|
77 switch (m_state) {
|
|
78 case PromiseState.Fulfilled:
|
|
79 handler.Resolve();
|
|
80 break;
|
|
81 case PromiseState.Rejected:
|
|
82 handler.Reject(RejectReason);
|
|
83 break;
|
|
84 default:
|
|
85 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
|
|
86 }
|
|
87 }
|
|
88
|
|
89 protected void WaitResult(int timeout) {
|
|
90 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
|
|
91 throw new TimeoutException();
|
|
92 }
|
|
93
|
|
94 protected Signal GetFulfillSignal() {
|
|
95 var next = new ResolvableSignal();
|
|
96 Then(next);
|
|
97 return next.Signal;
|
|
98 }
|
|
99
|
|
100 #endregion
|
|
101
|
|
102
|
|
103 public Type ResultType {
|
|
104 get {
|
|
105 return typeof(void);
|
|
106 }
|
|
107 }
|
|
108
|
|
109
|
|
110 protected void Rethrow() {
|
|
111 Debug.Assert(m_error != null);
|
|
112 if (m_error is OperationCanceledException)
|
|
113 throw new OperationCanceledException("Operation cancelled", m_error);
|
|
114 else
|
|
115 throw new TargetInvocationException(m_error);
|
|
116 }
|
|
117
|
|
118 public void Then(IResolvable next) {
|
|
119 AddHandler(next);
|
|
120 }
|
|
121
|
|
122 public IPromise<T> Cast<T>() {
|
|
123 throw new InvalidCastException();
|
|
124 }
|
|
125
|
|
126 public void Join() {
|
|
127 WaitResult(-1);
|
|
128 if (IsRejected)
|
|
129 Rethrow();
|
|
130 }
|
|
131
|
|
132 public void Join(int timeout) {
|
|
133 WaitResult(timeout);
|
|
134 if (IsRejected)
|
|
135 Rethrow();
|
|
136 }
|
|
137
|
|
138 public static ResolvedPromise Resolve() {
|
|
139 return new ResolvedPromise();
|
|
140 }
|
|
141
|
|
142 public static ResolvedPromise<T> Resolve<T>(T result) {
|
|
143 return new ResolvedPromise<T>(result);
|
|
144 }
|
|
145
|
|
146 public static RejectedPromise Reject(Exception reason) {
|
|
147 return new RejectedPromise(reason);
|
|
148 }
|
|
149
|
|
150 public static RejectedPromise<T> Reject<T>(Exception reason) {
|
|
151 return new RejectedPromise<T>(reason);
|
|
152 }
|
|
153
|
|
154 public static IPromise Create(PromiseExecutor executor) {
|
|
155 Safe.ArgumentNotNull(executor, nameof(executor));
|
|
156
|
|
157 var p = new Promise();
|
|
158 var d = new Deferred(p, DefaultDispatcher);
|
|
159
|
|
160 try {
|
|
161 executor(d);
|
|
162 } catch (Exception e) {
|
|
163 d.Reject(e);
|
|
164 }
|
|
165
|
|
166 return d.Promise;
|
|
167 }
|
|
168
|
|
169 public static IPromise<T> Create<T>(PromiseExecutor<T> executor) {
|
|
170 Safe.ArgumentNotNull(executor, nameof(executor));
|
|
171
|
|
172 var p = new Promise<T>();
|
|
173 var d = new Deferred<T>(p, DefaultDispatcher);
|
|
174
|
|
175 try {
|
|
176 executor(d);
|
|
177 } catch (Exception e) {
|
|
178 d.Reject(e);
|
|
179 }
|
|
180
|
|
181 return d.Promise;
|
|
182 }
|
|
183
|
|
184 public static IPromise All(IEnumerable<IPromise> promises) {
|
|
185 var d = new Deferred(DefaultDispatcher);
|
|
186 var all = new PromiseAll(d);
|
|
187 foreach (var promise in promises) {
|
|
188 all.AddPromise(promise);
|
|
189 if (all.Done)
|
|
190 break;
|
|
191 }
|
|
192 all.Complete();
|
|
193 return all.ResultPromise;
|
|
194 }
|
|
195
|
|
196 public static IPromise<T[]> All<T>(IEnumerable<IPromise<T>> promises, Func<T, IPromise> cleanup, Action cancel) {
|
|
197 var d = new Deferred<T[]>(DefaultDispatcher);
|
|
198 var all = new PromiseAll<T>(d, cleanup, cancel);
|
|
199 foreach (var promise in promises) {
|
|
200 all.AddPromise(promise);
|
|
201 if (all.Done)
|
|
202 break;
|
|
203 }
|
|
204 all.Complete();
|
|
205 return all.ResultPromise;
|
|
206 }
|
|
207 }
|
|
208 }
|
|
209
|