using System; using System.Diagnostics; using System.Reflection; using Implab.Parallels; namespace Implab { public class AbstractPromise : 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() { 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 void Resolve() { if (BeginTransit()) CompleteResolve(); } internal void Reject(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 override Signal GetFulfillSignal() { var next = new ResolvableSignal(); Then(next); return next.Signal; } #endregion protected void CompleteResolve() { m_state = PromiseState.Fulfilled; CompleteTransit(); } 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 Cast() { throw new InvalidCastException(); } public void Join() { WaitResult(-1); if (IsRejected) Rethrow(); } public void Join(int timeout) { WaitResult(timeout); } } }