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