diff Implab/Promise.cs @ 11:6ec82bf68c8e promises

refactoring
author cin
date Tue, 05 Nov 2013 01:09:58 +0400
parents aa33d0bb8c0c
children e943453e5039
line wrap: on
line diff
--- a/Implab/Promise.cs	Sun Nov 03 18:07:38 2013 +0400
+++ b/Implab/Promise.cs	Tue Nov 05 01:09:58 2013 +0400
@@ -7,7 +7,7 @@
 namespace Implab {
 
     public delegate void ErrorHandler(Exception e);
-
+    public delegate T ErrorHandler<out T>(Exception e);
     public delegate void ResultHandler<in T>(T result);
     public delegate TNew ResultMapper<in TSrc, out TNew>(TSrc result);
     public delegate Promise<TNew> ChainedOperation<in TSrc, TNew>(TSrc result);
@@ -126,52 +126,18 @@
             return Cancel(true);
         }
 
-        protected virtual void OnStateChanged() {
-            switch (m_state) {
-                case PromiseState.Resolved:
-                    foreach (var resultHandlerInfo in m_resultHandlers)
-                        try {
-                            if (resultHandlerInfo.resultHandler != null)
-                                resultHandlerInfo.resultHandler(m_result);
-                        } catch (Exception e) {
-                            try {
-                                if (resultHandlerInfo.errorHandler != null)
-                                    resultHandlerInfo.errorHandler(e);
-                            } catch { }
-                        }
-                    break;
-                case PromiseState.Cancelled:
-                    foreach (var cancelHandler in m_cancelHandlers)
-                        cancelHandler();
-                    break;
-                case PromiseState.Rejected:
-                    foreach (var resultHandlerInfo in m_resultHandlers)
-                        try {
-                            if (resultHandlerInfo.errorHandler != null)
-                                resultHandlerInfo.errorHandler(m_error);
-                        } catch { }
-                    break;
-                default:
-                    throw new InvalidOperationException(String.Format("Promise entered an invalid state {0}", m_state));
-            }
-
-            m_resultHandlers = null;
-            m_cancelHandlers = null;
-        }
-
         /// <summary>
-        /// Добавляет обработчики событий выполнения обещания.
+        /// Adds new handlers to this promise.
         /// </summary>
-        /// <param name="success">Обработчик успешного выполнения обещания.
-        /// Данному обработчику будет передан результат выполнения операции.</param>
-        /// <param name="error">Обработчик ошибки. Данный обработчик получит
-        /// исключение возникшее при выполнении операции.</param>
-        /// <returns>Само обещание</returns>
+        /// <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.</param>
+        /// <returns>The new promise chained to this one.</returns>
         public Promise<T> Then(ResultHandler<T> success, ErrorHandler error) {
             if (success == null && error == null)
                 return this;
 
-            var medium = new Promise<T>();
+            var medium = new Promise<T>(this, true);
 
             var handlerInfo = new ResultHandlerInfo();
 
@@ -198,14 +164,99 @@
             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 Promise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) {
+            if (success == null && error == null)
+                return this;
+
+            var medium = new Promise<T>(this, true);
+
+            var handlerInfo = new ResultHandlerInfo();
+
+            if (success != null)
+                handlerInfo.resultHandler = x => {
+                    success(x);
+                    medium.Resolve(x);
+                };
+            else
+                handlerInfo.resultHandler = medium.Resolve;
+
+            if (error != null)
+                handlerInfo.errorHandler = x => {
+                    try {
+                        medium.Resolve(error(x));
+                    } catch { }
+                    medium.Reject(x);
+                };
+            else
+                handlerInfo.errorHandler = medium.Reject;
+
+            AddHandler(handlerInfo);
+
+            return medium;
+        }
+
+
         public Promise<T> Then(ResultHandler<T> success) {
-            return Then(success, null);
+            if (success == null)
+                return this;
+
+            var medium = new Promise<T>(this, true);
+
+            var handlerInfo = new ResultHandlerInfo();
+
+            if (success != null)
+                handlerInfo.resultHandler = x => {
+                    success(x);
+                    medium.Resolve(x);
+                };
+            else
+                handlerInfo.resultHandler = medium.Resolve;
+
+            handlerInfo.errorHandler = medium.Reject;
+
+            AddHandler(handlerInfo);
+
+            return medium;
         }
 
         public Promise<T> Error(ErrorHandler error) {
             return Then(null, error);
         }
 
+        /// <summary>
+        /// Handles error and allows to keep the promise.
+        /// </summary>
+        /// <remarks>
+        /// If the specified handler throws an exception, this exception will be used to reject the promise.
+        /// </remarks>
+        /// <param name="handler">The error handler which returns the result of the promise.</param>
+        /// <returns>New promise.</returns>
+        public Promise<T> Error(ErrorHandler<T> handler) {
+            if (handler == null)
+                return this;
+
+            var medium = new Promise<T>(this, true);
+
+            AddHandler(new ResultHandlerInfo {
+                errorHandler = e => {
+                    try {
+                        medium.Resolve(handler(e));
+                    } catch (Exception e2) {
+                        medium.Reject(e2);
+                    }
+                }
+            });
+
+            return medium;
+        }
+
         public Promise<T> Anyway(Action handler) {
             if (handler == null)
                 return this;
@@ -295,9 +346,9 @@
                     // notify chained operation that it's not needed
                     medium.Cancelled(() => promise.Cancel());
                     promise.Then(
-                        medium.Resolve,
-                        medium.Reject
-                        );
+                        x => medium.Resolve(x),
+                        e => medium.Reject(e)
+                    );
                 },
                 errorHandler = delegate(Exception e) {
                     if (error != null)
@@ -416,6 +467,39 @@
             }
         }
 
+        protected virtual void OnStateChanged() {
+            switch (m_state) {
+                case PromiseState.Resolved:
+                    foreach (var resultHandlerInfo in m_resultHandlers)
+                        try {
+                            if (resultHandlerInfo.resultHandler != null)
+                                resultHandlerInfo.resultHandler(m_result);
+                        } catch (Exception e) {
+                            try {
+                                if (resultHandlerInfo.errorHandler != null)
+                                    resultHandlerInfo.errorHandler(e);
+                            } catch { }
+                        }
+                    break;
+                case PromiseState.Cancelled:
+                    foreach (var cancelHandler in m_cancelHandlers)
+                        cancelHandler();
+                    break;
+                case PromiseState.Rejected:
+                    foreach (var resultHandlerInfo in m_resultHandlers)
+                        try {
+                            if (resultHandlerInfo.errorHandler != null)
+                                resultHandlerInfo.errorHandler(m_error);
+                        } catch { }
+                    break;
+                default:
+                    throw new InvalidOperationException(String.Format("Promise entered an invalid state {0}", m_state));
+            }
+
+            m_resultHandlers = null;
+            m_cancelHandlers = null;
+        }
+
 
 
         public bool IsExclusive {
@@ -434,7 +518,7 @@
             }
         }
 
-        public bool Cancel(bool dependencies) {
+        protected bool Cancel(bool dependencies) {
             bool result;
 
             lock (m_lock) {
@@ -450,7 +534,7 @@
                 OnStateChanged();
 
             if (dependencies && m_parent != null && m_parent.IsExclusive) {
-                m_parent.Cancel(true);
+                m_parent.Cancel();
             }
 
             return result;