Promise`1.cs
159 lines
| 3.9 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / Promise`1.cs
cin
|
r248 | using System; | ||
using System.Diagnostics; | ||||
using System.Reflection; | ||||
using Implab.Parallels; | ||||
namespace Implab { | ||||
public class Promise<T> : AbstractEvent<IResolvable<T>>, IPromise<T> { | ||||
class ResolvableSignal : IResolvable<T> { | ||||
public Signal Signal { get; private set; } | ||||
public ResolvableSignal() { | ||||
Signal = new Signal(); | ||||
} | ||||
public void Reject(Exception error) { | ||||
Signal.Set(); | ||||
} | ||||
public void Resolve(T result) { | ||||
Signal.Set(); | ||||
} | ||||
} | ||||
class ResolvableWrapper : IResolvable<T> { | ||||
readonly IResolvable m_resolvable; | ||||
public ResolvableWrapper(IResolvable resolvable) { | ||||
m_resolvable = resolvable; | ||||
} | ||||
public void Reject(Exception reason) { | ||||
m_resolvable.Reject(reason); | ||||
} | ||||
public void Resolve(T value) { | ||||
m_resolvable.Resolve(); | ||||
} | ||||
} | ||||
PromiseState m_state; | ||||
T m_result; | ||||
Exception m_error; | ||||
public bool IsRejected { | ||||
get { | ||||
return m_state == PromiseState.Rejected; | ||||
} | ||||
} | ||||
public bool IsFulfilled { | ||||
get { | ||||
return m_state == PromiseState.Fulfilled; | ||||
} | ||||
} | ||||
public Exception RejectReason { | ||||
get { | ||||
return m_error; | ||||
} | ||||
} | ||||
internal void ResolvePromise(T result) { | ||||
if (BeginTransit()) { | ||||
m_result = result; | ||||
m_state = PromiseState.Fulfilled; | ||||
CompleteTransit(); | ||||
} | ||||
} | ||||
internal void RejectPromise(Exception reason) { | ||||
if (BeginTransit()) { | ||||
m_error = reason; | ||||
m_state = PromiseState.Rejected; | ||||
CompleteTransit(); | ||||
} | ||||
} | ||||
#region implemented abstract members of AbstractPromise | ||||
protected override void SignalHandler(IResolvable<T> handler) { | ||||
switch (m_state) { | ||||
case PromiseState.Fulfilled: | ||||
handler.Resolve(m_result); | ||||
break; | ||||
case PromiseState.Rejected: | ||||
handler.Reject(RejectReason); | ||||
break; | ||||
default: | ||||
throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); | ||||
} | ||||
} | ||||
protected void WaitResult(int timeout) { | ||||
if (!(IsResolved || GetFulfillSignal().Wait(timeout))) | ||||
throw new TimeoutException(); | ||||
} | ||||
protected Signal GetFulfillSignal() { | ||||
var next = new ResolvableSignal(); | ||||
Then(next); | ||||
return next.Signal; | ||||
} | ||||
#endregion | ||||
public Type ResultType { | ||||
get { | ||||
return typeof(void); | ||||
} | ||||
} | ||||
protected void Rethrow() { | ||||
if (m_error is OperationCanceledException) | ||||
throw new OperationCanceledException("Operation cancelled", m_error); | ||||
else | ||||
throw new TargetInvocationException(m_error); | ||||
} | ||||
public void Then(IResolvable<T> next) { | ||||
AddHandler(next); | ||||
} | ||||
public void Then(IResolvable next) { | ||||
AddHandler(new ResolvableWrapper(next)); | ||||
} | ||||
public IPromise<T2> Cast<T2>() { | ||||
return (IPromise<T2>)this; | ||||
} | ||||
void IPromise.Join() { | ||||
Join(); | ||||
} | ||||
void IPromise.Join(int timeout) { | ||||
Join(timeout); | ||||
} | ||||
public T Join() { | ||||
WaitResult(-1); | ||||
if (IsRejected) | ||||
Rethrow(); | ||||
return m_result; | ||||
} | ||||
public T Join(int timeout) { | ||||
WaitResult(timeout); | ||||
if (IsRejected) | ||||
Rethrow(); | ||||
return m_result; | ||||
} | ||||
} | ||||
} | ||||