Mercurial > pub > ImplabNet
comparison Implab/PromiseT.cs @ 144:8c0b95069066 v2
DRAFT: refactoring
| author | cin | 
|---|---|
| date | Fri, 06 Mar 2015 15:45:26 +0300 | 
| parents | f75cfa58e3d4 | 
| children | e03ccec4a08d | 
   comparison
  equal
  deleted
  inserted
  replaced
| 143:16f926ee499d | 144:8c0b95069066 | 
|---|---|
| 1 using System; | 1 using System; | 
| 2 using System.Diagnostics; | 2 using System.Diagnostics; | 
| 3 using Implab.Parallels; | |
| 3 | 4 | 
| 4 namespace Implab { | 5 namespace Implab { | 
| 5 | 6 | 
| 6 /// <summary> | 7 /// <summary> | 
| 7 /// Класс для асинхронного получения результатов. Так называемое "обещание". | 8 /// Класс для асинхронного получения результатов. Так называемое "обещание". | 
| 35 /// <para> | 36 /// <para> | 
| 36 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать | 37 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать | 
| 37 /// только инициатор обещания иначе могут возникнуть противоречия. | 38 /// только инициатор обещания иначе могут возникнуть противоречия. | 
| 38 /// </para> | 39 /// </para> | 
| 39 /// </remarks> | 40 /// </remarks> | 
| 40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> { | 41 public class Promise<T> : AbstractPromise<T>, IDeferred<T> { | 
| 41 | 42 | 
| 42 class StubDeferred : IDeferred, IDeferred<T> { | 43 public static IPromise<T> FromResult(T value) { | 
| 43 public static readonly StubDeferred instance = new StubDeferred(); | 44 var p = new Promise<T>(); | 
| 44 | 45 p.Resolve(value); | 
| 45 StubDeferred() { | 46 return p; | 
| 46 } | |
| 47 | |
| 48 #region IDeferred implementation | |
| 49 | |
| 50 public void Resolve(T value) { | |
| 51 } | |
| 52 | |
| 53 public void Resolve() { | |
| 54 } | |
| 55 | |
| 56 public void Reject(Exception error) { | |
| 57 } | |
| 58 | |
| 59 #endregion | |
| 60 | |
| 61 #region ICancellable implementation | |
| 62 | |
| 63 public void Cancel() { | |
| 64 } | |
| 65 | |
| 66 public void Cancel(Exception reason) { | |
| 67 } | |
| 68 | |
| 69 #endregion | |
| 70 | |
| 71 | |
| 72 } | 47 } | 
| 73 | 48 | 
| 74 class RemapDescriptor<T2> : IDeferred<T> { | 49 public static IPromise<T> FromException(Exception error) { | 
| 75 readonly Func<T,T2> m_remap; | 50 var p = new Promise<T>(); | 
| 76 readonly Func<Exception, T2> m_failed; | 51 p.Reject(error); | 
| 77 readonly Func<Exception, T2> m_cancel; | 52 return p; | 
| 78 readonly IDeferred<T2> m_deferred; | |
| 79 | |
| 80 public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<Exception, T2> cancel, IDeferred<T2> deferred ) { | |
| 81 Debug.Assert(deferred != null); | |
| 82 m_remap = remap; | |
| 83 m_failed = failed; | |
| 84 m_cancel = cancel; | |
| 85 m_deferred = deferred; | |
| 86 } | |
| 87 | |
| 88 | |
| 89 | |
| 90 #region IDeferred implementation | |
| 91 | |
| 92 public void Resolve(T value) { | |
| 93 if (m_remap != null) { | |
| 94 try { | |
| 95 m_deferred.Resolve(m_remap(value)); | |
| 96 } catch (Exception ex) { | |
| 97 Reject(ex); | |
| 98 } | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 public void Reject(Exception error) { | |
| 103 if (m_failed != null) { | |
| 104 try { | |
| 105 m_deferred.Resolve(m_failed(error)); | |
| 106 } catch (Exception ex) { | |
| 107 m_deferred.Reject(ex); | |
| 108 } | |
| 109 } else { | |
| 110 m_deferred.Reject(error); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 | |
| 115 #endregion | |
| 116 | |
| 117 #region ICancellable implementation | |
| 118 | |
| 119 public void Cancel(Exception reason) { | |
| 120 if (m_cancel != null) { | |
| 121 try { | |
| 122 m_deferred.Resolve(m_cancel(reason)); | |
| 123 } catch (Exception ex) { | |
| 124 Reject(ex); | |
| 125 } | |
| 126 } else { | |
| 127 m_deferred.Cancel(reason); | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 public void Cancel() { | |
| 132 Cancel(null); | |
| 133 } | |
| 134 #endregion | |
| 135 } | 53 } | 
| 136 | 54 | 
| 137 class ListenerDescriptor : IDeferred<T> { | |
| 138 readonly Action m_handler; | |
| 139 readonly PromiseEventType m_events; | |
| 140 | |
| 141 public ListenerDescriptor(Action handler, PromiseEventType events) { | |
| 142 Debug.Assert(handler != null); | |
| 143 | |
| 144 m_handler = handler; | |
| 145 m_events = events; | |
| 146 } | |
| 147 | |
| 148 #region IDeferred implementation | |
| 149 | |
| 150 public void Resolve(T value) { | |
| 151 if (m_events.HasFlag(PromiseEventType.Success)) { | |
| 152 try { | |
| 153 m_handler(); | |
| 154 // Analysis disable once EmptyGeneralCatchClause | |
| 155 } catch { | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 public void Reject(Exception error) { | |
| 161 if (m_events.HasFlag(PromiseEventType.Error)){ | |
| 162 try { | |
| 163 m_handler(); | |
| 164 // Analysis disable once EmptyGeneralCatchClause | |
| 165 } catch { | |
| 166 } | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 #endregion | |
| 171 | |
| 172 #region ICancellable implementation | |
| 173 | |
| 174 public void Cancel() { | |
| 175 Cancel(null); | |
| 176 } | |
| 177 | |
| 178 public void Cancel(Exception reason) { | |
| 179 if (m_events.HasFlag(PromiseEventType.Cancelled)){ | |
| 180 try { | |
| 181 m_handler(); | |
| 182 // Analysis disable once EmptyGeneralCatchClause | |
| 183 } catch { | |
| 184 } | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 #endregion | |
| 189 } | |
| 190 | |
| 191 class ValueEventDescriptor : IDeferred<T> { | |
| 192 readonly Action<T> m_success; | |
| 193 readonly Action<Exception> m_failed; | |
| 194 readonly Action<Exception> m_cancelled; | |
| 195 readonly IDeferred<T> m_deferred; | |
| 196 | |
| 197 public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action<Exception> cancelled, IDeferred<T> deferred) { | |
| 198 Debug.Assert(deferred != null); | |
| 199 | |
| 200 m_success = success; | |
| 201 m_failed = failed; | |
| 202 m_cancelled = cancelled; | |
| 203 m_deferred = deferred; | |
| 204 } | |
| 205 | |
| 206 #region IDeferred implementation | |
| 207 | |
| 208 public void Resolve(T value) { | |
| 209 if (m_success != null) { | |
| 210 try { | |
| 211 m_success(value); | |
| 212 m_deferred.Resolve(value); | |
| 213 } catch (Exception ex) { | |
| 214 Reject(ex); | |
| 215 } | |
| 216 } | |
| 217 } | |
| 218 | |
| 219 public void Reject(Exception error) { | |
| 220 if (m_failed != null) { | |
| 221 try { | |
| 222 m_failed(error); | |
| 223 m_deferred.Resolve(default(T)); | |
| 224 } catch(Exception ex) { | |
| 225 m_deferred.Reject(ex); | |
| 226 } | |
| 227 } else { | |
| 228 m_deferred.Reject(error); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 #endregion | |
| 233 | |
| 234 #region ICancellable implementation | |
| 235 | |
| 236 public void Cancel(Exception reason) { | |
| 237 if (m_cancelled != null) { | |
| 238 try { | |
| 239 m_cancelled(reason); | |
| 240 m_deferred.Resolve(default(T)); | |
| 241 } catch (Exception ex) { | |
| 242 Reject(ex); | |
| 243 } | |
| 244 } else { | |
| 245 m_deferred.Cancel(reason); | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 public void Cancel() { | |
| 250 Cancel(null); | |
| 251 } | |
| 252 | |
| 253 #endregion | |
| 254 } | |
| 255 | |
| 256 public class EventDescriptor : IDeferred<T> { | |
| 257 readonly Action m_success; | |
| 258 readonly Action<Exception> m_failed; | |
| 259 readonly Action<Exception> m_cancelled; | |
| 260 readonly IDeferred m_deferred; | |
| 261 | |
| 262 public EventDescriptor(Action success, Action<Exception> failed, Action<Exception> cancelled, IDeferred deferred) { | |
| 263 Debug.Assert(deferred != null); | |
| 264 | |
| 265 m_success = success; | |
| 266 m_failed = failed; | |
| 267 m_cancelled = cancelled; | |
| 268 m_deferred = deferred; | |
| 269 } | |
| 270 | |
| 271 #region IDeferred implementation | |
| 272 | |
| 273 public void Resolve(T value) { | |
| 274 if (m_success != null) { | |
| 275 try { | |
| 276 m_success(); | |
| 277 m_deferred.Resolve(); | |
| 278 } catch (Exception ex) { | |
| 279 Reject(ex); | |
| 280 } | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 public void Reject(Exception error) { | |
| 285 if (m_failed != null) { | |
| 286 try { | |
| 287 m_failed(error); | |
| 288 m_deferred.Resolve(); | |
| 289 } catch (Exception ex) { | |
| 290 m_deferred.Reject(ex); | |
| 291 } | |
| 292 } else { | |
| 293 m_deferred.Reject(error); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 #endregion | |
| 298 | |
| 299 #region ICancellable implementation | |
| 300 | |
| 301 public void Cancel(Exception reason) { | |
| 302 if (m_cancelled != null) { | |
| 303 try { | |
| 304 m_cancelled(reason); | |
| 305 m_deferred.Resolve(); | |
| 306 } catch (Exception ex) { | |
| 307 Reject(ex); | |
| 308 } | |
| 309 } else { | |
| 310 m_deferred.Cancel(reason); | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 public void Cancel() { | |
| 315 Cancel(null); | |
| 316 } | |
| 317 | |
| 318 #endregion | |
| 319 } | |
| 320 | |
| 321 T m_result; | |
| 322 | |
| 323 public virtual void Resolve(T value) { | 55 public virtual void Resolve(T value) { | 
| 324 if (BeginSetResult()) { | 56 SetResult(value); | 
| 325 m_result = value; | |
| 326 EndSetResult(); | |
| 327 } | |
| 328 } | 57 } | 
| 329 | 58 | 
| 330 public void Reject(Exception error) { | 59 public void Reject(Exception error) { | 
| 331 SetError(error); | 60 SetError(error); | 
| 332 } | 61 } | 
| 333 | |
| 334 public Type PromiseType { | |
| 335 get { | |
| 336 return typeof(T); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 public new T Join() { | |
| 341 WaitResult(-1); | |
| 342 return m_result; | |
| 343 } | |
| 344 public new T Join(int timeout) { | |
| 345 WaitResult(timeout); | |
| 346 return m_result; | |
| 347 } | |
| 348 | |
| 349 public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) { | |
| 350 AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance)); | |
| 351 return this; | |
| 352 } | |
| 353 | |
| 354 public IPromise<T> On(Action<T> success, Action<Exception> error) { | |
| 355 AddHandler(new ValueEventDescriptor(success, error, null, StubDeferred.instance)); | |
| 356 return this; | |
| 357 } | |
| 358 | |
| 359 public IPromise<T> On(Action<T> success) { | |
| 360 AddHandler(new ValueEventDescriptor(success, null, null, StubDeferred.instance)); | |
| 361 return this; | |
| 362 } | |
| 363 | |
| 364 public IPromise<T> On(Action handler, PromiseEventType events) { | |
| 365 Listen(events, handler); | |
| 366 return this; | |
| 367 } | |
| 368 | |
| 369 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel) { | |
| 370 var promise = new Promise<T2>(); | |
| 371 if (mapper != null) | |
| 372 promise.On((Action)null, null, Cancel); | |
| 373 AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise)); | |
| 374 return promise; | |
| 375 } | |
| 376 | |
| 377 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) { | |
| 378 var promise = new Promise<T2>(); | |
| 379 if (mapper != null) | |
| 380 promise.On((Action)null, null, Cancel); | |
| 381 AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise)); | |
| 382 return promise; | |
| 383 } | |
| 384 | |
| 385 public IPromise<T2> Then<T2>(Func<T, T2> mapper) { | |
| 386 var promise = new Promise<T2>(); | |
| 387 if (mapper != null) | |
| 388 promise.On((Action)null, null, Cancel); | |
| 389 AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise)); | |
| 390 return promise; | |
| 391 } | |
| 392 | |
| 393 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) { | |
| 394 // this promise will be resolved when an asyc operation is started | |
| 395 var promise = new Promise<IPromise<T2>>(); | |
| 396 | |
| 397 AddHandler(new RemapDescriptor<IPromise<T2>>( | |
| 398 chained, | |
| 399 error, | |
| 400 cancel, | |
| 401 promise | |
| 402 )); | |
| 403 | |
| 404 var medium = new Promise<T2>(); | |
| 405 | |
| 406 if (chained != null) | |
| 407 medium.On(Cancel, PromiseEventType.Cancelled); | |
| 408 | |
| 409 // we need to connect started async operation with the medium | |
| 410 // if the async operation hasn't been started by the some reason | |
| 411 // report is to the medium | |
| 412 promise.On( | |
| 413 result => ConnectPromise<T2>(result, medium), | |
| 414 medium.Reject, | |
| 415 medium.Cancel | |
| 416 ); | |
| 417 | |
| 418 return medium; | |
| 419 } | |
| 420 | |
| 421 static void ConnectPromise<T2>(IPromise<T2> result, Promise<T2> medium) { | |
| 422 if (result != null) { | |
| 423 result.On( | |
| 424 medium.Resolve, | |
| 425 medium.Reject, | |
| 426 medium.Cancel | |
| 427 ); | |
| 428 medium.On(result.Cancel, PromiseEventType.Cancelled); | |
| 429 } else { | |
| 430 medium.Reject( | |
| 431 new NullReferenceException( | |
| 432 "The chained asynchronous operation returned" + | |
| 433 " 'null' where the promise instance is expected" | |
| 434 ) | |
| 435 ); | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error) { | |
| 440 return Chain(chained, error, null); | |
| 441 } | |
| 442 | |
| 443 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained) { | |
| 444 return Chain(chained, null, null); | |
| 445 } | |
| 446 | |
| 447 public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) { | |
| 448 var promise = new Promise(); | |
| 449 if (success != null) | |
| 450 promise.On(null, null, Cancel); | |
| 451 | |
| 452 AddHandler(new EventDescriptor(success, error, cancel, promise)); | |
| 453 | |
| 454 return promise; | |
| 455 } | |
| 456 | |
| 457 public IPromise Then(Action success, Action<Exception> error) { | |
| 458 return Then(success, error, null); | |
| 459 } | |
| 460 | |
| 461 public IPromise Then(Action success) { | |
| 462 return Then(success, null, null); | |
| 463 } | |
| 464 | |
| 465 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) { | |
| 466 var promise = new Promise<IPromise>(); | |
| 467 | |
| 468 AddHandler( | |
| 469 new RemapDescriptor<IPromise>( | |
| 470 x => chained(), | |
| 471 error, | |
| 472 cancel, | |
| 473 promise | |
| 474 ) | |
| 475 ); | |
| 476 | |
| 477 var medium = new Promise(); | |
| 478 if (chained != null) | |
| 479 medium.On(null, null, Cancel); | |
| 480 | |
| 481 promise.On( | |
| 482 result => ConnectPromise(result, medium), | |
| 483 medium.Reject, | |
| 484 medium.Cancel | |
| 485 ); | |
| 486 | |
| 487 return medium; | |
| 488 } | |
| 489 | |
| 490 static void ConnectPromise(IPromise result, Promise medium) { | |
| 491 if (result != null) { | |
| 492 result.On( | |
| 493 medium.Resolve, | |
| 494 medium.Reject, | |
| 495 medium.Cancel | |
| 496 ); | |
| 497 medium.On(null, null, result.Cancel); | |
| 498 } else { | |
| 499 medium.Reject( | |
| 500 new NullReferenceException( | |
| 501 "The chained asynchronous operation returned" + | |
| 502 " 'null' where the promise instance is expected" | |
| 503 ) | |
| 504 ); | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) { | |
| 509 return Chain(chained, error, null); | |
| 510 } | |
| 511 | |
| 512 public IPromise Chain(Func<IPromise> chained) { | |
| 513 return Chain(chained, null, null); | |
| 514 } | |
| 515 | |
| 516 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | |
| 517 AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance)); | |
| 518 return this; | |
| 519 } | |
| 520 | |
| 521 public IPromise On(Action success, Action<Exception> error) { | |
| 522 AddHandler(new EventDescriptor(success, error, null, StubDeferred.instance)); | |
| 523 return this; | |
| 524 } | |
| 525 | |
| 526 public IPromise On(Action success) { | |
| 527 Listen(PromiseEventType.Success, success); | |
| 528 return this; | |
| 529 } | |
| 530 | |
| 531 IPromise IPromise.On(Action handler, PromiseEventType events) { | |
| 532 Listen(events,handler); | |
| 533 return this; | |
| 534 } | |
| 535 | |
| 536 public IPromise<T2> Cast<T2>() { | |
| 537 return (IPromise<T2>)this; | |
| 538 } | |
| 539 | |
| 540 #region implemented abstract members of AbstractPromise | |
| 541 | |
| 542 protected override void SignalSuccess(IDeferred<T> handler) { | |
| 543 handler.Resolve(m_result); | |
| 544 } | |
| 545 | |
| 546 protected override void SignalError(IDeferred<T> handler, Exception error) { | |
| 547 handler.Reject(error); | |
| 548 } | |
| 549 | |
| 550 protected override void SignalCancelled(IDeferred<T> handler, Exception reason) { | |
| 551 handler.Cancel(reason); | |
| 552 } | |
| 553 | |
| 554 protected override void Listen(PromiseEventType events, Action handler) { | |
| 555 if (handler != null) | |
| 556 AddHandler(new ListenerDescriptor(handler, events)); | |
| 557 } | |
| 558 | |
| 559 #endregion | |
| 560 | |
| 561 public static IPromise<T> ResultToPromise(T value) { | |
| 562 var p = new Promise<T>(); | |
| 563 p.Resolve(value); | |
| 564 return p; | |
| 565 } | |
| 566 | |
| 567 public static IPromise<T> ExceptionToPromise(Exception error) { | |
| 568 var p = new Promise<T>(); | |
| 569 p.Reject(error); | |
| 570 return p; | |
| 571 } | |
| 572 | |
| 573 } | 62 } | 
| 574 } | 63 } | 
