Mercurial > pub > ImplabNet
view Implab/Promise.cs @ 281:e0916ddc9950 v3 tip
code cleanup and refactoring
author | cin |
---|---|
date | Fri, 01 Jun 2018 21:35:24 +0300 |
parents | 547a2fc0d93e |
children |
line wrap: on
line source
using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Implab.Parallels; namespace Implab { public class Promise : AbstractEvent<IResolvable>, IPromise { public static IDispatcher DefaultDispatcher { get { return ThreadPoolDispatcher.Instance; } } class ResolvableSignal : IResolvable { public Signal Signal { get; private set; } public ResolvableSignal() { Signal = new Signal(); } public void Reject(Exception error) { Signal.Set(); } public void Resolve() { Signal.Set(); } } PromiseState m_state; Exception m_error; public bool IsRejected { get { return m_state == PromiseState.Rejected; } } public bool IsFulfilled { get { return m_state == PromiseState.Fulfilled; } } public Exception RejectReason { get { return m_error; } } internal Promise() { } internal void ResolvePromise() { if (BeginTransit()) { m_state = PromiseState.Fulfilled; CompleteTransit(); } } internal void RejectPromise(Exception reason) { if (BeginTransit()) { m_error = reason; m_state = PromiseState.Rejected; CompleteTransit(); } } #region implemented abstract members of AbstractPromise protected override void SignalHandler(IResolvable handler) { switch (m_state) { case PromiseState.Fulfilled: handler.Resolve(); break; case PromiseState.Rejected: handler.Reject(RejectReason); break; default: throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); } } protected void WaitResult(int timeout) { if (!(IsResolved || GetFulfillSignal().Wait(timeout))) throw new TimeoutException(); } protected Signal GetFulfillSignal() { var next = new ResolvableSignal(); Then(next); return next.Signal; } #endregion public Type ResultType { get { return typeof(void); } } protected void Rethrow() { Debug.Assert(m_error != null); if (m_error is OperationCanceledException) throw new OperationCanceledException("Operation cancelled", m_error); else throw new TargetInvocationException(m_error); } public void Then(IResolvable next) { AddHandler(next); } public IPromise<T> Cast<T>() { throw new InvalidCastException(); } public void Join() { WaitResult(-1); if (IsRejected) Rethrow(); } public void Join(int timeout) { WaitResult(timeout); if (IsRejected) Rethrow(); } public static ResolvedPromise Resolve() { return new ResolvedPromise(); } public static ResolvedPromise<T> Resolve<T>(T result) { return new ResolvedPromise<T>(result); } public static RejectedPromise Reject(Exception reason) { return new RejectedPromise(reason); } public static RejectedPromise<T> Reject<T>(Exception reason) { return new RejectedPromise<T>(reason); } public static IPromise Create(PromiseExecutor executor) { return Create(executor, CancellationToken.None); } public static IPromise Create(PromiseExecutor executor, CancellationToken ct) { Safe.ArgumentNotNull(executor, nameof(executor)); if (!ct.CanBeCanceled) return Create(executor); var d = new Deferred(); ct.Register(d.Cancel); try { if (!ct.IsCancellationRequested) executor(d); } catch(Exception e) { d.Reject(e); } return d.Promise; } public static IPromise<T> Create<T>(PromiseExecutor<T> executor) { return Create(executor, CancellationToken.None); } public static IPromise<T> Create<T>(PromiseExecutor<T> executor, CancellationToken ct) { Safe.ArgumentNotNull(executor, nameof(executor)); var d = new Deferred<T>(); ct.Register(d.Cancel); try { if (!ct.IsCancellationRequested) executor(d); } catch(Exception e) { d.Reject(e); } return d.Promise; } public static IPromise All(IEnumerable<IPromise> promises) { var d = new Deferred(); var all = new PromiseAll(d); foreach (var promise in promises) { all.AddPromise(promise); if (all.Done) break; } all.Complete(); return all.ResultPromise; } public static IPromise<T[]> All<T>(IEnumerable<IPromise<T>> promises, Func<T, IPromise> cleanup = null, Action cancel = null) { var d = new Deferred<T[]>(); var all = new PromiseAll<T>(d, cleanup, cancel); foreach (var promise in promises) { all.AddPromise(promise); if (all.Done) break; } all.Complete(); return all.ResultPromise; } } }