Mercurial > pub > ImplabNet
changeset 244:eee3e49dd1ff v3
working on promises
author | cin |
---|---|
date | Thu, 25 Jan 2018 19:09:16 +0300 |
parents | b1e0ffdf3451 |
children | b904e0a3ba72 |
files | Implab/AbstractEvent.cs Implab/AbstractPromise.cs Implab/ActionChainTask.cs Implab/ActionTask.cs Implab/Components/RunnableComponent.cs Implab/Deferred.cs Implab/FuncChainTask.cs Implab/FuncTask.cs Implab/IDeferred.cs Implab/IDispatcher.cs Implab/IPromise.cs Implab/IResolvable.cs Implab/Implab.old.csproj Implab/Promise.cs Implab/PromiseState.cs |
diffstat | 15 files changed, 255 insertions(+), 449 deletions(-) [+] |
line wrap: on
line diff
--- a/Implab/AbstractEvent.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/AbstractEvent.cs Thu Jan 25 19:09:16 2018 +0300 @@ -35,31 +35,31 @@ /// </para> /// </remarks> public abstract class AbstractEvent<THandler> where THandler : class { - const int PENDING_SATE = 0; + const int PendingState = 0; - const int TRANSITIONAL_STATE = 1; + const int TransitionalState = 1; - const int FULFILLED_STATE = 2; + const int ResolvedState = 2; volatile int m_state; THandler m_handler; SimpleAsyncQueue<THandler> m_extraHandlers; - public bool IsFulfilled { + public bool IsResolved { get { - return m_state > TRANSITIONAL_STATE; + return m_state > TransitionalState; } } #region state managment protected bool BeginTransit() { - return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE); + return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState); } protected void CompleteTransit() { #if DEBUG - if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, FULFILLED_STATE, TRANSITIONAL_STATE)) + if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState)) throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); #else m_state = state; @@ -68,11 +68,11 @@ } protected void WaitTransition() { - if (m_state == TRANSITIONAL_STATE) { + if (m_state == TransitionalState) { SpinWait spin; do { spin.SpinOnce(); - } while (m_state == TRANSITIONAL_STATE); + } while (m_state == TransitionalState); } } @@ -91,7 +91,7 @@ #region synchronization traits protected void WaitResult(int timeout) { - if (!(IsFulfilled || GetFulfillSignal().Wait(timeout))) + if (!(IsResolved || GetFulfillSignal().Wait(timeout))) throw new TimeoutException(); } @@ -102,13 +102,13 @@ protected void AddHandler(THandler handler) { - if (IsFulfilled) { + if (IsResolved) { // the promise is in the resolved state, just invoke the handler SignalHandler(handler); } else { EnqueueHandler(handler); - if (IsFulfilled && TryDequeueHandler(out handler)) + if (IsResolved && TryDequeueHandler(out handler)) // if the promise have been resolved while we was adding the handler to the queue // we can't guarantee that someone is still processing it // therefore we need to fetch a handler from the queue and execute it
--- a/Implab/AbstractPromise.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/AbstractPromise.cs Thu Jan 25 19:09:16 2018 +0300 @@ -4,36 +4,21 @@ using Implab.Parallels; namespace Implab { - public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise { - public class HandlerDescriptor { - readonly Action m_resolve; - readonly Action<Exception> m_reject; + public class AbstractPromise : AbstractEvent<IResolvable>, IPromise { - readonly IDeferred m_deferred; - public HandlerDescriptor(Action success, Action<Exception> error) { - m_resolve = success; - m_reject = error; + class ResolvableSignal : IResolvable { + public Signal Signal { get; private set; } + public ResolvableSignal() { + Signal = new Signal(); } - public void SignalSuccess() { - try { - if (m_resolve != null) - m_resolve(); - m_deferred.Resolve(); - } catch (Exception ex) { - m_deferred.Reject(ex); - } + + public void Reject(Exception error) { + Signal.Set(); } - public void SignalError(Exception err) { - if (m_reject != null) { - try { - m_reject(err); - m_deferred.Resolve(); - } catch (Exception ex) { - m_deferred.Reject(ex); - } - } + public void Resolve() { + Signal.Set(); } } @@ -47,9 +32,9 @@ } } - public bool IsResolved { + public bool IsFulfilled { get { - return m_state == PromiseState.Resolved; + return m_state == PromiseState.Fulfilled; } } @@ -60,15 +45,29 @@ } + internal void Resolve() { + if (BeginTransit()) + CompleteResolve(); + } + + internal void Reject(Exception reason) { + if (BeginTransit()) { + m_error = reason; + m_state = PromiseState.Rejected; + CompleteTransit(); + } + } + + #region implemented abstract members of AbstractPromise - protected override void SignalHandler(HandlerDescriptor handler) { + protected override void SignalHandler(IResolvable handler) { switch (m_state) { - case PromiseState.Resolved: - handler.SignalSuccess(); + case PromiseState.Fulfilled: + handler.Resolve(); break; case PromiseState.Rejected: - handler.SignalError(RejectReason); + handler.Reject(RejectReason); break; default: throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state)); @@ -76,15 +75,15 @@ } protected override Signal GetFulfillSignal() { - var signal = new Signal(); - On(signal.Set, e => signal.Set()); - return signal; + var next = new ResolvableSignal(); + Then(next); + return next.Signal; } #endregion protected void CompleteResolve() { - m_state = PromiseState.Resolved; + m_state = PromiseState.Fulfilled; CompleteTransit(); } @@ -94,27 +93,6 @@ } } - /// <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); @@ -124,8 +102,8 @@ throw new TargetInvocationException(m_error); } - public void On(Action success, Action<Exception> error) { - AddHandler(new HandlerDescriptor(success, error)); + public void Then(IResolvable next) { + AddHandler(next); } public IPromise<T> Cast<T>() {
--- a/Implab/ActionChainTask.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/ActionChainTask.cs Thu Jan 25 19:09:16 2018 +0300 @@ -1,7 +1,7 @@ using System; namespace Implab { - public class ActionChainTask : ActionChainTaskBase, IDeferred { + public class ActionChainTask : ActionChainTaskBase, IResolvable { readonly Func<IPromise> m_task; /// <summary>
--- a/Implab/ActionTask.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/ActionTask.cs Thu Jan 25 19:09:16 2018 +0300 @@ -1,7 +1,7 @@ using System; namespace Implab { - public class ActionTask : ActionTaskBase, IDeferred { + public class ActionTask : ActionTaskBase, IResolvable { readonly Action m_task; public ActionTask(Action task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) { m_task = task;
--- a/Implab/Components/RunnableComponent.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/Components/RunnableComponent.cs Thu Jan 25 19:09:16 2018 +0300 @@ -1,6 +1,6 @@ using System; -using System.Diagnostics.CodeAnalysis; - +using System.Diagnostics.CodeAnalysis; + namespace Implab.Components { public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable { enum Commands { @@ -18,28 +18,28 @@ public static readonly ExecutionState[,] ReusableTransitions; public static readonly ExecutionState[,] NonreusableTransitions; - class StateBuilder { - readonly ExecutionState[,] m_states; - - public ExecutionState[,] States { - get { return m_states; } - } - public StateBuilder(ExecutionState[,] states) { - m_states = states; - } - - public StateBuilder() { - m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1]; - } - - public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { - m_states[(int)s1, (int)cmd] = s2; - return this; - } - - public StateBuilder Clone() { - return new StateBuilder((ExecutionState[,])m_states.Clone()); - } + class StateBuilder { + readonly ExecutionState[,] m_states; + + public ExecutionState[,] States { + get { return m_states; } + } + public StateBuilder(ExecutionState[,] states) { + m_states = states; + } + + public StateBuilder() { + m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1]; + } + + public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) { + m_states[(int)s1, (int)cmd] = s2; + return this; + } + + public StateBuilder Clone() { + return new StateBuilder((ExecutionState[,])m_states.Clone()); + } } static StateMachine() { @@ -65,8 +65,8 @@ .Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose) .Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose) - .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset) - + .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset) + .Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail) .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose) @@ -74,11 +74,11 @@ var reusable = common .Clone() - .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok); - - var nonreusable = common - .Clone() - .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok); + .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok); + + var nonreusable = common + .Clone() + .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok); NonreusableTransitions = nonreusable.States; ReusableTransitions = reusable.States; @@ -109,45 +109,45 @@ IPromise m_pending; Exception m_lastError; - readonly StateMachine m_stateMachine; - readonly bool m_reusable; - public event EventHandler<StateChangeEventArgs> StateChanged; - - /// <summary> - /// Initializes component state. - /// </summary> - /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param> - /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param> - protected RunnableComponent(bool initialized, bool reusable) { + readonly StateMachine m_stateMachine; + readonly bool m_reusable; + public event EventHandler<StateChangeEventArgs> StateChanged; + + /// <summary> + /// Initializes component state. + /// </summary> + /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param> + /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param> + protected RunnableComponent(bool initialized, bool reusable) { m_stateMachine = new StateMachine( reusable ? StateMachine.ReusableTransitions : StateMachine.NonreusableTransitions, initialized ? ExecutionState.Ready : ExecutionState.Created ); m_reusable = reusable; - } - - /// <summary> - /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop. - /// </summary> - /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param> + } + + /// <summary> + /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop. + /// </summary> + /// <param name="initialized">If set, the component initial state is <see cref="ExecutionState.Ready"/> and the component is ready to start, otherwise initialization is required.</param> protected RunnableComponent(bool initialized) : this(initialized, false) { } void ThrowInvalidCommand(Commands cmd) { if (m_stateMachine.State == ExecutionState.Disposed) - throw new ObjectDisposedException(ToString()); - + throw new ObjectDisposedException(ToString()); + throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State)); } bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) { ExecutionState prev, current; - lock (m_stateMachine) { - if (m_stateMachine.State != state) - return false; - - prev = m_stateMachine.State; - if (!m_stateMachine.Move(cmd)) + lock (m_stateMachine) { + if (m_stateMachine.State != state) + return false; + + prev = m_stateMachine.State; + if (!m_stateMachine.Move(cmd)) ThrowInvalidCommand(cmd); current = m_stateMachine.State; @@ -161,46 +161,46 @@ bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) { ExecutionState prev, current; - lock (m_stateMachine) { - if (m_pending != expected) - return false; - prev = m_stateMachine.State; - if (!m_stateMachine.Move(cmd)) + lock (m_stateMachine) { + if (m_pending != expected) + return false; + prev = m_stateMachine.State; + if (!m_stateMachine.Move(cmd)) ThrowInvalidCommand(cmd); current = m_stateMachine.State; m_pending = pending; m_lastError = error; - } + } if (prev != current) - OnStateChanged(prev, current, error); + OnStateChanged(prev, current, error); return true; } IPromise Move(Commands cmd, IPromise pending, Exception error) { ExecutionState prev, current; IPromise ret; - lock (m_stateMachine) { - prev = m_stateMachine.State; - if (!m_stateMachine.Move(cmd)) + lock (m_stateMachine) { + prev = m_stateMachine.State; + if (!m_stateMachine.Move(cmd)) ThrowInvalidCommand(cmd); current = m_stateMachine.State; ret = m_pending; m_pending = pending; - m_lastError = error; - + m_lastError = error; + } if (prev != current) OnStateChanged(prev, current, error); return ret; } - /// <summary> - /// Handles the state of the component change event, raises the <see cref="StateChanged"/> event, handles - /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method). - /// </summary> - /// <param name="previous">The previous state</param> - /// <param name="current">The current state</param> + /// <summary> + /// Handles the state of the component change event, raises the <see cref="StateChanged"/> event, handles + /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method). + /// </summary> + /// <param name="previous">The previous state</param> + /// <param name="current">The current state</param> /// <param name="error">The last error if any.</param> /// <remarks> /// <para> @@ -212,31 +212,31 @@ /// the wrong behavior of the component. /// </para> /// </remarks> - protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) { - StateChanged.DispatchEvent( - this, - new StateChangeEventArgs { - State = current, - LastError = error - } - ); - if (current == ExecutionState.Disposed) { - GC.SuppressFinalize(this); - Dispose(true); - } + protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) { + StateChanged.DispatchEvent( + this, + new StateChangeEventArgs { + State = current, + LastError = error + } + ); + if (current == ExecutionState.Disposed) { + GC.SuppressFinalize(this); + Dispose(true); + } } /// <summary> /// Moves the component from running to failed state. /// </summary> /// <param name="error">The exception which is describing the error.</param> - protected bool Fail(Exception error) { - return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running); + protected bool Fail(Exception error) { + return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running); } - /// <summary> - /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>. - /// </summary> + /// <summary> + /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>. + /// </summary> /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't /// in <see cref="ExecutionState.Failed"/> state.</returns> /// <remarks> @@ -246,10 +246,10 @@ /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/> /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller. /// </remarks> - protected bool ResetState() { - if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed)) - return false; - + protected bool ResetState() { + if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed)) + return false; + try { OnResetState(); Move(Commands.Ok, null, null); @@ -257,38 +257,38 @@ } catch (Exception err) { Move(Commands.Fail, null, err); throw; - } + } } - /// <summary> - /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state. + /// <summary> + /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state. /// </summary> /// <remarks> /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state. /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state. /// </remarks> - protected virtual void OnResetState() { - throw new NotImplementedException(); + protected virtual void OnResetState() { + throw new NotImplementedException(); } - IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) { + IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IResolvable> chain) { IPromise promise = null; IPromise prev; var task = new ActionChainTask(action, null, null, true); - Action<Exception> errorOrCancel = e => { - if (e == null) - e = new OperationCanceledException(); - MoveIfPending(Commands.Fail, null, e, promise); - throw new PromiseTransientException(e); + Action<Exception> errorOrCancel = e => { + if (e == null) + e = new OperationCanceledException(); + MoveIfPending(Commands.Fail, null, e, promise); + throw new PromiseTransientException(e); }; promise = task.Then( () => MoveIfPending(Commands.Ok, null, null, promise), errorOrCancel, - errorOrCancel + errorOrCancel ); prev = Move(cmd, promise, null); @@ -305,8 +305,8 @@ #region IInitializable implementation public void Initialize() { - Move(Commands.Init, null, null); - + Move(Commands.Init, null, null); + try { OnInitialize(); Move(Commands.Ok, null, null); @@ -344,7 +344,7 @@ /// </summary> /// <param name="current">Current.</param> /// <param name="stop">Stop.</param> - protected virtual void StopPending(IPromise current, IDeferred stop) { + protected virtual void StopPending(IPromise current, IResolvable stop) { if (current == null) { stop.Resolve(); } else { @@ -398,11 +398,11 @@ #endregion - /// <summary> - /// Releases all resources used by the component, called automatically, override this method to implement your cleanup. - /// </summary> - /// <param name="disposing">true if this method is called during normal dispose process.</param> - /// <param name="pending">The operation which is currenty pending</param> + /// <summary> + /// Releases all resources used by the component, called automatically, override this method to implement your cleanup. + /// </summary> + /// <param name="disposing">true if this method is called during normal dispose process.</param> + /// <param name="pending">The operation which is currenty pending</param> protected virtual void Dispose(bool disposing) { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Deferred.cs Thu Jan 25 19:09:16 2018 +0300 @@ -0,0 +1,52 @@ +using System; +using System.Diagnostics; + +namespace Implab { + /// <summary> + /// This class is responsible for the promise resolution, dispatching and chaining + /// </summary> + public class Deferred : IResolvable { + + readonly AbstractPromise m_promise; + readonly IDispatcher m_dispatcher; + + internal Deferred(AbstractPromise promise, IDispatcher dispatcher) { + Debug.Assert(promise != null); + m_promise = promise; + m_dispatcher = dispatcher; + } + + public IPromise Promise { + get { return m_promise; } + } + + public void Reject(Exception error) { + m_promise.Reject(error); + } + + public void Resolve() { + m_promise.Resolve(); + } + + public void Resolve(IPromise thenable) { + if (thenable == null) + Reject(new Exception("The promise or task are expected")); + if (thenable == m_promise) + Reject(new Exception("The promise cannot be resolved with oneself")); + + else if (m_dispatcher != null) + // dispatch (see ecma-262/6.0: 25.4.1.3.2 Promise Resolve Functions) + m_dispatcher.Enqueue(() => thenable.Then(this)); + else + thenable.Then(this); + } + + void Chain(IPromise thenable) { + try { + thenable.Then(this); + } catch (Exception err) { + Reject(err); + } + } + } +} \ No newline at end of file
--- a/Implab/FuncChainTask.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/FuncChainTask.cs Thu Jan 25 19:09:16 2018 +0300 @@ -1,7 +1,7 @@ using System; namespace Implab { - public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IDeferred { + public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IResolvable { readonly Func<IPromise<TResult>> m_task; public FuncChainTask(Func<IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable)
--- a/Implab/FuncTask.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/FuncTask.cs Thu Jan 25 19:09:16 2018 +0300 @@ -2,7 +2,7 @@ using System.Threading; namespace Implab { - public class FuncTask<T> : FuncTaskBase<T>, IDeferred { + public class FuncTask<T> : FuncTaskBase<T>, IResolvable { readonly Func<T> m_task; public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel, bool autoCancellable) : base(error, cancel, autoCancellable) {
--- a/Implab/IDeferred.cs Wed Jan 24 19:24:10 2018 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -using System; - -namespace Implab { - /// <summary> - /// Deferred result, usually used by asynchronous services as the service part of the promise. - /// </summary> - public interface IDeferred { - - void Resolve(); - - /// <summary> - /// Reject the promise with the specified error. - /// </summary> - /// <param name="error">The reason why the promise is rejected.</param> - /// <remarks> - /// Some exceptions are treated in a special case: - /// <see cref="OperationCanceledException"/> is interpreted as call to <see cref="Cancel()"/> method, - /// and <see cref="PromiseTransientException"/> is always unwrapped and its - /// <see cref="PromiseTransientException.InnerException"> is used as the reason to reject promise. - /// </remarks> - void Reject(Exception error); - - /// <summary> - /// Marks current instance as cencelled with the specified reason. - /// </summary> - /// <param name="reason">The reason for the operation cancellation, - /// if not specified the new <see cref="OperationCanceledException"> will be created</param> - void SetCancelled(Exception reason); - } -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/IDispatcher.cs Thu Jan 25 19:09:16 2018 +0300 @@ -0,0 +1,7 @@ +using System; + +namespace Implab { + public interface IDispatcher { + void Enqueue(Action job); + } +} \ No newline at end of file
--- a/Implab/IPromise.cs Wed Jan 24 19:24:10 2018 +0300 +++ b/Implab/IPromise.cs Thu Jan 25 19:09:16 2018 +0300 @@ -14,11 +14,11 @@ /// <summary> /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено. /// </summary> - bool IsFulfilled { get; } + bool IsResolved { get; } bool IsRejected { get; } - bool IsResolved { get; } + bool IsFulfilled { get; } /// <summary> /// Исключение возникшее в результате выполнения обещания, либо причина отмены. @@ -31,23 +31,11 @@ /// <param name="success">The handler called on the successful promise completion.</param> /// <param name="error">The handler is called if an error while completing the promise occurred.</param> /// <returns>The current promise.</returns> - void On(Action success, Action<Exception> error); + void Then(IResolvable next); /// <summary> /// Преобразует результат обещания к заданному типу и возвращает новое обещание. /// </summary> IPromise<T> Cast<T>(); - - /// <summary> - /// Синхронизирует текущий поток с обещанием. - /// </summary> - void Join(); - /// <summary> - /// Синхронизирует текущий поток с обещанием. - /// </summary> - /// <param name="timeout">Время ожидания, по его истечению возникнет исключение.</param> - /// <exception cref="TimeoutException">Превышено время ожидания.</exception> - void Join(int timeout); - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/IResolvable.cs Thu Jan 25 19:09:16 2018 +0300 @@ -0,0 +1,26 @@ +using System; + +namespace Implab { + /// <summary> + /// Deferred result, usually used by asynchronous services as the service part of the promise. + /// </summary> + public interface IResolvable { + + void Resolve(); + + void Resolve(IPromise thenable); + + /// <summary> + /// Reject the promise with the specified error. + /// </summary> + /// <param name="error">The reason why the promise is rejected.</param> + /// <remarks> + /// Some exceptions are treated in a special case: + /// <see cref="OperationCanceledException"/> is interpreted as call to <see cref="Cancel()"/> method, + /// and <see cref="PromiseTransientException"/> is always unwrapped and its + /// <see cref="PromiseTransientException.InnerException"> is used as the reason to reject promise. + /// </remarks> + void Reject(Exception error); + } +} +
--- a/Implab/Implab.old.csproj Wed Jan 24 19:24:10 2018 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid> - <OutputType>Library</OutputType> - <RootNamespace>Implab</RootNamespace> - <AssemblyName>Implab</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> - <TargetFrameworkProfile /> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>true</Optimize> - <OutputPath>bin\Debug</OutputPath> - <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> - <RunCodeAnalysis>true</RunCodeAnalysis> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>full</DebugType> - <Optimize>true</Optimize> - <OutputPath>bin\Release</OutputPath> - <DefineConstants>NET_4_5</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - <ConsolePause>false</ConsolePause> - </PropertyGroup> - <PropertyGroup> - <SignAssembly>false</SignAssembly> - </PropertyGroup> - <PropertyGroup> - <AssemblyOriginatorKeyFile>implab.snk</AssemblyOriginatorKeyFile> - </PropertyGroup> - <ItemGroup> - <Reference Include="System" /> - <Reference Include="System.Xml" /> - <Reference Include="mscorlib" /> - <Reference Include="System.Xml.Linq" /> - </ItemGroup> - <ItemGroup> - <Compile Include="Components\StateChangeEventArgs.cs" /> - <Compile Include="CustomEqualityComparer.cs" /> - <Compile Include="Diagnostics\ConsoleTraceListener.cs" /> - <Compile Include="Diagnostics\LogChannel.cs" /> - <Compile Include="Diagnostics\LogicalOperation.cs" /> - <Compile Include="Diagnostics\TextFileListener.cs" /> - <Compile Include="Diagnostics\Trace.cs" /> - <Compile Include="Diagnostics\TraceLog.cs" /> - <Compile Include="Diagnostics\TraceEvent.cs" /> - <Compile Include="Diagnostics\TraceEventType.cs" /> - <Compile Include="Diagnostics\TraceSourceAttribute.cs" /> - <Compile Include="Formats\CharMap.cs" /> - <Compile Include="Formats\FastInpurScanner.cs" /> - <Compile Include="Formats\InputScanner.cs" /> - <Compile Include="Formats\Json\JsonStringScanner.cs" /> - <Compile Include="Formats\Json\JsonTextScanner.cs" /> - <Compile Include="ICancellable.cs" /> - <Compile Include="IProgressHandler.cs" /> - <Compile Include="IProgressNotifier.cs" /> - <Compile Include="IPromiseT.cs" /> - <Compile Include="IPromise.cs" /> - <Compile Include="IServiceLocator.cs" /> - <Compile Include="ITaskController.cs" /> - <Compile Include="Parallels\DispatchPool.cs" /> - <Compile Include="Parallels\ArrayTraits.cs" /> - <Compile Include="Parallels\SimpleAsyncQueue.cs" /> - <Compile Include="Parallels\WorkerPool.cs" /> - <Compile Include="ProgressInitEventArgs.cs" /> - <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Parallels\AsyncPool.cs" /> - <Compile Include="Safe.cs" /> - <Compile Include="SyncContextPromise.cs" /> - <Compile Include="ValueEventArgs.cs" /> - <Compile Include="PromiseExtensions.cs" /> - <Compile Include="SyncContextPromiseT.cs" /> - <Compile Include="Diagnostics\OperationContext.cs" /> - <Compile Include="Diagnostics\TraceContext.cs" /> - <Compile Include="Diagnostics\LogEventArgs.cs" /> - <Compile Include="Diagnostics\LogEventArgsT.cs" /> - <Compile Include="Diagnostics\Extensions.cs" /> - <Compile Include="PromiseEventType.cs" /> - <Compile Include="Parallels\AsyncQueue.cs" /> - <Compile Include="PromiseT.cs" /> - <Compile Include="IDeferred.cs" /> - <Compile Include="IDeferredT.cs" /> - <Compile Include="Promise.cs" /> - <Compile Include="PromiseTransientException.cs" /> - <Compile Include="Parallels\Signal.cs" /> - <Compile Include="Parallels\SharedLock.cs" /> - <Compile Include="Diagnostics\ILogWriter.cs" /> - <Compile Include="Diagnostics\ListenerBase.cs" /> - <Compile Include="Parallels\BlockingQueue.cs" /> - <Compile Include="AbstractEvent.cs" /> - <Compile Include="AbstractPromise.cs" /> - <Compile Include="AbstractPromiseT.cs" /> - <Compile Include="FuncTask.cs" /> - <Compile Include="FuncTaskBase.cs" /> - <Compile Include="FuncTaskT.cs" /> - <Compile Include="ActionChainTaskBase.cs" /> - <Compile Include="ActionChainTask.cs" /> - <Compile Include="ActionChainTaskT.cs" /> - <Compile Include="FuncChainTaskBase.cs" /> - <Compile Include="FuncChainTask.cs" /> - <Compile Include="FuncChainTaskT.cs" /> - <Compile Include="ActionTaskBase.cs" /> - <Compile Include="ActionTask.cs" /> - <Compile Include="ActionTaskT.cs" /> - <Compile Include="ICancellationToken.cs" /> - <Compile Include="SuccessPromise.cs" /> - <Compile Include="SuccessPromiseT.cs" /> - <Compile Include="PromiseAwaiterT.cs" /> - <Compile Include="PromiseAwaiter.cs" /> - <Compile Include="Components\ComponentContainer.cs" /> - <Compile Include="Components\Disposable.cs" /> - <Compile Include="Components\DisposablePool.cs" /> - <Compile Include="Components\ObjectPool.cs" /> - <Compile Include="Components\ServiceLocator.cs" /> - <Compile Include="Components\IInitializable.cs" /> - <Compile Include="TaskController.cs" /> - <Compile Include="Components\App.cs" /> - <Compile Include="Components\IRunnable.cs" /> - <Compile Include="Components\ExecutionState.cs" /> - <Compile Include="Components\RunnableComponent.cs" /> - <Compile Include="Components\IFactory.cs" /> - <Compile Include="Automaton\IAlphabet.cs" /> - <Compile Include="Automaton\ParserException.cs" /> - <Compile Include="Automaton\IndexedAlphabetBase.cs" /> - <Compile Include="Automaton\IAlphabetBuilder.cs" /> - <Compile Include="Automaton\RegularExpressions\AltToken.cs" /> - <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" /> - <Compile Include="Automaton\RegularExpressions\CatToken.cs" /> - <Compile Include="Automaton\RegularExpressions\StarToken.cs" /> - <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" /> - <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" /> - <Compile Include="Automaton\RegularExpressions\Token.cs" /> - <Compile Include="Automaton\RegularExpressions\IVisitor.cs" /> - <Compile Include="Automaton\AutomatonTransition.cs" /> - <Compile Include="Formats\Json\JsonElementContext.cs" /> - <Compile Include="Formats\Json\JsonElementType.cs" /> - <Compile Include="Formats\Json\JsonGrammar.cs" /> - <Compile Include="Formats\Json\JsonReader.cs" /> - <Compile Include="Formats\Json\JsonScanner.cs" /> - <Compile Include="Formats\Json\JsonTokenType.cs" /> - <Compile Include="Formats\Json\JsonWriter.cs" /> - <Compile Include="Formats\Json\StringTranslator.cs" /> - <Compile Include="Automaton\MapAlphabet.cs" /> - <Compile Include="Formats\CharAlphabet.cs" /> - <Compile Include="Formats\ByteAlphabet.cs" /> - <Compile Include="Automaton\IDFATable.cs" /> - <Compile Include="Automaton\IDFATableBuilder.cs" /> - <Compile Include="Automaton\DFATable.cs" /> - <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" /> - <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" /> - <Compile Include="Formats\Grammar.cs" /> - <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" /> - <Compile Include="Automaton\RegularExpressions\EndToken.cs" /> - <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" /> - <Compile Include="Automaton\AutomatonConst.cs" /> - <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" /> - <Compile Include="Components\LazyAndWeak.cs" /> - <Compile Include="AbstractTask.cs" /> - <Compile Include="AbstractTaskT.cs" /> - <Compile Include="FailedPromise.cs" /> - <Compile Include="FailedPromiseT.cs" /> - <Compile Include="Components\PollingComponent.cs" /> - <Compile Include="Xml\JsonXmlReader.cs" /> - <Compile Include="Xml\JsonXmlReaderOptions.cs" /> - <Compile Include="Xml\JsonXmlReaderPosition.cs" /> - <Compile Include="Xml\SerializationHelpers.cs" /> - <Compile Include="Xml\SerializersPool.cs" /> - <Compile Include="Xml\XmlSimpleAttribute.cs" /> - <Compile Include="Xml\XmlNameContext.cs" /> - </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <ItemGroup> - <None Include="Implab.nuspec"> - <SubType>Designer</SubType> - </None> - <None Include="implab.snk" /> - </ItemGroup> - <ItemGroup> - <Content Include="license.txt" /> - </ItemGroup> -</Project> \ No newline at end of file
--- a/Implab/Promise.cs Wed Jan 24 19:24:10 2018 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -using System; -using Implab.Parallels; - -namespace Implab { - public class Promise : AbstractPromise { - public static readonly IPromise Success; - - static Promise() { - Success = new SuccessPromise(); - } - - internal void ResolvePromise() { - SetResult(); - } - - internal void RejectPromise(Exception error) { - SetError(error); - } - - public static IPromise Reject(Exception exception) { - return new FailedPromise(exception); - } - } -} -