view Implab/AbstractPromiseT.cs @ 156:97fbbf816844 v2

Promises: SignalXXX methods merged into SignalHandler method. Components: RunnableComponent In progress
author cin
date Mon, 15 Feb 2016 04:22:15 +0300
parents 706fccb85524
children 86187b01c4e0
line wrap: on
line source

using System;
using Implab.Parallels;

namespace Implab {
    public abstract class AbstractPromise<T> : AbstractEvent<AbstractPromise<T>.HandlerDescriptor>, IPromise<T> {
        public struct HandlerDescriptor {
            readonly Action m_handler;
            readonly Action<T> m_success;
            readonly Action<Exception> m_error;
            readonly Action<Exception> m_cancel;
            readonly PromiseEventType m_mask;

            public HandlerDescriptor(Action<T> success, Action<Exception> error, Action<Exception> cancel) {
                m_success = success;
                m_error = error;
                m_cancel = cancel;

                m_handler = null;
                m_mask = 0;
            }

            public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) {
                m_handler = success;
                m_success = null;
                m_error = error;
                m_cancel = cancel;
                m_mask = PromiseEventType.Success;
            }

            public HandlerDescriptor(Action handler, PromiseEventType mask) {
                m_handler = handler;
                m_mask = mask;
                m_success = null;
                m_error = null;
                m_cancel = null;
            }

            public void SignalSuccess(T result) {
                if (m_success != null) {
                    try {
                        m_success(result);
                    } catch(Exception err) {
                        SignalError(err);
                    }
                } else if ((m_mask & PromiseEventType.Success) != 0 && m_handler != null) {
                    try {
                        m_handler();
                    } catch(Exception err) {
                        // avoid calling handler twice in case of error
                        if (m_error != null)
                            SignalError(err);
                    }
                }
            }

            public void SignalError(Exception err) {
                if (m_error != null) {
                    try {
                        m_error(err);
                        // Analysis disable once EmptyGeneralCatchClause
                    } catch {
                    }
                } else if ((m_mask & PromiseEventType.Error) != 0 && m_handler != null) {
                    try {
                        m_handler();
                        // Analysis disable once EmptyGeneralCatchClause
                    } catch {
                    }
                }
            }

            public void SignalCancel(Exception reason) {
                if (m_cancel != null) {
                    try {
                        m_cancel(reason);
                    } catch (Exception err) {
                        SignalError(err);
                    }
                } else if ((m_mask & PromiseEventType.Cancelled) != 0 && m_handler != null) {
                    try {
                        m_handler();
                        // Analysis disable once EmptyGeneralCatchClause
                    } catch {
                    }
                }
            }
        }

        public Type PromiseType {
            get {
                return typeof(T);
            }
        }

        public T Join() {
            WaitResult(-1);
            return m_result;
        }
        public T Join(int timeout) {
            WaitResult(timeout);
            return m_result;
        }

        void IPromise.Join() {
            WaitResult(-1);
        }
        void IPromise.Join(int timeout) {
            WaitResult(timeout);
        }

        public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) {
            AddHandler(new HandlerDescriptor(success, error, cancel));
            return this;
        }

        public IPromise<T> On(Action<T> success, Action<Exception> error) {
            AddHandler(new HandlerDescriptor(success, error, null));
            return this;
        }

        public IPromise<T> On(Action<T> success) {
            AddHandler(new HandlerDescriptor(success, null, null));
            return this;
        }

        public IPromise<T> On(Action handler, PromiseEventType events) {
            AddHandler(new HandlerDescriptor(handler, events));
            return this;
        }

        public IPromise<T> On(Action success, Action<Exception> error, Action<Exception> cancel) {
            AddHandler(new HandlerDescriptor(success, error, cancel));
            return this;
        }

        public IPromise<T> On(Action success, Action<Exception> error) {
            AddHandler(new HandlerDescriptor(success, error, null));
            return this;
        }

        public IPromise<T> On(Action success) {
            AddHandler(new HandlerDescriptor(success, null, null));
            return this;
        }

        IPromise IPromise.On(Action success, Action<Exception> error, Action<Exception> cancel) {
            AddHandler(new HandlerDescriptor(success, error, cancel));
            return this;
        }

        IPromise IPromise.On(Action success, Action<Exception> error) {
            AddHandler(new HandlerDescriptor(success, error, null));
            return this;
        }

        IPromise IPromise.On(Action success) {
            AddHandler(new HandlerDescriptor(success, null, null));
            return this;
        }

        IPromise IPromise.On(Action handler, PromiseEventType events) {
            AddHandler(new HandlerDescriptor(handler, events));
            return this;
        }

        public IPromise<T2> Cast<T2>() {
            return (IPromise<T2>)this;
        }

        #region implemented abstract members of AbstractPromise

        protected override Signal GetResolveSignal() {
            var signal = new Signal();
            AddHandler(new HandlerDescriptor(signal.Set, PromiseEventType.All));
            return signal;
        }

        protected override void SignalHandler(HandlerDescriptor handler, int signal) {
            switch (signal) {
                case SUCCEEDED_STATE:
                    handler.SignalSuccess(m_result);
                    break;
                case REJECTED_STATE:
                    handler.SignalError(Error);
                    break;
                case CANCELLED_STATE:
                    handler.SignalCancel(CancellationReason);
                    break;
                default:
                    throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal));
            }
        }

        #endregion

        T m_result;

        protected void SetResult(T value) {
            if (BeginSetResult()) {
                m_result = value;
                EndSetResult();
            }
        }
    }
}