using System; using System.Diagnostics; using System.Reflection; using Implab.Parallels; namespace Implab { public class Promise : AbstractEvent>, IPromise { class ResolvableSignal : IResolvable { 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 { 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 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 next) { AddHandler(next); } public void Then(IResolvable next) { AddHandler(new ResolvableWrapper(next)); } public IPromise Cast() { return (IPromise)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; } } }