##// END OF EJS Templates
Bound promise to CancellationToken...
cin -
r209:a867536c68fc v2
parent child
Show More
@@ -1,24 +1,30
1 1 namespace Implab.Components {
2 2
3 3 public enum ExecutionState {
4 4 Undefined = 0,
5 5
6 6 Created,
7 7
8 8 Initializing,
9 9
10 10 Ready,
11 11
12 12 Starting,
13 13
14 14 Running,
15 15
16 Suspending,
17
18 Suspended,
19
20 Resuming,
21
16 22 Stopping,
17 23
18 24 Failed,
19 25
20 26 Disposed,
21 27
22 28 Last = Disposed
23 29 }
24 30 } No newline at end of file
@@ -1,448 +1,475
1 1 using System.Threading;
2 2 using System;
3 3 using Implab.Diagnostics;
4 4 using System.Collections.Generic;
5 5 using System.Linq;
6 6
7 7 namespace Implab {
8 8 public static class PromiseExtensions {
9 9 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
10 10 Safe.ArgumentNotNull(that, "that");
11 11 var context = SynchronizationContext.Current;
12 12 if (context == null)
13 13 return that;
14 14
15 15 var p = new SyncContextPromise<T>(context);
16 16 p.CancellationRequested(that.Cancel);
17 17
18 18 that.On(
19 19 p.Resolve,
20 20 p.Reject,
21 21 p.CancelOperation
22 22 );
23 23 return p;
24 24 }
25 25
26 26 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
27 27 Safe.ArgumentNotNull(that, "that");
28 28 Safe.ArgumentNotNull(context, "context");
29 29
30 30 var p = new SyncContextPromise<T>(context);
31 31 p.CancellationRequested(that.Cancel);
32 32
33 33 that.On(
34 34 p.Resolve,
35 35 p.Reject,
36 36 p.CancelOperation
37 37 );
38 38 return p;
39 39 }
40 40
41 41 /// <summary>
42 42 /// Ensures the dispatched.
43 43 /// </summary>
44 44 /// <returns>The dispatched.</returns>
45 45 /// <param name="that">That.</param>
46 46 /// <param name="head">Head.</param>
47 47 /// <param name="cleanup">Cleanup.</param>
48 48 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
49 49 /// <typeparam name="T">The 2nd type parameter.</typeparam>
50 50 public static TPromise EnsureDispatched<TPromise, T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise {
51 51 Safe.ArgumentNotNull(that, "that");
52 52 Safe.ArgumentNotNull(head, "head");
53 53
54 54 that.On(() => head.On(cleanup), PromiseEventType.Cancelled);
55 55
56 56 return that;
57 57 }
58 58
59 59 /// <summary>
60 60 /// Adds a cancellation point to the chain of promises. When a cancellation request reaches the cancellation point the operation is
61 61 /// cancelled immediatelly, and the request is passed towards. If the operation at the higher level can not be cancelled is't result
62 62 /// will be collected with <paramref name="cleanup"/> callback.
63 63 /// </summary>
64 64 /// <typeparam name="T">The type of the promise result.</typeparam>
65 65 /// <param name="that">The promise to which the cancellation point should be attached.</param>
66 66 /// <param name="cleanup">The callback which is used to cleanup the result of the operation if the cancellation point is cancelled already.</param>
67 67 /// <returns>The promise</returns>
68 68 public static IPromise<T> CancellationPoint<T>(this IPromise<T> that, Action<T> cleanup) {
69 69 var meduim = new Promise<T>();
70 70
71 71 that.On(meduim.Resolve, meduim.Reject, meduim.CancelOperation);
72 72
73 73 meduim.CancellationRequested(that.Cancel);
74 74 meduim.CancellationRequested(meduim.CancelOperation);
75 75
76 76 if (cleanup != null)
77 77 meduim.On((Action<T>)null, null, (e) => {
78 78 that.On(cleanup);
79 79 });
80 80
81 81 return meduim;
82 82 }
83 83
84 84 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult, T> callback) {
85 85 Safe.ArgumentNotNull(that, "that");
86 86 Safe.ArgumentNotNull(callback, "callback");
87 87 var op = TraceContext.Instance.CurrentOperation;
88 88 return ar => {
89 89 TraceContext.Instance.EnterLogicalOperation(op, false);
90 90 try {
91 91 that.Resolve(callback(ar));
92 92 } catch (Exception err) {
93 93 that.Reject(err);
94 94 } finally {
95 95 TraceContext.Instance.Leave();
96 96 }
97 97 };
98 98 }
99 99
100 100 static void CancelByTimeoutCallback(object cookie) {
101 101 ((ICancellable)cookie).Cancel(new TimeoutException());
102 102 }
103 103
104 104 /// <summary>
105 105 /// Cancells promise after the specified timeout is elapsed.
106 106 /// </summary>
107 107 /// <param name="that">The promise to cancel on timeout.</param>
108 108 /// <param name="milliseconds">The timeout in milliseconds.</param>
109 109 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
110 110 public static TPromise Timeout<TPromise>(this TPromise that, int milliseconds) where TPromise : IPromise {
111 111 Safe.ArgumentNotNull(that, "that");
112 112 var timer = new Timer(CancelByTimeoutCallback, that, milliseconds, -1);
113 113 that.On(timer.Dispose, PromiseEventType.All);
114 114 return that;
115 115 }
116 116
117 117 public static IPromise PromiseAll(this IEnumerable<IPromise> that) {
118 118 Safe.ArgumentNotNull(that, "that");
119 119 return PromiseAll(that.ToList());
120 120 }
121 121
122 122 public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that) {
123 123 return PromiseAll(that, null);
124 124 }
125 125
126 126 public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that, Action<T> cleanup) {
127 127 Safe.ArgumentNotNull(that, "that");
128 128 return PromiseAll(that.ToList(), cleanup);
129 129 }
130 130
131 131 public static IPromise PromiseAll(this ICollection<IPromise> that) {
132 132 Safe.ArgumentNotNull(that, "that");
133 133
134 134 int count = that.Count;
135 135 int errors = 0;
136 136 var medium = new Promise();
137 137
138 138 if (count == 0) {
139 139 medium.Resolve();
140 140 return medium;
141 141 }
142 142
143 143 medium.On(() => {
144 144 foreach (var p2 in that)
145 145 p2.Cancel();
146 146 }, PromiseEventType.ErrorOrCancel);
147 147
148 148 foreach (var p in that)
149 149 p.On(
150 150 () => {
151 151 if (Interlocked.Decrement(ref count) == 0)
152 152 medium.Resolve();
153 153 },
154 154 error => {
155 155 if (Interlocked.Increment(ref errors) == 1)
156 156 medium.Reject(
157 157 new Exception("The dependency promise is failed", error)
158 158 );
159 159 },
160 160 reason => {
161 161 if (Interlocked.Increment(ref errors) == 1)
162 162 medium.Cancel(
163 163 new Exception("The dependency promise is cancelled")
164 164 );
165 165 }
166 166 );
167 167
168 168 return medium;
169 169 }
170 170
171 171 public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that) {
172 172 return PromiseAll(that, null);
173 173 }
174 174
175 175 /// <summary>
176 176 /// Creates a new promise which will be satisfied when all promises are satisfied.
177 177 /// </summary>
178 178 /// <typeparam name="T"></typeparam>
179 179 /// <param name="that"></param>
180 180 /// <param name="cleanup">A callback used to cleanup already resolved promises in case of an error</param>
181 181 /// <returns></returns>
182 182 public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that, Action<T> cleanup) {
183 183 Safe.ArgumentNotNull(that, "that");
184 184
185 185 int count = that.Count;
186 186
187 187 if (count == 0)
188 188 return Promise<T[]>.FromResult(new T[0]);
189 189
190 190 int errors = 0;
191 191 var medium = new Promise<T[]>();
192 192 var results = new T[that.Count];
193 193
194 194 medium.On(() => {
195 195 foreach (var p2 in that) {
196 196 p2.Cancel();
197 197 if (cleanup != null)
198 198 p2.On(cleanup);
199 199 }
200 200 }, PromiseEventType.ErrorOrCancel);
201 201
202 202 int i = 0;
203 203 foreach (var p in that) {
204 204 var idx = i;
205 205 p.On(
206 206 x => {
207 207 results[idx] = x;
208 208 if (Interlocked.Decrement(ref count) == 0)
209 209 medium.Resolve(results);
210 210 },
211 211 error => {
212 212 if (Interlocked.Increment(ref errors) == 1)
213 213 medium.Reject(
214 214 new Exception("The dependency promise is failed", error)
215 215 );
216 216 },
217 217 reason => {
218 218 if (Interlocked.Increment(ref errors) == 1)
219 219 medium.Cancel(
220 220 new Exception("The dependency promise is cancelled", reason)
221 221 );
222 222 }
223 223 );
224 224 i++;
225 225 }
226 226
227 227 return medium;
228 228 }
229 229
230 230 public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) {
231 231 Safe.ArgumentNotNull(that, "that");
232 232
233 233 var d = new ActionTask(success, error, cancel, false);
234 234 that.On(d.Resolve, d.Reject, d.CancelOperation);
235 235 d.CancellationRequested(that.Cancel);
236 236 return d;
237 237 }
238 238
239 239 public static IPromise Then(this IPromise that, Action success, Action<Exception> error) {
240 240 return Then(that, success, error, null);
241 241 }
242 242
243 243 public static IPromise Then(this IPromise that, Action success) {
244 244 return Then(that, success, null, null);
245 245 }
246 246
247 247 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
248 248 Safe.ArgumentNotNull(that, "that");
249 249
250 250 var d = new FuncTask<T>(success, error, cancel, false);
251 251 that.On(d.Resolve, d.Reject, d.CancelOperation);
252 252 d.CancellationRequested(that.Cancel);
253 253 return d;
254 254 }
255 255
256 256 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error) {
257 257 return Then(that, success, error, null);
258 258 }
259 259
260 260 public static IPromise<T> Then<T>(this IPromise that, Func<T> success) {
261 261 return Then(that, success, null, null);
262 262 }
263 263
264 264 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) {
265 265 Safe.ArgumentNotNull(that, "that");
266 Safe.ArgumentNotNull(success, "success");
267
266 268 var d = new FuncTask<T, T2>(success, error, cancel, false);
267 269 that.On(d.Resolve, d.Reject, d.CancelOperation);
268 270 d.CancellationRequested(that.Cancel);
269 271 return d;
270 272 }
271 273
272 274 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
273 275 Safe.ArgumentNotNull(that, "that");
274 276 var d = new FuncTask<T, T>(
275 277 x => {
276 278 success(x);
277 279 return x;
278 280 },
279 281 error,
280 282 cancel,
281 283 false
282 284 );
283 285 that.On(d.Resolve, d.Reject, d.CancelOperation);
284 286 d.CancellationRequested(that.Cancel);
285 287 return d;
286 288 }
287 289
288 290 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error) {
289 291 return Then(that, success, error, null);
290 292 }
291 293
292 294 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success) {
293 295 return Then(that, success, null, null);
294 296 }
295 297
296 298 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) {
297 299 return Then(that, success, error, null);
298 300 }
299 301
300 302 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success) {
301 303 return Then(that, success, null, null);
302 304 }
303 305
304 306 public static IPromise<T> Always<T>(this IPromise<T> that, Action handler) {
305 307 Func<Exception, T> errorOrCancel;
306 308 if (handler != null)
307 309 errorOrCancel = e => {
308 310 handler();
309 311 throw new PromiseTransientException(e);
310 312 };
311 313 else
312 314 errorOrCancel = null;
313 315
314 316 return Then(
315 317 that,
316 318 x => {
317 319 handler();
318 320 return x;
319 321 },
320 322 errorOrCancel,
321 323 errorOrCancel);
322 324 }
323 325
324 326 public static IPromise Always(this IPromise that, Action handler) {
325 327 Action<Exception> errorOrCancel;
326 328 if (handler != null)
327 329 errorOrCancel = e => {
328 330 handler();
329 331 throw new PromiseTransientException(e);
330 332 };
331 333 else
332 334 errorOrCancel = null;
333 335
334 336 return Then(
335 337 that,
336 338 handler,
337 339 errorOrCancel,
338 340 errorOrCancel);
339 341 }
340 342
341 343 public static IPromise Error(this IPromise that, Action<Exception> handler, bool handleCancellation) {
342 344 Action<Exception> errorOrCancel;
343 345 if (handler != null)
344 346 errorOrCancel = e => {
345 347 handler(e);
346 348 throw new PromiseTransientException(e);
347 349 };
348 350 else
349 351 errorOrCancel = null;
350 352
351 353 return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null);
352 354 }
353 355
354 356 public static IPromise Error(this IPromise that, Action<Exception> handler) {
355 357 return Error(that, handler, false);
356 358 }
357 359
358 360 public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler, bool handleCancellation) {
359 361 Func<Exception, T> errorOrCancel;
360 362 if (handler != null)
361 363 errorOrCancel = e => {
362 364 handler(e);
363 365 throw new PromiseTransientException(e);
364 366 };
365 367 else
366 368 errorOrCancel = null;
367 369
368 370 return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null);
369 371 }
370 372
371 373 public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler) {
372 374 return Error(that, handler, false);
373 375 }
374 376
375 377 #region chain traits
376 378 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) {
377 379 Safe.ArgumentNotNull(that, "that");
378 380
379 381 var d = new ActionChainTask(success, error, cancel, false);
380 382 that.On(d.Resolve, d.Reject, d.CancelOperation);
381 383 d.CancellationRequested(that.Cancel);
382 384 return d;
383 385 }
384 386
385 387 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error) {
386 388 return Chain(that, success, error, null);
387 389 }
388 390
389 391 public static IPromise Chain(this IPromise that, Func<IPromise> success) {
390 392 return Chain(that, success, null, null);
391 393 }
392 394
393 395 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error, Func<Exception, IPromise<T>> cancel) {
394 396 Safe.ArgumentNotNull(that, "that");
395 397
396 398 var d = new FuncChainTask<T>(success, error, cancel, false);
397 399 that.On(d.Resolve, d.Reject, d.CancelOperation);
398 400 if (success != null)
399 401 d.CancellationRequested(that.Cancel);
400 402 return d;
401 403 }
402 404
403 405 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error) {
404 406 return Chain(that, success, error, null);
405 407 }
406 408
407 409 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success) {
408 410 return Chain(that, success, null, null);
409 411 }
410 412
411 413 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) {
412 414 Safe.ArgumentNotNull(that, "that");
413 415 var d = new FuncChainTask<T, T2>(success, error, cancel, false);
414 416 that.On(d.Resolve, d.Reject, d.CancelOperation);
415 417 if (success != null)
416 418 d.CancellationRequested(that.Cancel);
417 419 return d;
418 420 }
419 421
420 422 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error) {
421 423 return Chain(that, success, error, null);
422 424 }
423 425
424 426 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) {
425 427 return Chain(that, success, null, null);
426 428 }
427 429
428 430 #endregion
429 431
432 public static IPromise<T2> Guard<T, T2>(this IPromise<T> that, Func<IPromise<T>, IPromise<T2>> continuation, Action<T> cleanup) {
433 Safe.ArgumentNotNull(that, "that");
434 Safe.ArgumentNotNull(continuation, "continuation");
435 return continuation(that).Error((err) => {
436 that.On(cleanup);
437 }, true);
438 }
430 439
431 440 #if NET_4_5
432 441
433 442 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
434 443 Safe.ArgumentNotNull(that, "that");
435 444
436 445 return new PromiseAwaiter<T>(that);
437 446 }
438 447
439 448 public static PromiseAwaiter GetAwaiter(this IPromise that) {
440 449 Safe.ArgumentNotNull(that, "that");
441 450
442 451 return new PromiseAwaiter(that);
443 452 }
444 453
454 public static IPromise BoundCancellationToken(this IPromise that, CancellationToken ct) {
455 Safe.ArgumentNotNull(that, "that");
456 ct.Register(that.Cancel);
457 return that.Then(null, null, (err) => {
458 ct.ThrowIfCancellationRequested();
459 throw new PromiseTransientException(err);
460 });
461 }
462
463 public static IPromise<T> BoundCancellationToken<T>(this IPromise<T> that, CancellationToken ct) {
464 Safe.ArgumentNotNull(that, "that");
465 ct.Register(that.Cancel);
466 return that.Then(null, null, (err) => {
467 ct.ThrowIfCancellationRequested();
468 throw new PromiseTransientException(err);
469 });
470 }
471
445 472 #endif
446 473 }
447 474 }
448 475
@@ -1,131 +1,132
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Text.RegularExpressions;
6 6 using System.Diagnostics;
7 7 using System.Collections;
8 8
9 9 namespace Implab
10 10 {
11 11 public static class Safe
12 12 {
13 13 public static void ArgumentAssert(bool condition, string paramName) {
14 14 if (!condition)
15 15 throw new ArgumentException("The parameter is invalid", paramName);
16 16 }
17 17
18 18 public static void ArgumentMatch(string value, string paramName, Regex rx) {
19 19 if (rx == null)
20 20 throw new ArgumentNullException("rx");
21 21 if (!rx.IsMatch(value))
22 22 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
23 23 }
24 24
25 25 public static void ArgumentNotEmpty(string value, string paramName) {
26 26 if (String.IsNullOrEmpty(value))
27 27 throw new ArgumentException("The parameter can't be empty", paramName);
28 28 }
29 29
30 30 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
31 31 if (value == null || value.Length == 0)
32 32 throw new ArgumentException("The array must be not emty", paramName);
33 33 }
34 34
35 35 public static void ArgumentNotNull(object value, string paramName) {
36 36 if (value == null)
37 37 throw new ArgumentNullException(paramName);
38 38 }
39 39
40 40 public static void ArgumentInRange(int value, int min, int max, string paramName) {
41 41 if (value < min || value > max)
42 42 throw new ArgumentOutOfRangeException(paramName);
43 43 }
44 44
45 45 public static void ArgumentOfType(object value, Type type, string paramName) {
46 46 if (!type.IsInstanceOfType(value))
47 47 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
48 48 }
49 49
50 50 public static void Dispose(params IDisposable[] objects) {
51 51 foreach (var d in objects)
52 52 if (d != null)
53 53 d.Dispose();
54 54 }
55 55
56 56 public static void Dispose(params object[] objects) {
57 57 foreach (var obj in objects) {
58 58 var d = obj as IDisposable;
59 59 if (d != null)
60 60 d.Dispose();
61 61 }
62 62 }
63 63
64 64 public static void Dispose(IEnumerable<IDisposable> objects) {
65 65 foreach (var d in objects)
66 66 if (d != null)
67 67 d.Dispose();
68 68 }
69 69
70 70 public static void Dispose(object obj) {
71 71 var d = obj as IDisposable;
72 72 if (d != null)
73 73 d.Dispose();
74 74 }
75 75
76 76 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
77 77 if (handler != null)
78 78 handler(sender, args);
79 79 }
80 80
81 81 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
82 82 if (handler != null)
83 83 handler(sender, args);
84 84 }
85 85
86 86 [DebuggerStepThrough]
87 87 public static IPromise<T> Run<T>(Func<T> action) {
88 88 ArgumentNotNull(action, "action");
89 89
90 90 try {
91 91 return Promise<T>.FromResult(action());
92 92 } catch (Exception err) {
93 93 return Promise<T>.FromException(err);
94 94 }
95 95 }
96 96
97 97 [DebuggerStepThrough]
98 98 public static IPromise Run(Action action) {
99 99 ArgumentNotNull(action, "action");
100 100
101 101 try {
102 102 action();
103 103 return Promise.Success;
104 104 } catch (Exception err) {
105 105 return new FailedPromise(err);
106 106 }
107 107 }
108 108
109 109 [DebuggerStepThrough]
110 110 public static IPromise Run(Func<IPromise> action) {
111 111 ArgumentNotNull(action, "action");
112 112
113 113 try {
114 114 return action() ?? new FailedPromise(new Exception("The action returned null"));
115 115 } catch (Exception err) {
116 116 return new FailedPromise(err);
117 117 }
118 118 }
119 119
120 120 [DebuggerStepThrough]
121 121 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
122 122 ArgumentNotNull(action, "action");
123 123
124 124 try {
125 125 return action() ?? Promise<T>.FromException(new Exception("The action returned null"));
126 126 } catch (Exception err) {
127 127 return Promise<T>.FromException(err);
128 128 }
129 129 }
130
130 131 }
131 132 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now