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