##// END OF EJS Templates
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.

File last commit:

r185:822aab37b107 ref20160224
r196:40d7fed4a09e default
Show More
PromiseExtensions.cs
289 lines | 10.8 KiB | text/x-csharp | CSharpLexer
/ Implab / PromiseExtensions.cs
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
}
}