view Implab/AbstractPromise`1.cs @ 247:fb70574741a1 v3

working on promises
author cin
date Fri, 26 Jan 2018 18:46:27 +0300
parents
children
line wrap: on
line source

using System;
using System.Diagnostics;
using System.Reflection;
using Implab.Parallels;

namespace Implab {
    public class AbstractPromise<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) {

            }

            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 Resolve(T result) {
            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<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 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<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() {
            WaitResult(-1);
            if (IsRejected)
                Rethrow();
        }

        void IPromise.Join(int timeout) {
            WaitResult(timeout);
            if (IsRejected)
                Rethrow();
        }

        public T Join() {
            WaitResult(-1);
            if (IsRejected)
                Rethrow();
            return m_result;
        }

        public T Join(int timeout) {
            WaitResult(timeout);
            if (IsRejected)
                Rethrow();
            return m_result;
        }
    }
}