AbstractPromise.cs
146 lines
| 4.6 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / AbstractPromise.cs
cin
|
r119 | using System; | ||
cin
|
r243 | using System.Diagnostics; | ||
using System.Reflection; | ||||
cin
|
r119 | using Implab.Parallels; | ||
namespace Implab { | ||||
cin
|
r144 | public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { | ||
cin
|
r242 | public class HandlerDescriptor { | ||
cin
|
r243 | readonly Action m_resolve; | ||
readonly Action<Exception> m_reject; | ||||
readonly IDeferred m_deferred; | ||||
cin
|
r242 | public HandlerDescriptor(Action success, Action<Exception> error) { | ||
cin
|
r243 | m_resolve = success; | ||
m_reject = error; | ||||
cin
|
r144 | } | ||
cin
|
r119 | |||
cin
|
r144 | public void SignalSuccess() { | ||
cin
|
r243 | try { | ||
if (m_resolve != null) | ||||
m_resolve(); | ||||
m_deferred.Resolve(); | ||||
} catch (Exception ex) { | ||||
m_deferred.Reject(ex); | ||||
cin
|
r144 | } | ||
} | ||||
cin
|
r119 | |||
cin
|
r144 | public void SignalError(Exception err) { | ||
cin
|
r243 | if (m_reject != null) { | ||
cin
|
r144 | try { | ||
cin
|
r243 | m_reject(err); | ||
m_deferred.Resolve(); | ||||
} catch (Exception ex) { | ||||
m_deferred.Reject(ex); | ||||
cin
|
r144 | } | ||
} | ||||
cin
|
r119 | } | ||
} | ||||
cin
|
r243 | PromiseState m_state; | ||
Exception m_error; | ||||
public bool IsRejected { | ||||
get { | ||||
return m_state == PromiseState.Rejected; | ||||
} | ||||
} | ||||
public bool IsResolved { | ||||
get { | ||||
return m_state == PromiseState.Resolved; | ||||
} | ||||
} | ||||
public Exception RejectReason { | ||||
get { | ||||
return m_error; | ||||
} | ||||
} | ||||
cin
|
r119 | |||
cin
|
r144 | #region implemented abstract members of AbstractPromise | ||
cin
|
r119 | |||
cin
|
r243 | protected override void SignalHandler(HandlerDescriptor handler) { | ||
switch (m_state) { | ||||
case PromiseState.Resolved: | ||||
cin
|
r156 | handler.SignalSuccess(); | ||
break; | ||||
cin
|
r243 | case PromiseState.Rejected: | ||
cin
|
r242 | handler.SignalError(RejectReason); | ||
cin
|
r156 | break; | ||
default: | ||||
cin
|
r243 | throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); | ||
cin
|
r156 | } | ||
cin
|
r119 | } | ||
cin
|
r242 | protected override Signal GetFulfillSignal() { | ||
cin
|
r144 | var signal = new Signal(); | ||
cin
|
r242 | On(signal.Set, e => signal.Set()); | ||
cin
|
r145 | return signal; | ||
cin
|
r119 | } | ||
#endregion | ||||
cin
|
r243 | protected void CompleteResolve() { | ||
m_state = PromiseState.Resolved; | ||||
CompleteTransit(); | ||||
} | ||||
cin
|
r242 | public Type ResultType { | ||
cin
|
r144 | get { | ||
return typeof(void); | ||||
cin
|
r119 | } | ||
} | ||||
cin
|
r243 | /// <summary> | ||
/// Выполняет обещание, сообщая об ошибке | ||||
/// </summary> | ||||
/// <remarks> | ||||
/// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков | ||||
/// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные | ||||
/// будут проигнорированы. | ||||
/// </remarks> | ||||
/// <param name="error">Исключение возникшее при выполнении операции</param> | ||||
/// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> | ||||
protected void SetError(Exception error) { | ||||
if (BeginTransit()) { | ||||
m_error = error; | ||||
m_state = PromiseState.Rejected; | ||||
CompleteTransit(); | ||||
} else { | ||||
WaitTransition(); | ||||
if (m_state == PromiseState.Resolved) | ||||
throw new InvalidOperationException("The promise is already resolved"); | ||||
} | ||||
} | ||||
protected void Rethrow() { | ||||
Debug.Assert(m_error != null); | ||||
if (m_error is OperationCanceledException) | ||||
throw new OperationCanceledException("Operation cancelled", m_error); | ||||
else | ||||
throw new TargetInvocationException(m_error); | ||||
} | ||||
cin
|
r242 | public void On(Action success, Action<Exception> error) { | ||
AddHandler(new HandlerDescriptor(success, error)); | ||||
cin
|
r144 | } | ||
cin
|
r119 | |||
cin
|
r144 | public IPromise<T> Cast<T>() { | ||
throw new InvalidCastException(); | ||||
cin
|
r119 | } | ||
public void Join() { | ||||
WaitResult(-1); | ||||
cin
|
r243 | if (IsRejected) | ||
Rethrow(); | ||||
cin
|
r119 | } | ||
cin
|
r144 | public void Join(int timeout) { | ||
WaitResult(timeout); | ||||
cin
|
r119 | } | ||
} | ||||
} | ||||