Mercurial > pub > ImplabNet
diff Implab/Promise`1.cs @ 248:5cb4826c2c2a v3
Added awaiters to promises
Added static methods to Promise Resolve, Reject, All.
Updated promise helpers
author | cin |
---|---|
date | Tue, 30 Jan 2018 01:37:17 +0300 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Promise`1.cs Tue Jan 30 01:37:17 2018 +0300 @@ -0,0 +1,159 @@ +using System; +using System.Diagnostics; +using System.Reflection; +using Implab.Parallels; + +namespace Implab { + public class Promise<T> : AbstractEvent<IResolvable<T>>, IPromise<T> { + + class ResolvableSignal : IResolvable<T> { + public Signal Signal { get; private set; } + public ResolvableSignal() { + Signal = new Signal(); + } + + + public void Reject(Exception error) { + Signal.Set(); + } + + public void Resolve(T result) { + Signal.Set(); + } + } + + class ResolvableWrapper : IResolvable<T> { + readonly IResolvable m_resolvable; + public ResolvableWrapper(IResolvable resolvable) { + m_resolvable = resolvable; + } + + public void Reject(Exception reason) { + m_resolvable.Reject(reason); + } + + public void Resolve(T value) { + m_resolvable.Resolve(); + } + } + + PromiseState m_state; + + T m_result; + + 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 void ResolvePromise(T result) { + if (BeginTransit()) { + m_result = result; + 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<T> handler) { + switch (m_state) { + case PromiseState.Fulfilled: + handler.Resolve(m_result); + 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() { + if (m_error is OperationCanceledException) + throw new OperationCanceledException("Operation cancelled", m_error); + else + throw new TargetInvocationException(m_error); + } + + public void Then(IResolvable<T> next) { + AddHandler(next); + } + + public void Then(IResolvable next) { + AddHandler(new ResolvableWrapper(next)); + } + + public IPromise<T2> Cast<T2>() { + return (IPromise<T2>)this; + } + + void IPromise.Join() { + Join(); + } + + void IPromise.Join(int timeout) { + Join(timeout); + } + + public T Join() { + WaitResult(-1); + if (IsRejected) + Rethrow(); + return m_result; + } + + public T Join(int timeout) { + WaitResult(timeout); + if (IsRejected) + Rethrow(); + return m_result; + } + } +} +