Mercurial > pub > ImplabNet
annotate Implab/PromiseExtensions.cs @ 185:822aab37b107 ref20160224
runnable component, work in progress
author | cin |
---|---|
date | Mon, 18 Apr 2016 16:41:17 +0300 |
parents | ec91a6dfa5b3 |
children | 8200ab154c8a |
rev | line source |
---|---|
72 | 1 using System.Threading; |
75 | 2 using System; |
109 | 3 using Implab.Diagnostics; |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
4 using System.Collections.Generic; |
109 | 5 |
72 | 6 namespace Implab { |
7 public static class PromiseExtensions { | |
8 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) { | |
75 | 9 Safe.ArgumentNotNull(that, "that"); |
72 | 10 var context = SynchronizationContext.Current; |
11 if (context == null) | |
12 return that; | |
13 | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
14 var p = new SyncContextPromise<T>(context); |
185 | 15 p.CancellationRequested(that.Cancel); |
72 | 16 |
104 | 17 that.On( |
76 | 18 p.Resolve, |
19 p.Reject, | |
185 | 20 p.CancelOperation |
72 | 21 ); |
22 return p; | |
23 } | |
24 | |
25 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) { | |
75 | 26 Safe.ArgumentNotNull(that, "that"); |
72 | 27 Safe.ArgumentNotNull(context, "context"); |
28 | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
29 var p = new SyncContextPromise<T>(context); |
185 | 30 p.CancellationRequested(that.Cancel); |
72 | 31 |
104 | 32 that.On( |
76 | 33 p.Resolve, |
34 p.Reject, | |
185 | 35 p.CancelOperation |
72 | 36 ); |
37 return p; | |
38 } | |
75 | 39 |
101 | 40 /// <summary> |
41 /// Ensures the dispatched. | |
42 /// </summary> | |
43 /// <returns>The dispatched.</returns> | |
44 /// <param name="that">That.</param> | |
45 /// <param name="head">Head.</param> | |
46 /// <param name="cleanup">Cleanup.</param> | |
47 /// <typeparam name="TPromise">The 1st type parameter.</typeparam> | |
48 /// <typeparam name="T">The 2nd type parameter.</typeparam> | |
49 public static TPromise EnsureDispatched<TPromise,T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise{ | |
50 Safe.ArgumentNotNull(that, "that"); | |
51 Safe.ArgumentNotNull(head, "head"); | |
52 | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
136
diff
changeset
|
53 that.On(() => head.On(cleanup), PromiseEventType.Cancelled); |
101 | 54 |
55 return that; | |
56 } | |
57 | |
75 | 58 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) { |
59 Safe.ArgumentNotNull(that, "that"); | |
60 Safe.ArgumentNotNull(callback, "callback"); | |
109 | 61 var op = TraceContext.Instance.CurrentOperation; |
75 | 62 return ar => { |
109 | 63 TraceContext.Instance.EnterLogicalOperation(op,false); |
75 | 64 try { |
65 that.Resolve(callback(ar)); | |
66 } catch (Exception err) { | |
67 that.Reject(err); | |
109 | 68 } finally { |
69 TraceContext.Instance.Leave(); | |
75 | 70 } |
71 }; | |
72 } | |
110 | 73 |
185 | 74 static void CancelByTimeoutCallback(object cookie) { |
75 ((ICancellable)cookie).Cancel(new TimeoutException()); | |
110 | 76 } |
77 | |
78 /// <summary> | |
79 /// Cancells promise after the specified timeout is elapsed. | |
80 /// </summary> | |
81 /// <param name="that">The promise to cancel on timeout.</param> | |
82 /// <param name="milliseconds">The timeout in milliseconds.</param> | |
83 /// <typeparam name="TPromise">The 1st type parameter.</typeparam> | |
84 public static TPromise Timeout<TPromise>(this TPromise that, int milliseconds) where TPromise : IPromise { | |
85 Safe.ArgumentNotNull(that, "that"); | |
185 | 86 var timer = new Timer(CancelByTimeoutCallback, that, milliseconds, -1); |
110 | 87 that.On(timer.Dispose, PromiseEventType.All); |
88 return that; | |
89 } | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
90 |
124 | 91 public static IPromise Bundle(this ICollection<IPromise> that) { |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
92 Safe.ArgumentNotNull(that, "that"); |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
93 |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
94 int count = that.Count; |
124 | 95 int errors = 0; |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
96 var medium = new Promise(); |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
97 |
136 | 98 if (count == 0) { |
99 medium.Resolve(); | |
100 return medium; | |
101 } | |
102 | |
124 | 103 medium.On(() => { |
104 foreach(var p2 in that) | |
105 p2.Cancel(); | |
106 }, PromiseEventType.ErrorOrCancel); | |
107 | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
108 foreach (var p in that) |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
109 p.On( |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
110 () => { |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
111 if (Interlocked.Decrement(ref count) == 0) |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
112 medium.Resolve(); |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
113 }, |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
114 error => { |
124 | 115 if (Interlocked.Increment(ref errors) == 1) |
116 medium.Reject( | |
117 new Exception("The dependency promise is failed", error) | |
118 ); | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
119 }, |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
136
diff
changeset
|
120 reason => { |
124 | 121 if (Interlocked.Increment(ref errors) == 1) |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
136
diff
changeset
|
122 medium.Cancel( |
124 | 123 new Exception("The dependency promise is cancelled") |
124 ); | |
119
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
125 } |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
126 ); |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
127 |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
128 return medium; |
2573b562e328
Promises rewritten, added improved version of AsyncQueue
cin
parents:
110
diff
changeset
|
129 } |
124 | 130 |
131 public static IPromise<T[]> Bundle<T>(this ICollection<IPromise<T>> that) { | |
132 Safe.ArgumentNotNull(that, "that"); | |
133 | |
134 int count = that.Count; | |
135 int errors = 0; | |
136 var medium = new Promise<T[]>(); | |
137 var results = new T[that.Count]; | |
138 | |
139 medium.On(() => { | |
140 foreach(var p2 in that) | |
141 p2.Cancel(); | |
142 }, PromiseEventType.ErrorOrCancel); | |
143 | |
144 int i = 0; | |
145 foreach (var p in that) { | |
146 var idx = i; | |
147 p.On( | |
148 x => { | |
149 results[idx] = x; | |
150 if (Interlocked.Decrement(ref count) == 0) | |
151 medium.Resolve(results); | |
152 }, | |
153 error => { | |
154 if (Interlocked.Increment(ref errors) == 1) | |
155 medium.Reject( | |
156 new Exception("The dependency promise is failed", error) | |
157 ); | |
158 }, | |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
136
diff
changeset
|
159 reason => { |
124 | 160 if (Interlocked.Increment(ref errors) == 1) |
138
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
136
diff
changeset
|
161 medium.Cancel( |
f75cfa58e3d4
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin
parents:
136
diff
changeset
|
162 new Exception("The dependency promise is cancelled", reason) |
124 | 163 ); |
164 } | |
165 ); | |
166 i++; | |
167 } | |
168 | |
169 return medium; | |
170 } | |
145 | 171 |
172 public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) { | |
173 Safe.ArgumentNotNull(that, "that"); | |
174 | |
149 | 175 var d = new ActionTask(success, error, cancel, false); |
145 | 176 that.On(d.Resolve, d.Reject, d.CancelOperation); |
185 | 177 d.CancellationRequested(that.Cancel); |
145 | 178 return d; |
179 } | |
180 | |
181 public static IPromise Then(this IPromise that, Action success, Action<Exception> error) { | |
182 return Then(that, success, error, null); | |
183 } | |
184 | |
185 public static IPromise Then(this IPromise that, Action success) { | |
186 return Then(that, success, null, null); | |
187 } | |
188 | |
189 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error, Func<Exception, T> cancel) { | |
190 Safe.ArgumentNotNull(that, "that"); | |
191 | |
149 | 192 var d = new FuncTask<T>(success, error, cancel, false); |
145 | 193 that.On(d.Resolve, d.Reject, d.CancelOperation); |
185 | 194 d.CancellationRequested(that.Cancel); |
145 | 195 return d; |
196 } | |
197 | |
198 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error) { | |
199 return Then(that, success, error, null); | |
200 } | |
201 | |
202 public static IPromise<T> Then<T>(this IPromise that, Func<T> success) { | |
203 return Then(that, success, null, null); | |
204 } | |
205 | |
206 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) { | |
207 Safe.ArgumentNotNull(that, "that"); | |
149 | 208 var d = new FuncTask<T,T2>(success, error, cancel, false); |
145 | 209 that.On(d.Resolve, d.Reject, d.CancelOperation); |
185 | 210 d.CancellationRequested(that.Cancel); |
145 | 211 return d; |
212 } | |
213 | |
214 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) { | |
215 return Then(that, success, error, null); | |
216 } | |
217 | |
218 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success) { | |
219 return Then(that, success, null, null); | |
220 } | |
221 | |
222 #region chain traits | |
223 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error, Func<Exception,IPromise> cancel) { | |
224 Safe.ArgumentNotNull(that, "that"); | |
225 | |
149 | 226 var d = new ActionChainTask(success, error, cancel, false); |
145 | 227 that.On(d.Resolve, d.Reject, d.CancelOperation); |
185 | 228 d.CancellationRequested(that.Cancel); |
145 | 229 return d; |
230 } | |
231 | |
232 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error) { | |
233 return Chain(that, success, error, null); | |
234 } | |
235 | |
236 public static IPromise Chain(this IPromise that, Func<IPromise> success) { | |
237 return Chain(that, success, null, null); | |
238 } | |
239 | |
240 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error, Func<Exception, IPromise<T>> cancel) { | |
241 Safe.ArgumentNotNull(that, "that"); | |
242 | |
149 | 243 var d = new FuncChainTask<T>(success, error, cancel, false); |
145 | 244 that.On(d.Resolve, d.Reject, d.CancelOperation); |
245 if (success != null) | |
246 d.CancellationRequested(that.Cancel); | |
247 return d; | |
248 } | |
249 | |
250 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error) { | |
251 return Chain(that, success, error, null); | |
252 } | |
253 | |
254 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success) { | |
255 return Chain(that, success, null, null); | |
256 } | |
257 | |
258 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) { | |
259 Safe.ArgumentNotNull(that, "that"); | |
149 | 260 var d = new FuncChainTask<T,T2>(success, error, cancel, false); |
145 | 261 that.On(d.Resolve, d.Reject, d.CancelOperation); |
262 if (success != null) | |
263 d.CancellationRequested(that.Cancel); | |
264 return d; | |
265 } | |
266 | |
267 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error) { | |
268 return Chain(that, success, error, null); | |
269 } | |
270 | |
271 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) { | |
272 return Chain(that, success, null, null); | |
273 } | |
274 | |
275 #endregion | |
276 | |
75 | 277 |
278 #if NET_4_5 | |
279 | |
151 | 280 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) { |
75 | 281 Safe.ArgumentNotNull(that, "that"); |
282 | |
151 | 283 return new PromiseAwaiter<T>(that); |
75 | 284 } |
285 | |
286 #endif | |
72 | 287 } |
288 } | |
289 |