Promise.cs
222 lines
| 7.4 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; | ||||
cin
|
r138 | readonly Action<Exception> m_cancel; | ||
cin
|
r119 | readonly IDeferred m_deferred; | ||
cin
|
r138 | public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel, IDeferred deferred) { | ||
cin
|
r119 | 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); | ||||
} | ||||
} | ||||
cin
|
r138 | public void SignalCancel(Exception reason) { | ||
cin
|
r119 | if (m_cancel != null) { | ||
try { | ||||
cin
|
r138 | 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)); | ||||
cin
|
r119 | if (m_deferred != null) | ||
m_deferred.Resolve(); | ||||
} catch (Exception err) { | ||||
SignalError(err); | ||||
} | ||||
} else { | ||||
if (m_deferred != null) | ||||
cin
|
r138 | m_deferred.Cancel(reason); | ||
cin
|
r119 | } | ||
} | ||||
} | ||||
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); | ||||
} | ||||
cin
|
r138 | protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) { | ||
handler.SignalCancel(reason); | ||||
cin
|
r119 | } | ||
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, | ||||
cin
|
r138 | events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null, | ||
cin
|
r119 | null | ||
)); | ||||
} | ||||
#endregion | ||||
public Type PromiseType { | ||||
get { | ||||
return typeof(void); | ||||
} | ||||
} | ||||
cin
|
r138 | public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) { | ||
cin
|
r119 | 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); | ||||
} | ||||
cin
|
r138 | public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) { | ||
cin
|
r119 | 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, | ||||
cin
|
r138 | events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null | ||
cin
|
r119 | ); | ||
} | ||||
public IPromise<T> Cast<T>() { | ||||
throw new InvalidCastException(); | ||||
} | ||||
cin
|
r138 | public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception,IPromise> cancel) { | ||
cin
|
r119 | 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); | ||||
} | ||||
}, | ||||
cin
|
r138 | reason => { | ||
cin
|
r119 | if (medium.IsCancelled) | ||
return; | ||||
if (cancel != null) | ||||
cin
|
r138 | ConnectPromise(cancel(reason), medium); | ||
cin
|
r119 | else | ||
cin
|
r138 | medium.Cancel(reason); | ||
cin
|
r119 | } | ||
); | ||||
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, | ||||
cin
|
r138 | medium.Cancel | ||
cin
|
r119 | ); | ||
cin
|
r138 | medium.On(null,null,result.Cancel); | ||
cin
|
r119 | } 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); | ||||
} | ||||
} | ||||
} | ||||