changeset 11:6ec82bf68c8e promises

refactoring
author cin
date Tue, 05 Nov 2013 01:09:58 +0400
parents aa33d0bb8c0c
children eb418ba8275b
files Implab.Test/AsyncTests.cs Implab.Test/PromiseHelper.cs Implab.v11.suo Implab/AsyncPool.cs Implab/IPromise.cs Implab/Implab.csproj Implab/Parallels/AsyncPool.cs Implab/Promise.cs
diffstat 8 files changed, 178 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Test/AsyncTests.cs	Sun Nov 03 18:07:38 2013 +0400
+++ b/Implab.Test/AsyncTests.cs	Tue Nov 05 01:09:58 2013 +0400
@@ -2,6 +2,7 @@
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using System.Reflection;
 using System.Threading;
+using Implab.Parallels;
 
 namespace Implab.Test
 {
@@ -70,6 +71,17 @@
 		}
 
         [TestMethod]
+        public void FixErrorTest() {
+            var p = new Promise<int>();
+
+            var p2 = p.Error(e => 101);
+
+            p.Reject(new Exception());
+
+            Assert.AreEqual(p2.Join(), 101);
+        }
+
+        [TestMethod]
 		public void ChainTest ()
 		{
 			var p1 = new Promise<int> ();
--- a/Implab.Test/PromiseHelper.cs	Sun Nov 03 18:07:38 2013 +0400
+++ b/Implab.Test/PromiseHelper.cs	Tue Nov 05 01:09:58 2013 +0400
@@ -1,4 +1,5 @@
-using System;
+using Implab.Parallels;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
Binary file Implab.v11.suo has changed
--- a/Implab/AsyncPool.cs	Sun Nov 03 18:07:38 2013 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Implab {
-	/// <summary>
-	/// Класс для распаралеливания задач.
-	/// </summary>
-	/// <remarks>
-	/// Используя данный класс и лямда выражения можно распараллелить
-	/// вычисления, для этого используется концепция обещаний.
-	/// </remarks>
-	public static class AsyncPool {
-
-		public static Promise<T> Invoke<T>(Func<T> func) {
-			var p = new Promise<T>();
-
-			ThreadPool.QueueUserWorkItem(param => {
-				try {
-					p.Resolve(func());
-				} catch(Exception e) {
-					p.Reject(e);
-				}
-			});
-
-			return p;
-		}
-	}
-}
--- a/Implab/IPromise.cs	Sun Nov 03 18:07:38 2013 +0400
+++ b/Implab/IPromise.cs	Tue Nov 05 01:09:58 2013 +0400
@@ -24,11 +24,10 @@
         }
 
         /// <summary>
-        /// Tries to cancel the promise or the complete chain.
+        /// Tries to cancel the the complete chain of promises.
         /// </summary>
-        /// <param name="dependencies">Try to cancel the whole promise chain, the parent promise will be cancelled only if it has only one promise</param>
-        /// <returns></returns>
-        bool Cancel(bool dependencies);
+        /// <returns><c>true</c> -  if the promise has been cancelled, otherwise the promise will be resolved (or resolved already).</returns>
+        bool Cancel();
 
         /// <summary>
         /// Registers handler for the case when the promise is cencelled. If the promise already cancelled the
--- a/Implab/Implab.csproj	Sun Nov 03 18:07:38 2013 +0400
+++ b/Implab/Implab.csproj	Tue Nov 05 01:09:58 2013 +0400
@@ -38,12 +38,10 @@
     <Compile Include="ProgressInitEventArgs.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Promise.cs" />
-    <Compile Include="AsyncPool.cs" />
+    <Compile Include="Parallels\AsyncPool.cs" />
     <Compile Include="Safe.cs" />
     <Compile Include="ValueEventArgs.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <Folder Include="Parallels\" />
-  </ItemGroup>
+  <ItemGroup />
 </Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Parallels/AsyncPool.cs	Tue Nov 05 01:09:58 2013 +0400
@@ -0,0 +1,28 @@
+using System;
+using System.Threading;
+
+namespace Implab.Parallels {
+	/// <summary>
+	/// Класс для распаралеливания задач.
+	/// </summary>
+	/// <remarks>
+	/// Используя данный класс и лямда выражения можно распараллелить
+	/// вычисления, для этого используется концепция обещаний.
+	/// </remarks>
+	public static class AsyncPool {
+
+		public static Promise<T> Invoke<T>(Func<T> func) {
+			var p = new Promise<T>();
+
+			ThreadPool.QueueUserWorkItem(param => {
+				try {
+					p.Resolve(func());
+				} catch(Exception e) {
+					p.Reject(e);
+				}
+			});
+
+			return p;
+		}
+	}
+}
--- 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;