|  |  | using System; | 
                        
    
    
        |  |  | using System.Diagnostics; | 
                        
    
    
        |  |  | using System.Reflection; | 
                        
    
    
        |  |  | using Implab.Parallels; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | namespace Implab { | 
                        
    
    
        |  |  | public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | 
                        
    
    
        |  |  | public class HandlerDescriptor { | 
                        
    
    
        |  |  | readonly Action m_resolve; | 
                        
    
    
        |  |  | readonly Action<Exception> m_reject; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | readonly IDeferred m_deferred; | 
                        
    
    
        |  |  | public HandlerDescriptor(Action success, Action<Exception> error) { | 
                        
    
    
        |  |  | m_resolve = success; | 
                        
    
    
        |  |  | m_reject = error; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public void SignalSuccess() { | 
                        
    
    
        |  |  | try { | 
                        
    
    
        |  |  | if (m_resolve != null) | 
                        
    
    
        |  |  | m_resolve(); | 
                        
    
    
        |  |  | m_deferred.Resolve(); | 
                        
    
    
        |  |  | } catch (Exception ex) { | 
                        
    
    
        |  |  | m_deferred.Reject(ex); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public void SignalError(Exception err) { | 
                        
    
    
        |  |  | if (m_reject != null) { | 
                        
    
    
        |  |  | try { | 
                        
    
    
        |  |  | m_reject(err); | 
                        
    
    
        |  |  | m_deferred.Resolve(); | 
                        
    
    
        |  |  | } catch (Exception ex) { | 
                        
    
    
        |  |  | m_deferred.Reject(ex); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | PromiseState m_state; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | Exception m_error; | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public bool IsRejected { | 
                        
    
    
        |  |  | get { | 
                        
    
    
        |  |  | return m_state == PromiseState.Rejected; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public bool IsResolved { | 
                        
    
    
        |  |  | get { | 
                        
    
    
        |  |  | return m_state == PromiseState.Resolved; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public Exception RejectReason { | 
                        
    
    
        |  |  | get { | 
                        
    
    
        |  |  | return m_error; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | #region implemented abstract members of AbstractPromise | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | protected override void SignalHandler(HandlerDescriptor handler) { | 
                        
    
    
        |  |  | switch (m_state) { | 
                        
    
    
        |  |  | case PromiseState.Resolved: | 
                        
    
    
        |  |  | handler.SignalSuccess(); | 
                        
    
    
        |  |  | break; | 
                        
    
    
        |  |  | case PromiseState.Rejected: | 
                        
    
    
        |  |  | handler.SignalError(RejectReason); | 
                        
    
    
        |  |  | break; | 
                        
    
    
        |  |  | default: | 
                        
    
    
        |  |  | throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | protected override Signal GetFulfillSignal() { | 
                        
    
    
        |  |  | var signal = new Signal(); | 
                        
    
    
        |  |  | On(signal.Set, e => signal.Set()); | 
                        
    
    
        |  |  | return signal; | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | #endregion | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | protected void CompleteResolve() { | 
                        
    
    
        |  |  | m_state = PromiseState.Resolved; | 
                        
    
    
        |  |  | CompleteTransit(); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public Type ResultType { | 
                        
    
    
        |  |  | get { | 
                        
    
    
        |  |  | return typeof(void); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | /// <summary> | 
                        
    
    
        |  |  | /// Выполняет обещание, сообщая об ошибке | 
                        
    
    
        |  |  | /// </summary> | 
                        
    
    
        |  |  | /// <remarks> | 
                        
    
    
        |  |  | /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков | 
                        
    
    
        |  |  | /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные | 
                        
    
    
        |  |  | /// будут проигнорированы. | 
                        
    
    
        |  |  | /// </remarks> | 
                        
    
    
        |  |  | /// <param name="error">Исключение возникшее при выполнении операции</param> | 
                        
    
    
        |  |  | /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> | 
                        
    
    
        |  |  | protected void SetError(Exception error) { | 
                        
    
    
        |  |  | if (BeginTransit()) { | 
                        
    
    
        |  |  | m_error = error; | 
                        
    
    
        |  |  | m_state = PromiseState.Rejected; | 
                        
    
    
        |  |  | CompleteTransit(); | 
                        
    
    
        |  |  | } else { | 
                        
    
    
        |  |  | WaitTransition(); | 
                        
    
    
        |  |  | if (m_state == PromiseState.Resolved) | 
                        
    
    
        |  |  | throw new InvalidOperationException("The promise is already resolved"); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | 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 On(Action success, Action<Exception> error) { | 
                        
    
    
        |  |  | AddHandler(new HandlerDescriptor(success, error)); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public IPromise<T> Cast<T>() { | 
                        
    
    
        |  |  | throw new InvalidCastException(); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public void Join() { | 
                        
    
    
        |  |  | WaitResult(-1); | 
                        
    
    
        |  |  | if (IsRejected) | 
                        
    
    
        |  |  | Rethrow(); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  | public void Join(int timeout) { | 
                        
    
    
        |  |  | WaitResult(timeout); | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  | } | 
                        
    
    
        |  |  |  | 
                        
    
    
        |  |  |  |