##// END OF EJS Templates
Fixed chaining of promises with 'Then' method
Fixed chaining of promises with 'Then' method

File last commit:

r119:2573b562e328 v2
r135:656815cb7147 v2
Show More
Promise.cs
258 lines | 8.1 KiB | text/x-csharp | CSharpLexer
cin
Promises rewritten, added improved version of AsyncQueue
r119 using System;
using System.Diagnostics;
namespace Implab {
public class Promise : AbstractPromise<Promise.HandlerDescriptor>, IPromise, IDeferred {
public struct HandlerDescriptor {
readonly Action m_success;
readonly Action<Exception> m_error;
readonly Action m_cancel;
readonly IDeferred m_deferred;
public HandlerDescriptor(Action success, Action<Exception> error, Action cancel, IDeferred deferred) {
m_success = success;
m_error = error;
m_cancel = cancel;
m_deferred = deferred;
}
public void SignalSuccess() {
if (m_success != null) {
try {
m_success();
if (m_deferred != null)
m_deferred.Resolve();
} catch (Exception err) {
SignalError(err);
}
}
}
public void SignalError(Exception err) {
if (m_error != null) {
try {
m_error(err);
if (m_deferred != null)
m_deferred.Resolve();
} catch (Exception err2) {
if (m_deferred != null)
m_deferred.Reject(err2);
}
} else {
if (m_deferred != null)
m_deferred.Reject(err);
}
}
public void SignalCancel() {
if (m_cancel != null) {
try {
m_cancel();
if (m_deferred != null)
m_deferred.Resolve();
} catch (Exception err) {
SignalError(err);
}
} else {
if (m_deferred != null)
m_deferred.Cancel();
}
}
}
public void Resolve() {
BeginSetResult();
EndSetResult();
}
public void Reject(Exception error) {
SetError(error);
}
#region implemented abstract members of AbstractPromise
protected override void SignalSuccess(HandlerDescriptor handler) {
handler.SignalSuccess();
}
protected override void SignalError(HandlerDescriptor handler, Exception error) {
handler.SignalError(error);
}
protected override void SignalCancelled(HandlerDescriptor handler) {
handler.SignalCancel();
}
protected override void Listen(PromiseEventType events, Action handler) {
AddHandler(new HandlerDescriptor(
events.HasFlag(PromiseEventType.Success) ? handler : null,
events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null,
events.HasFlag(PromiseEventType.Cancelled) ? handler : null,
null
));
}
#endregion
public Type PromiseType {
get {
return typeof(void);
}
}
public IPromise Then(Action success, Action<Exception> error, Action cancel) {
var promise = new Promise();
if (success != null)
promise.On(Cancel, PromiseEventType.Cancelled);
AddHandler(new HandlerDescriptor(success, error, cancel, promise));
return promise;
}
public IPromise Then(Action success, Action<Exception> error) {
return Then(success, error, null);
}
public IPromise Then(Action success) {
return Then(success, null, null);
}
public IPromise On(Action success, Action<Exception> error, Action cancel) {
AddHandler(new HandlerDescriptor(success, error, cancel, null));
return this;
}
public IPromise On(Action success, Action<Exception> error) {
return On(success, error, null);
}
public IPromise On(Action success) {
return On(success, null, null);
}
public IPromise On(Action handler, PromiseEventType events) {
return On(
events.HasFlag(PromiseEventType.Success) ? handler : null,
events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null,
events.HasFlag(PromiseEventType.Cancelled) ? handler : null
);
}
public IPromise<T> Cast<T>() {
throw new InvalidCastException();
}
public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<IPromise> cancel) {
var medium = new Promise();
On(
() => {
if (medium.IsCancelled)
return;
if (chained != null)
ConnectPromise(chained(), medium);
},
ex => {
if (medium.IsCancelled)
return;
if (error != null) {
try {
ConnectPromise(error(ex), medium);
} catch (Exception ex2) {
medium.Reject(ex2);
}
} else {
medium.Reject(ex);
}
},
() => {
if (medium.IsCancelled)
return;
if (cancel != null)
ConnectPromise(cancel(), medium);
else
medium.Cancel();
}
);
if (chained != null)
medium.On(Cancel, PromiseEventType.Cancelled);
return medium;
}
static void ConnectPromise(IPromise result, Promise medium) {
if (result != null) {
result.On(
medium.Resolve,
medium.Reject,
() => medium.Reject(new OperationCanceledException())
);
medium.On(result.Cancel, PromiseEventType.Cancelled);
} else {
medium.Reject(
new NullReferenceException(
"The chained asynchronous operation returned" +
" 'null' where the promise instance is expected"
)
);
}
}
public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error) {
return Chain(chained, error, null);
}
public IPromise Chain(Func<IPromise> chained) {
return Chain(chained, null, null);
}
public IPromise Error(Action<Exception> error) {
var promise = new Promise();
On(
null,
err => {
if (error != null)
try {
error(err);
promise.Resolve();
} catch (Exception err2) {
promise.Reject(err2);
}
else
promise.Reject(err);
}
);
return promise;
}
public IPromise Cancelled(Action handler) {
var promise = new Promise();
On(
null,
null,
() => {
if (handler != null) {
try {
handler();
promise.Resolve();
} catch (Exception err) {
promise.Reject(err);
}
} else {
promise.Cancel();
}
}
);
return promise;
}
}
}