diff Implab/Promise.cs @ 106:d4e38929ce36 v2

promises refactoring
author cin
date Mon, 10 Nov 2014 18:00:28 +0300
parents 4d308952fd5e
children f5220e5472ef
line wrap: on
line diff
--- a/Implab/Promise.cs	Mon Nov 10 10:17:54 2014 +0300
+++ b/Implab/Promise.cs	Mon Nov 10 18:00:28 2014 +0300
@@ -42,53 +42,68 @@
     /// </remarks>
     public class Promise<T> : IPromise<T> {
 
-        protected struct HandlerDescriptor {
-            public Action<T> resultHandler;
-            public Func<Exception,T> errorHandler;
-            public Action cancellHandler;
-            public Promise<T> medium;
+        protected abstract class AbstractHandler : MTCustomQueueNode<AbstractHandler> {
+            public abstract void Resolve(T result);
+            public abstract void Reject(Exception error);
+            public abstract void Cancel();
+        }
+
+        protected class HandlerDescriptor<T2> : AbstractHandler  {
+
+            readonly Func<T,T2> m_resultHandler;
+            readonly Func<Exception,T2> m_errorHandler;
+            readonly Action m_cancellHandler;
+            readonly Promise<T2> m_medium;
 
-            public void Resolve(T result) {
-                if (resultHandler != null) {
+            public HandlerDescriptor(Func<T,T2> resultHandler, Func<Exception,T2> errorHandler, Action cancelHandler, Promise<T2> medium) {
+                m_resultHandler = resultHandler;
+                m_errorHandler = errorHandler;
+                m_cancellHandler = cancelHandler;
+                m_medium = medium;
+            }
+
+            public override void Resolve(T result) {
+                if (m_resultHandler != null) {
                     try {
-                        resultHandler(result);
+                        if (m_medium != null)
+                            m_medium.Resolve(m_resultHandler(result));
+                        else
+                            m_resultHandler(result);
                     } catch (Exception e) {
                         Reject(e);
-                        return;
                     }
-                }
-                if (medium != null)
-                    medium.Resolve(result);
+                } else if(m_medium != null)
+                    m_medium.Resolve(default(T2));
             }
 
-            public void Reject(Exception err) {
-                if (errorHandler != null) {
+            public override void Reject(Exception error) {
+                if (m_errorHandler != null) {
                     try {
-                        var res = errorHandler(err);
-                        if (medium != null)
-                            medium.Resolve(res);
+                        var res = m_errorHandler(error);
+                        if (m_medium != null)
+                            m_medium.Resolve(res);
                         /*} catch (TransientPromiseException err2) {
                         if (medium != null)
                             medium.Reject(err2.InnerException);*/
                     } catch (Exception err2) {
-                        if (medium != null)
-                            medium.Reject(err2);
+                        if (m_medium != null)
+                            m_medium.Reject(err2);
                     }
-                } else if (medium != null)
-                    medium.Reject(err);
+                } else if (m_medium != null)
+                    m_medium.Reject(error);
             }
 
-            public void Cancel() {
-                if (cancellHandler != null) {
+            public override void Cancel() {
+                if (m_cancellHandler != null) {
                     try {
-                        cancellHandler();
+                        m_cancellHandler();
                     } catch (Exception err) {
                         Reject(err);
                         return;
                     }
                 }
-                if (medium != null)
-                    medium.Cancel();
+                if (m_medium != null)
+                    m_medium.Cancel();
             }
         }
 
@@ -103,14 +118,15 @@
         T m_result;
         Exception m_error;
 
-        readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
+        readonly MTCustomQueue<AbstractHandler> m_handlers = new MTCustomQueue<AbstractHandler>();
+        //readonly MTQueue<AbstractHandler> m_handlers = new MTQueue<AbstractHandler>();
 
         public Promise() {
         }
 
         public Promise(IPromise parent) {
             if (parent != null)
-                AddHandler(
+                AddHandler<T>(
                     null,
                     null,
                     () => {
@@ -215,49 +231,6 @@
             }
         }
 
-        public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) {
-            if (success == null && error == null && cancel == null)
-                return this;
-
-            var medium = new Promise<T>(this);
-
-            AddHandler(success, error, cancel, medium, true);
-
-            return medium;
-        }
-
-        /// <summary>
-        /// Adds new handlers to this promise.
-        /// </summary>
-        /// <param name="success">The handler of the successfully completed operation.
-        /// This handler will recieve an operation result as a parameter.</param>
-        /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param>
-        /// <returns>The new promise chained to this one.</returns>
-        public IPromise<T> Then(Action<T> success, Func<Exception,T> error) {
-            if (success == null && error == null)
-                return this;
-
-            var medium = new Promise<T>(this);
-
-            AddHandler(success, error, null, medium, true);
-
-            return medium;
-        }
-
-        
-
-
-        public IPromise<T> Then(Action<T> success) {
-            if (success == null)
-                return this;
-
-            var medium = new Promise<T>(this);
-
-            AddHandler(success, null, null, medium, true);
-
-            return medium;
-        }
-
         /// <summary>
         /// Последний обработчик в цепочки обещаний.
         /// </summary>
@@ -279,13 +252,19 @@
             if (success == null && error == null && cancel == null)
                 return;
 
-            Func<Exception,T> errorHandler = null;
-            if (error != null)
-                errorHandler = err => {
-                    error(err);
+            AddHandler(
+                success != null ? new Func<T,T>(x => {
+                    success(x);
+                    return x;
+                }) : null,
+                error != null ? new Func<Exception,T>(e => {
+                    error(e);
                     return default(T);
-                };
-            AddHandler(success, errorHandler, cancel, null, false);
+                }) : null,
+                cancel,
+                null,
+                false
+            );
         }
 
         public void On(Action<T> success, Action<Exception> error) {
@@ -299,7 +278,10 @@
         public void On(Action handler, PromiseEventType events) {
             Safe.ArgumentNotNull(handler, "handler");
 
-            Action<T> success = events.HasFlag(PromiseEventType.Success) ? new Action<T>(x => handler()) : null;
+            Func<T,T> success = events.HasFlag(PromiseEventType.Success) ? new Func<T,T>(x => {
+                handler();
+                return x;
+            }) : null;
             Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => {
                 handler();
                 return default(T);
@@ -363,39 +345,11 @@
             // создаем прицепленное обещание
             var medium = new Promise<TNew>(this);
 
-            Action<T> resultHandler = result => medium.Resolve(mapper(result));
-            Func<Exception,T> errorHandler;
-            if (error != null)
-                errorHandler = e => {
-                    try {
-                        medium.Resolve(error(e));
-                    } catch (Exception e2) {
-                        // в случае ошибки нужно передать исключение дальше по цепочке
-                        medium.Reject(e2);
-                    }
-                    return default(T);
-                };
-            else
-                errorHandler = e => {
-                    medium.Reject(e);
-                    return default(T);
-                };
-
-            Action cancelHandler;
-            if (cancel != null)
-                cancelHandler = () => {
-                    cancel();
-                    medium.Cancel();
-                };
-            else
-                cancelHandler = medium.Cancel;
-
-
             AddHandler(
-                resultHandler,
-                errorHandler,
-                cancelHandler,
-                null,
+                mapper,
+                error,
+                cancel,
+                medium,
                 true
             );
 
@@ -431,9 +385,9 @@
             // передать через него результаты работы.
             var medium = new Promise<TNew>(this);
 
-            Action<T> resultHandler = delegate(T result) {
+            Func<T,T> resultHandler = delegate(T result) {
                 if (medium.IsCancelled)
-                    return;
+                    return default(T);
 
                 var promise = chained(result);
 
@@ -454,6 +408,8 @@
                             promise.Cancel();
                     }
                 );
+
+                return default(T);
             };
 
             Func<Exception,T> errorHandler;
@@ -534,7 +490,10 @@
             var medium = new Promise<T>(this);
 
             AddHandler(
-                x => handler(),
+                x => {
+                    handler();
+                    return x;
+                },
                 e => {
                     handler();
                     throw new TransientPromiseException(e);
@@ -600,16 +559,11 @@
             return Join(Timeout.Infinite);
         }
 
-        void AddHandler(Action<T> success, Func<Exception,T> error, Action cancel, Promise<T> medium, bool inc) {
+        void AddHandler<T2>(Func<T,T2> success, Func<Exception,T2> error, Action cancel, Promise<T2> medium, bool inc) {
             if (inc)
                 Interlocked.Increment(ref m_childrenCount);
 
-            var handler = new HandlerDescriptor {
-                resultHandler = success,
-                errorHandler = error,
-                cancellHandler = cancel,
-                medium = medium
-            };
+            AbstractHandler handler = new HandlerDescriptor<T2>(success, error, cancel, medium);
 
             bool queued;
 
@@ -631,7 +585,7 @@
                 InvokeHandler(handler);
         }
 
-        protected virtual void InvokeHandler(HandlerDescriptor handler) {
+        protected virtual void InvokeHandler(AbstractHandler handler) {
             switch (m_state) {
                 case SUCCEEDED_STATE:
                     handler.Resolve(m_result);
@@ -649,7 +603,7 @@
         }
 
         void OnStateChanged() {
-            HandlerDescriptor handler;
+            AbstractHandler handler;
             while (m_handlers.TryDequeue(out handler))
                 InvokeHandler(handler);
         }
@@ -688,16 +642,13 @@
                 var dest = i;
 
                 if (promises[i] != null) {
-                    promises[i].Then(
+                    promises[i].On(
                         x => {
                             result[dest] = x;
                             if (Interlocked.Decrement(ref pending) == 0)
                                 promise.Resolve(result);
                         },
-                        e => {
-                            promise.Reject(e);
-                            return default(T);
-                        }
+                        promise.Reject
                     );
                 } else {
                     if (Interlocked.Decrement(ref pending) == 0)
@@ -776,7 +727,10 @@
 
         IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) {
             return Then(
-                success != null ? new Action<T>(x => success()) : null,
+                success != null ? new Func<T,T>(x => {
+                    success();
+                    return x;
+                }) : null,
                 error != null ? new Func<Exception,T>(e => {
                     error(e);
                     return default(T);
@@ -787,7 +741,10 @@
 
         IPromise IPromise.Then(Action success, Action<Exception> error) {
             return Then(
-                success != null ? new Action<T>(x => success()) : null,
+                success != null ? new Func<T,T>(x => {
+                    success();
+                    return x;
+                }) : null,
                 error != null ? new Func<Exception,T>(e => {
                     error(e);
                     return default(T);
@@ -797,7 +754,10 @@
 
         IPromise IPromise.Then(Action success) {
             Safe.ArgumentNotNull(success, "success");
-            return Then(x => success());
+            return Then(x => {
+                success();
+                return x;
+            });
         }
 
         IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
@@ -809,9 +769,9 @@
 
             var medium = new Promise<object>(this);
 
-            Action<T> resultHandler = delegate {
+            Func<T,T> resultHandler = delegate {
                 if (medium.IsCancelled)
-                    return;
+                    return default(T);
 
                 var promise = chained();
 
@@ -828,6 +788,8 @@
                     if (promise.IsExclusive)
                         promise.Cancel();
                 });
+
+                return default(T);
             };
 
             Func<Exception,T> errorHandler;