changeset 75:4439140706d0 v2

major refactoring, added tasks support
author cin
date Wed, 10 Sep 2014 11:17:37 +0400
parents c4140283575c
children c761fc982e1d
files Implab.Fx.Test/Implab.Fx.Test.csproj Implab.Fx/Implab.Fx.csproj Implab.Test/Implab.Test.csproj Implab.sln Implab/IPromise.cs Implab/IPromiseT.cs Implab/Implab.csproj Implab/Parallels/ArrayTraits.cs Implab/Promise.cs Implab/PromiseExtensions.cs
diffstat 10 files changed, 221 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/Implab.Fx.Test/Implab.Fx.Test.csproj	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab.Fx.Test/Implab.Fx.Test.csproj	Wed Sep 10 11:17:37 2014 +0400
@@ -31,6 +31,23 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
     <Reference Include="System" />
--- a/Implab.Fx/Implab.Fx.csproj	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab.Fx/Implab.Fx.csproj	Wed Sep 10 11:17:37 2014 +0400
@@ -30,6 +30,23 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
--- a/Implab.Test/Implab.Test.csproj	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab.Test/Implab.Test.csproj	Wed Sep 10 11:17:37 2014 +0400
@@ -31,6 +31,23 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
     <Reference Include="System" />
--- a/Implab.sln	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab.sln	Wed Sep 10 11:17:37 2014 +0400
@@ -20,22 +20,40 @@
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
+		Debug 4.5|Any CPU = Debug 4.5|Any CPU
+		Release 4.5|Any CPU = Release 4.5|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+		{2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
 		{2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+		{2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
 		{2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
 		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
 		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
 		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
+		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
 		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
--- a/Implab/IPromise.cs	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab/IPromise.cs	Wed Sep 10 11:17:37 2014 +0400
@@ -27,16 +27,26 @@
         /// </summary>
         bool IsCancelled { get; }
 
-        IPromise Then(Action success,ErrorHandler error);
+        IPromise Then(Action success, ErrorHandler error, Action cancel);
+        IPromise Then(Action success, ErrorHandler error);
         IPromise Then(Action success);
+
+        /// <summary>
+        /// Добавляет последнй обработчик в цепочку обещаний, не создает промежуточных обещаний.
+        /// </summary>
+        /// <param name="success">Success.</param>
+        /// <param name="error">Error.</param>
+        /// <param name="cancel">Cancel.</param>
+        void Last(Action success, ErrorHandler error, Action cancel);
+        void Last(Action success, ErrorHandler error);
+        void Last(Action success);
+
         IPromise Error(ErrorHandler error);
         /// <summary>
         /// Обрабатывает либо ошибку, либо результат. Событие отмены не обрабатывается.
         /// </summary>
         /// <param name="handler">Обработчик.</param>
         /// <remarks>После обработке ошибки, она передается дальше.</remarks>
-        IPromise Anyway(Action handler);
-
         /// <summary>
         /// Обрабатывает либо ошибку, либо результат, либо отмену обещания.
         /// </summary>
--- a/Implab/IPromiseT.cs	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab/IPromiseT.cs	Wed Sep 10 11:17:37 2014 +0400
@@ -3,27 +3,35 @@
 using System.Linq;
 using System.Text;
 
-namespace Implab
-{
-    public interface IPromise<T>: IPromise
-    {
+namespace Implab {
+    public interface IPromise<T>: IPromise {
 
         new T Join();
+
         new T Join(int timeout);
 
+        IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel);
+
         IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error);
+
         IPromise<T> Then(ResultHandler<T> success);
+
+        void Last(ResultHandler<T> success, ErrorHandler error, Action cancel);
+        void Last(ResultHandler<T> success, ErrorHandler error);
+        void Last(ResultHandler<T> success);
+
         IPromise<T> Error(ErrorHandler<T> error);
 
-        IPromise<T2> Map<T2>(ResultMapper<T,T2> mapper, ErrorHandler<T> error);
-        IPromise<T2> Map<T2>(ResultMapper<T, T2> mapper);
+        IPromise<T2> Then<T2>(ResultMapper<T,T2> mapper, ErrorHandler<T> error);
+
+        IPromise<T2> Then<T2>(ResultMapper<T,T2> mapper);
 
-        IPromise<T2> Chain<T2>(ChainedOperation<T, T2> chained, ErrorHandler<T> error);
-        IPromise<T2> Chain<T2>(ChainedOperation<T, T2> chained);
+        IPromise<T2> Then<T2>(ChainedOperation<T, T2> chained, ErrorHandler<T> error);
+
+        IPromise<T2> Then<T2>(ChainedOperation<T, T2> chained);
 
         new IPromise<T> Cancelled(Action handler);
+
         new IPromise<T> Finally(Action handler);
-        new IPromise<T> Anyway(Action handler);
-
     }
 }
--- a/Implab/Implab.csproj	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab/Implab.csproj	Wed Sep 10 11:17:37 2014 +0400
@@ -29,6 +29,25 @@
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+    <DefineConstants>NET_4_5</DefineConstants>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Xml" />
--- a/Implab/Parallels/ArrayTraits.cs	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab/Parallels/ArrayTraits.cs	Wed Sep 10 11:17:37 2014 +0400
@@ -29,8 +29,7 @@
                 m_pending = source.Length;
                 m_action = action;
 
-                m_promise.Anyway(() => Dispose());
-                m_promise.Cancelled(() => Dispose());
+                m_promise.Finally(Dispose);
 
                 InitPool();
             }
@@ -48,7 +47,7 @@
 
             protected override bool TryDequeue(out int unit) {
                 unit = Interlocked.Increment(ref m_next) - 1;
-                return unit >= m_source.Length ? false : true;
+                return unit < m_source.Length;
             }
 
             protected override void InvokeUnit(int unit) {
@@ -86,8 +85,7 @@
                 m_transform = transform;
                 m_traceContext = TraceContext.Snapshot();
 
-                m_promise.Anyway(() => Dispose());
-                m_promise.Cancelled(() => Dispose());
+                m_promise.Finally(Dispose);
 
                 InitPool();
             }
@@ -157,16 +155,17 @@
 
             var semaphore = new Semaphore(threads, threads);
 
+            // Analysis disable AccessToDisposedClosure
             AsyncPool.InvokeNewThread(() => {
                 for (int i = 0; i < source.Length; i++) {
                     if(promise.IsResolved)
                         break; // stop processing in case of error or cancellation
                     var idx = i;
+
                     semaphore.WaitOne();
                     try {
                         var p1 = transform(source[i]);
-                        p1.Anyway(() => semaphore.Release());
-                        p1.Cancelled(() => semaphore.Release());
+                        p1.Finally(() => semaphore.Release());
                         p1.Then(
                             x => {
                                 res[idx] = x;
@@ -187,7 +186,7 @@
                 return 0;
             });
 
-            return promise.Anyway(() => semaphore.Dispose());
+            return promise.Finally(semaphore.Dispose);
         }
 
     }
--- a/Implab/Promise.cs	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab/Promise.cs	Wed Sep 10 11:17:37 2014 +0400
@@ -225,6 +225,18 @@
             Cancel();
         }
 
+
+        public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel) {
+            if (success == null && error == null && cancel == null)
+                return this;
+
+            var medium = new Promise<T>(this, true);
+
+            AddHandler(success, error, cancel, medium);
+
+            return medium;
+        }
+
         /// <summary>
         /// Adds new handlers to this promise.
         /// </summary>
@@ -243,6 +255,17 @@
             return medium;
         }
 
+        public IPromise Then(Action success, ErrorHandler error, Action cancel) {
+            return Then(
+                x => success(),
+                e => {
+                    error(e);
+                    return default(T);
+                },
+                cancel
+            );
+        }
+
         public IPromise Then(Action success, ErrorHandler error) {
             return Then(
                 x => success(),
@@ -269,6 +292,39 @@
             return medium;
         }
 
+        public void Last(ResultHandler<T> success, ErrorHandler error, Action cancel) {
+            if (success == null && error == null && cancel == null)
+                return;
+
+            ErrorHandler<T> errorHandler = null;
+            if (error != null)
+                errorHandler = err => {
+                    error(err);
+                    return default(T);
+                };
+            AddHandler(success, errorHandler, cancel, null);
+        }
+
+        public void Last(ResultHandler<T> success, ErrorHandler error) {
+            Last(success, error, null);
+        }
+
+        public void Last(ResultHandler<T> success) {
+            Last(success, null, null);
+        }
+
+        public void Last(Action success,ErrorHandler error, Action cancel) {
+            Last(x => success(), error, cancel);
+        }
+
+        public void Last(Action success,ErrorHandler error) {
+            Last(x => success(), error, null);
+        }
+
+        public void Last(Action success) {
+            Last(x => success(), null, null);
+        }
+
         public IPromise Error(ErrorHandler error) {
             if (error == null)
                 return this;
@@ -307,25 +363,6 @@
             return medium;
         }
 
-        public IPromise<T> Anyway(Action handler) {
-            if (handler == null)
-                return this;
-
-            var medium = new Promise<T>(this, true);
-
-            AddHandler(
-                x => handler(),
-                e => {
-                    handler();
-                    throw new TransientPromiseException(e);
-                },
-                null,
-                medium
-            );
-
-            return medium;
-        }
-
         /// <summary>
         /// Позволяет преобразовать результат выполения операции к новому типу.
         /// </summary>
@@ -334,7 +371,7 @@
         /// <param name="error">Обработчик ошибки. Данный обработчик получит
         /// исключение возникшее при выполнении операции.</param>
         /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns>
-        public IPromise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<T> error) {
+        public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<T> error) {
             if (mapper == null)
                 throw new ArgumentNullException("mapper");
 
@@ -370,8 +407,8 @@
             return chained;
         }
 
-        public IPromise<TNew> Map<TNew>(ResultMapper<T, TNew> mapper) {
-            return Map(mapper, null);
+        public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper) {
+            return Then(mapper, null);
         }
 
         /// <summary>
@@ -384,7 +421,7 @@
         /// <param name="error">Обработчик ошибки. Данный обработчик получит
         /// исключение возникшее при выполнении текуещй операции.</param>
         /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns>
-        public IPromise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained, ErrorHandler<T> error) {
+        public IPromise<TNew> Then<TNew>(ChainedOperation<T, TNew> chained, ErrorHandler<T> error) {
 
             // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно
             // создать посредника, к которому будут подвызяваться следующие обработчики.
@@ -442,8 +479,8 @@
             return medium;
         }
 
-        public IPromise<TNew> Chain<TNew>(ChainedOperation<T, TNew> chained) {
-            return Chain(chained, null);
+        public IPromise<TNew> Then<TNew>(ChainedOperation<T, TNew> chained) {
+            return Then(chained, null);
         }
 
         public IPromise<T> Cancelled(Action handler) {
@@ -478,7 +515,7 @@
         /// <typeparam name="T2"></typeparam>
         /// <returns></returns>
         public IPromise<T2> Cast<T2>() {
-            return Map(x => (T2)(object)x, null);
+            return Then(x => (T2)(object)x, null);
         }
 
         /// <summary>
@@ -504,8 +541,7 @@
         /// <returns>Результат выполнения обещания</returns>
         public T Join(int timeout) {
             var evt = new ManualResetEvent(false);
-            Anyway(() => evt.Set());
-            Cancelled(() => evt.Set());
+            Finally(() => evt.Set());
 
             if (!evt.WaitOne(timeout, true))
                 throw new TimeoutException();
@@ -704,10 +740,6 @@
             return Error(error);
         }
 
-        IPromise IPromise.Anyway(Action handler) {
-            return Anyway(handler);
-        }
-
         IPromise IPromise.Finally(Action handler) {
             return Finally(handler);
         }
--- a/Implab/PromiseExtensions.cs	Mon Sep 08 17:40:46 2014 +0400
+++ b/Implab/PromiseExtensions.cs	Wed Sep 10 11:17:37 2014 +0400
@@ -1,8 +1,13 @@
 using System.Threading;
+using System;
+#if NET_4_5
+using System.Threading.Tasks;
+#endif
 
 namespace Implab {
     public static class PromiseExtensions {
         public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
+            Safe.ArgumentNotNull(that, "that");
             var context = SynchronizationContext.Current;
             if (context == null)
                 return that;
@@ -20,6 +25,7 @@
         }
 
         public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
+            Safe.ArgumentNotNull(that, "that");
             Safe.ArgumentNotNull(context, "context");
 
             var p = new SyncContextPromise<T>(context, that, true);
@@ -33,6 +39,31 @@
             );
             return p;
         }
+
+        public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
+            Safe.ArgumentNotNull(that, "that");
+            Safe.ArgumentNotNull(callback, "callback");
+            return ar => {
+                try {
+                    that.Resolve(callback(ar));
+                } catch (Exception err) {
+                    that.Reject(err);
+                }
+            };
+        }
+            
+        #if NET_4_5
+
+        public static Task<T> GetTask<T>(this IPromise<T> that) {
+            Safe.ArgumentNotNull(that, "that");
+            var tcs = new TaskCompletionSource<T>();
+
+            that.Last(tcs.SetResult, tcs.SetException, tcs.SetCanceled);
+
+            return tcs.Task;
+        }
+
+        #endif
     }
 }