|
|
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<Exception> m_cancel;
|
|
|
readonly IDeferred m_deferred;
|
|
|
|
|
|
public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> 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(Exception reason) {
|
|
|
if (m_cancel != null) {
|
|
|
try {
|
|
|
m_cancel(reason);
|
|
|
if (m_deferred != null)
|
|
|
m_deferred.Resolve();
|
|
|
} catch (Exception err) {
|
|
|
SignalError(err);
|
|
|
}
|
|
|
} else if (reason != null && m_error != null) {
|
|
|
try {
|
|
|
m_error(new OperationCanceledException("The operation was canceled.", reason));
|
|
|
if (m_deferred != null)
|
|
|
m_deferred.Resolve();
|
|
|
} catch (Exception err) {
|
|
|
SignalError(err);
|
|
|
}
|
|
|
} else {
|
|
|
if (m_deferred != null)
|
|
|
m_deferred.Cancel(reason);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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, Exception reason) {
|
|
|
handler.SignalCancel(reason);
|
|
|
}
|
|
|
|
|
|
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) ? new Action<Exception>(reason => handler()) : null,
|
|
|
null
|
|
|
));
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
public Type PromiseType {
|
|
|
get {
|
|
|
return typeof(void);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public IPromise Then(Action success, Action<Exception> error, Action<Exception> 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<Exception> 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) ? new Action<Exception>(reason => handler()) : null
|
|
|
);
|
|
|
}
|
|
|
|
|
|
public IPromise<T> Cast<T>() {
|
|
|
throw new InvalidCastException();
|
|
|
}
|
|
|
|
|
|
public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception,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);
|
|
|
}
|
|
|
},
|
|
|
reason => {
|
|
|
if (medium.IsCancelled)
|
|
|
return;
|
|
|
if (cancel != null)
|
|
|
ConnectPromise(cancel(reason), medium);
|
|
|
else
|
|
|
medium.Cancel(reason);
|
|
|
}
|
|
|
);
|
|
|
|
|
|
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.Cancel
|
|
|
);
|
|
|
medium.On(null,null,result.Cancel);
|
|
|
} 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);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|