view Implab/AbstractPromise.cs @ 187:dd4a3590f9c6 ref20160224

Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler Any unhandled OperationCanceledException will cause the promise cancelation
author cin
date Tue, 19 Apr 2016 17:35:20 +0300
parents 75103928da09
children 86187b01c4e0
line wrap: on
line source

using System;
using Implab.Parallels;

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

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

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

            public void SignalSuccess() {
                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 {
                    }
                }
            }
        }


        #region implemented abstract members of AbstractPromise

        protected override void SignalHandler(HandlerDescriptor handler, int signal) {
            switch (signal) {
                case SUCCEEDED_STATE:
                    handler.SignalSuccess();
                    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));
            }
        }

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

        #endregion

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

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

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

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

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

        public IPromise<T> Cast<T>() {
            throw new InvalidCastException();
        }

        public void Join() {
            WaitResult(-1);
        }

        public void Join(int timeout) {
            WaitResult(timeout);
        }

        protected void SetResult() {
            if(BeginSetResult())
                EndSetResult();
        }
    }
}