Promise.cs
258 lines
| 8.1 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / Promise.cs
cin
|
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; | ||||
} | ||||
} | ||||
} | ||||