diff Implab/PromiseExtensions.cs @ 192:f1da3afc3521 release v2.1

Слияние с v2
author cin
date Fri, 22 Apr 2016 13:10:34 +0300
parents 822aab37b107
children 8200ab154c8a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/PromiseExtensions.cs	Fri Apr 22 13:10:34 2016 +0300
@@ -0,0 +1,289 @@
+using System.Threading;
+using System;
+using Implab.Diagnostics;
+using System.Collections.Generic;
+
+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;
+
+            var p = new SyncContextPromise<T>(context);
+            p.CancellationRequested(that.Cancel);
+
+            that.On(
+                p.Resolve,
+                p.Reject,
+                p.CancelOperation
+            );
+            return p;
+        }
+
+        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);
+            p.CancellationRequested(that.Cancel);
+
+            that.On(
+                p.Resolve,
+                p.Reject,
+                p.CancelOperation
+            );
+            return p;
+        }
+
+        /// <summary>
+        /// Ensures the dispatched.
+        /// </summary>
+        /// <returns>The dispatched.</returns>
+        /// <param name="that">That.</param>
+        /// <param name="head">Head.</param>
+        /// <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{
+            Safe.ArgumentNotNull(that, "that");
+            Safe.ArgumentNotNull(head, "head");
+
+            that.On(() => head.On(cleanup), PromiseEventType.Cancelled);
+
+            return that;
+        }
+
+        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);
+                try {
+                    that.Resolve(callback(ar));
+                } catch (Exception err) {
+                    that.Reject(err);
+                } finally {
+                    TraceContext.Instance.Leave();
+                }
+            };
+        }
+
+        static void CancelByTimeoutCallback(object cookie) {
+            ((ICancellable)cookie).Cancel(new TimeoutException());
+        }
+
+        /// <summary>
+        /// Cancells promise after the specified timeout is elapsed.
+        /// </summary>
+        /// <param name="that">The promise to cancel on timeout.</param>
+        /// <param name="milliseconds">The timeout in milliseconds.</param>
+        /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
+        public static TPromise Timeout<TPromise>(this TPromise that, int milliseconds) where TPromise : IPromise {
+            Safe.ArgumentNotNull(that, "that");
+            var timer = new Timer(CancelByTimeoutCallback, that, milliseconds, -1);
+            that.On(timer.Dispose, PromiseEventType.All);
+            return that;
+        }
+
+        public static IPromise Bundle(this ICollection<IPromise> that) {
+            Safe.ArgumentNotNull(that, "that");
+
+            int count = that.Count;
+            int errors = 0;
+            var medium = new Promise();
+
+            if (count == 0) {
+                medium.Resolve();
+                return medium;
+            }
+
+            medium.On(() => {
+                foreach(var p2 in that)
+                    p2.Cancel();
+            }, PromiseEventType.ErrorOrCancel);
+
+            foreach (var p in that)
+                p.On(
+                    () => {
+                        if (Interlocked.Decrement(ref count) == 0)
+                            medium.Resolve();
+                    },
+                    error => {
+                        if (Interlocked.Increment(ref errors) == 1)
+                            medium.Reject(
+                                new Exception("The dependency promise is failed", error)
+                            );
+                    },
+                    reason => {
+                        if (Interlocked.Increment(ref errors) == 1)
+                            medium.Cancel(
+                                new Exception("The dependency promise is cancelled")
+                            );
+                    }
+                );
+
+            return medium;
+        }
+
+        public static IPromise<T[]> Bundle<T>(this ICollection<IPromise<T>> that) {
+            Safe.ArgumentNotNull(that, "that");
+
+            int count = that.Count;
+            int errors = 0;
+            var medium = new Promise<T[]>();
+            var results = new T[that.Count];
+
+            medium.On(() => {
+                foreach(var p2 in that)
+                    p2.Cancel();
+            }, PromiseEventType.ErrorOrCancel);
+
+            int i = 0;
+            foreach (var p in that) {
+                var idx = i;
+                p.On(
+                    x => {
+                        results[idx] = x;
+                        if (Interlocked.Decrement(ref count) == 0)
+                            medium.Resolve(results);
+                    },
+                    error => {
+                        if (Interlocked.Increment(ref errors) == 1)
+                            medium.Reject(
+                                new Exception("The dependency promise is failed", error)
+                            );
+                    },
+                    reason => {
+                        if (Interlocked.Increment(ref errors) == 1)
+                            medium.Cancel(
+                                new Exception("The dependency promise is cancelled", reason)
+                            );
+                    }
+                );
+                i++;
+            }
+
+            return medium;
+        }
+
+        public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) {
+            Safe.ArgumentNotNull(that, "that");
+
+            var d = new ActionTask(success, error, cancel, false);
+            that.On(d.Resolve, d.Reject, d.CancelOperation);
+            d.CancellationRequested(that.Cancel);
+            return d;
+        }
+
+        public static IPromise Then(this IPromise that, Action success, Action<Exception> error) {
+            return Then(that, success, error, null);
+        }
+
+        public static IPromise Then(this IPromise that, Action success) {
+            return Then(that, success, null, null);
+        }
+
+        public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
+            Safe.ArgumentNotNull(that, "that");
+
+            var d = new FuncTask<T>(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 that, Func<T> success, Func<Exception, T> error) {
+            return Then(that, success, error, null);
+        }
+
+        public static IPromise<T> Then<T>(this IPromise that, Func<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, Func<Exception, T2> cancel) {
+            Safe.ArgumentNotNull(that, "that");
+            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<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) {
+            return Then(that, success, error, null);
+        }
+
+        public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success) {
+            return Then(that, success, null, null);
+        }
+
+        #region chain traits
+        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);
+            that.On(d.Resolve, d.Reject, d.CancelOperation);
+            d.CancellationRequested(that.Cancel);
+            return d;
+        }
+
+        public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error) {
+            return Chain(that, success, error, null);
+        }
+
+        public static IPromise Chain(this IPromise that, Func<IPromise> success) {
+            return Chain(that, success, null, null);
+        }
+
+        public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error, Func<Exception, IPromise<T>> cancel) {
+            Safe.ArgumentNotNull(that, "that");
+
+            var d = new FuncChainTask<T>(success, error, cancel, false);
+            that.On(d.Resolve, d.Reject, d.CancelOperation);
+            if (success != null)
+                d.CancellationRequested(that.Cancel);
+            return d;
+        }
+
+        public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error) {
+            return Chain(that, success, error, null);
+        }
+
+        public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success) {
+            return Chain(that, success, null, null);
+        }
+
+        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);
+            that.On(d.Resolve, d.Reject, d.CancelOperation);
+            if (success != null)
+                d.CancellationRequested(that.Cancel);
+            return d;
+        }
+
+        public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error) {
+            return Chain(that, success, error, null);
+        }
+
+        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
+
+        public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
+            Safe.ArgumentNotNull(that, "that");
+
+            return new PromiseAwaiter<T>(that);
+        }
+
+        #endif
+    }
+}
+