changeset 207:558f34b2fb50 v2

added Safe.DispatchEvent() a legacy equivalent for '?.Invoke()' added Safe.Dispose(IEnumerable) added PromiseExtensions.CancellationPoint to add a cancellation point to the chain of promises added IPromise<T> PromiseExtensions.Then<T>(this IPromise<T> that, Action<T> success) overloads added PromiseExtensions.Error() overloads to handle a error or(and) a cancellation
author cin
date Wed, 09 Nov 2016 12:03:22 +0300
parents 86b61d53b7db
children 7d07503621fe
files Implab/Components/StateChangeEventArgs.cs Implab/PromiseExtensions.cs Implab/Safe.cs
diffstat 3 files changed, 159 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/Implab/Components/StateChangeEventArgs.cs	Tue Oct 25 17:40:45 2016 +0300
+++ b/Implab/Components/StateChangeEventArgs.cs	Wed Nov 09 12:03:22 2016 +0300
@@ -2,7 +2,7 @@
 
 namespace Implab.Components
 {
-    public class StateChangeEventArgs {
+    public class StateChangeEventArgs : EventArgs {
         /// <summary>
         /// The error information if any
         /// </summary>
--- a/Implab/PromiseExtensions.cs	Tue Oct 25 17:40:45 2016 +0300
+++ b/Implab/PromiseExtensions.cs	Wed Nov 09 12:03:22 2016 +0300
@@ -47,7 +47,7 @@
         /// <param name="cleanup">Cleanup.</param>
         /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
         /// <typeparam name="T">The 2nd type parameter.</typeparam>
-        public static TPromise EnsureDispatched<TPromise,T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise{
+        public static TPromise EnsureDispatched<TPromise, T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise {
             Safe.ArgumentNotNull(that, "that");
             Safe.ArgumentNotNull(head, "head");
 
@@ -56,12 +56,37 @@
             return that;
         }
 
-        public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
+        /// <summary>
+        /// Adds a cancellation point to the chain of promises. When a cancellation request reaches the cancellation point the operation is
+        /// cancelled immediatelly, and the request is passed towards. If the operation at the higher level can not be cancelled is't result
+        /// will be collected with <paramref name="cleanup"/> callback.
+        /// </summary>
+        /// <typeparam name="T">The type of the promise result.</typeparam>
+        /// <param name="that">The promise to which the cancellation point should be attached.</param>
+        /// <param name="cleanup">The callback which is used to cleanup the result of the operation if the cancellation point is cancelled already.</param>
+        /// <returns>The promise</returns>
+        public static IPromise<T> CancellationPoint<T>(this IPromise<T> that, Action<T> cleanup) {
+            var meduim = new Promise<T>();
+
+            that.On(meduim.Resolve, meduim.Reject, meduim.CancelOperation);
+
+            meduim.CancellationRequested(that.Cancel);
+            meduim.CancellationRequested(meduim.CancelOperation);
+
+            if (cleanup != null)
+                meduim.On((Action<T>)null, null, (e) => {
+                    that.On(cleanup);
+                });
+
+            return meduim;
+        }
+
+        public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult, T> callback) {
             Safe.ArgumentNotNull(that, "that");
             Safe.ArgumentNotNull(callback, "callback");
             var op = TraceContext.Instance.CurrentOperation;
             return ar => {
-                TraceContext.Instance.EnterLogicalOperation(op,false);
+                TraceContext.Instance.EnterLogicalOperation(op, false);
                 try {
                     that.Resolve(callback(ar));
                 } catch (Exception err) {
@@ -74,9 +99,9 @@
 
         static void CancelByTimeoutCallback(object cookie) {
             ((ICancellable)cookie).Cancel(new TimeoutException());
-        }
-
-/// <summary>
+        }
+
+        /// <summary>
         /// Cancells promise after the specified timeout is elapsed.
         /// </summary>
         /// <param name="that">The promise to cancel on timeout.</param>
@@ -112,7 +137,7 @@
             }
 
             medium.On(() => {
-                foreach(var p2 in that)
+                foreach (var p2 in that)
                     p2.Cancel();
             }, PromiseEventType.ErrorOrCancel);
 
@@ -148,7 +173,7 @@
             var results = new T[that.Count];
 
             medium.On(() => {
-                foreach(var p2 in that)
+                foreach (var p2 in that)
                     p2.Cancel();
             }, PromiseEventType.ErrorOrCancel);
 
@@ -216,12 +241,36 @@
 
         public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) {
             Safe.ArgumentNotNull(that, "that");
-            var d = new FuncTask<T,T2>(success, error, cancel, false);
+            var d = new FuncTask<T, T2>(success, error, cancel, false);
             that.On(d.Resolve, d.Reject, d.CancelOperation);
             d.CancellationRequested(that.Cancel);
             return d;
         }
 
+        public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
+            Safe.ArgumentNotNull(that, "that");
+            var d = new FuncTask<T, T>(
+                x => {
+                    success(x);
+                    return x;
+                },
+                error, 
+                cancel, 
+                false
+            );
+            that.On(d.Resolve, d.Reject, d.CancelOperation);
+            d.CancellationRequested(that.Cancel);
+            return d;
+        }
+
+        public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error) {
+            return Then(that, success, error, null);
+        }
+
+        public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success) {
+            return Then(that, success, null, null);
+        }
+
         public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) {
             return Then(that, success, error, null);
         }
@@ -230,8 +279,79 @@
             return Then(that, success, null, null);
         }
 
+        public static IPromise<T> Always<T>(this IPromise<T> that, Action handler) {
+            Func<Exception, T> errorOrCancel;
+            if (handler != null)
+                errorOrCancel = e => {
+                    handler();
+                    throw new PromiseTransientException(e);
+                };
+            else
+                errorOrCancel = null;
+
+            return Then(
+                that,
+                x => {
+                    handler();
+                    return x;
+                },
+                errorOrCancel,
+                errorOrCancel);
+        }
+
+        public static IPromise Always(this IPromise that, Action handler) {
+            Action<Exception> errorOrCancel;
+            if (handler != null)
+                errorOrCancel = e => {
+                    handler();
+                    throw new PromiseTransientException(e);
+                };
+            else
+                errorOrCancel = null;
+
+            return Then(
+                that,
+                handler,
+                errorOrCancel,
+                errorOrCancel);
+        }
+
+        public static IPromise Error(this IPromise that, Action<Exception> handler, bool handleCancellation) {
+            Action<Exception> errorOrCancel;
+            if (handler != null)
+                errorOrCancel = e => {
+                    handler(e);
+                    throw new PromiseTransientException(e);
+                };
+            else
+                errorOrCancel = null;
+
+            return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null);
+        }
+
+        public static IPromise Error(this IPromise that, Action<Exception> handler) {
+            return Error(that, handler, false);
+        }
+
+        public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler, bool handleCancellation) {
+            Func<Exception, T> errorOrCancel;
+            if (handler != null)
+                errorOrCancel = e => {
+                    handler(e);
+                    throw new PromiseTransientException(e);
+                };
+            else
+                errorOrCancel = null;
+
+            return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null);
+        }
+
+        public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler) {
+            return Error(that, handler, false);
+        }
+
         #region chain traits
-        public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error, Func<Exception,IPromise> cancel) {
+        public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) {
             Safe.ArgumentNotNull(that, "that");
 
             var d = new ActionChainTask(success, error, cancel, false);
@@ -240,7 +360,7 @@
             return d;
         }
 
-        public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error) {
+        public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error) {
             return Chain(that, success, error, null);
         }
 
@@ -268,7 +388,7 @@
 
         public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) {
             Safe.ArgumentNotNull(that, "that");
-            var d = new FuncChainTask<T,T2>(success, error, cancel, false);
+            var d = new FuncChainTask<T, T2>(success, error, cancel, false);
             that.On(d.Resolve, d.Reject, d.CancelOperation);
             if (success != null)
                 d.CancellationRequested(that.Cancel);
@@ -281,20 +401,20 @@
 
         public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) {
             return Chain(that, success, null, null);
-        }
-
+        }
+
         #endregion
-
-            
-        #if NET_4_5
-
+
+
+#if NET_4_5
+
         public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
             Safe.ArgumentNotNull(that, "that");
 
             return new PromiseAwaiter<T>(that);
-        }
-
-        #endif
+        }
+
+#endif
     }
 }
 
--- a/Implab/Safe.cs	Tue Oct 25 17:40:45 2016 +0300
+++ b/Implab/Safe.cs	Wed Nov 09 12:03:22 2016 +0300
@@ -4,6 +4,7 @@
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Diagnostics;
+using System.Collections;
 
 namespace Implab
 {
@@ -60,12 +61,28 @@
             }
         }
 
+        public static void Dispose(IEnumerable<IDisposable> objects) {
+            foreach (var d in objects)
+                if (d != null)
+                    d.Dispose();
+        }
+
         public static void Dispose(object obj) {
             var d = obj as IDisposable;
             if (d != null)
                 d.Dispose();
         }
 
+        public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
+            if (handler != null)
+                handler(sender, args);
+        }
+
+        public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
+            if (handler != null)
+                handler(sender, args);
+        }
+
         [DebuggerStepThrough]
         public static IPromise<T> Run<T>(Func<T> action) {
             ArgumentNotNull(action, "action");