##// END OF EJS Templates
working on promises
cin -
r244:eee3e49dd1ff v3
parent child
Show More
@@ -0,0 +1,52
1 using System;
2 using System.Diagnostics;
3
4 namespace Implab {
5 /// <summary>
6 /// This class is responsible for the promise resolution, dispatching and chaining
7 /// </summary>
8 public class Deferred : IResolvable {
9
10 readonly AbstractPromise m_promise;
11 readonly IDispatcher m_dispatcher;
12
13 internal Deferred(AbstractPromise promise, IDispatcher dispatcher) {
14 Debug.Assert(promise != null);
15 m_promise = promise;
16 m_dispatcher = dispatcher;
17 }
18
19 public IPromise Promise {
20 get { return m_promise; }
21 }
22
23 public void Reject(Exception error) {
24 m_promise.Reject(error);
25 }
26
27 public void Resolve() {
28 m_promise.Resolve();
29 }
30
31 public void Resolve(IPromise thenable) {
32 if (thenable == null)
33 Reject(new Exception("The promise or task are expected"));
34 if (thenable == m_promise)
35 Reject(new Exception("The promise cannot be resolved with oneself"));
36
37 else if (m_dispatcher != null)
38 // dispatch (see ecma-262/6.0: 25.4.1.3.2 Promise Resolve Functions)
39 m_dispatcher.Enqueue(() => thenable.Then(this));
40 else
41 thenable.Then(this);
42 }
43
44 void Chain(IPromise thenable) {
45 try {
46 thenable.Then(this);
47 } catch (Exception err) {
48 Reject(err);
49 }
50 }
51 }
52 } No newline at end of file
@@ -0,0 +1,7
1 using System;
2
3 namespace Implab {
4 public interface IDispatcher {
5 void Enqueue(Action job);
6 }
7 } No newline at end of file
@@ -0,0 +1,26
1 using System;
2
3 namespace Implab {
4 /// <summary>
5 /// Deferred result, usually used by asynchronous services as the service part of the promise.
6 /// </summary>
7 public interface IResolvable {
8
9 void Resolve();
10
11 void Resolve(IPromise thenable);
12
13 /// <summary>
14 /// Reject the promise with the specified error.
15 /// </summary>
16 /// <param name="error">The reason why the promise is rejected.</param>
17 /// <remarks>
18 /// Some exceptions are treated in a special case:
19 /// <see cref="OperationCanceledException"/> is interpreted as call to <see cref="Cancel()"/> method,
20 /// and <see cref="PromiseTransientException"/> is always unwrapped and its
21 /// <see cref="PromiseTransientException.InnerException"> is used as the reason to reject promise.
22 /// </remarks>
23 void Reject(Exception error);
24 }
25 }
26
@@ -35,31 +35,31 namespace Implab {
35 /// </para>
35 /// </para>
36 /// </remarks>
36 /// </remarks>
37 public abstract class AbstractEvent<THandler> where THandler : class {
37 public abstract class AbstractEvent<THandler> where THandler : class {
38 const int PENDING_SATE = 0;
38 const int PendingState = 0;
39
39
40 const int TRANSITIONAL_STATE = 1;
40 const int TransitionalState = 1;
41
41
42 const int FULFILLED_STATE = 2;
42 const int ResolvedState = 2;
43
43
44 volatile int m_state;
44 volatile int m_state;
45
45
46 THandler m_handler;
46 THandler m_handler;
47 SimpleAsyncQueue<THandler> m_extraHandlers;
47 SimpleAsyncQueue<THandler> m_extraHandlers;
48
48
49 public bool IsFulfilled {
49 public bool IsResolved {
50 get {
50 get {
51 return m_state > TRANSITIONAL_STATE;
51 return m_state > TransitionalState;
52 }
52 }
53 }
53 }
54
54
55 #region state managment
55 #region state managment
56 protected bool BeginTransit() {
56 protected bool BeginTransit() {
57 return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE);
57 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
58 }
58 }
59
59
60 protected void CompleteTransit() {
60 protected void CompleteTransit() {
61 #if DEBUG
61 #if DEBUG
62 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, FULFILLED_STATE, TRANSITIONAL_STATE))
62 if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
63 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
63 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
64 #else
64 #else
65 m_state = state;
65 m_state = state;
@@ -68,11 +68,11 namespace Implab {
68 }
68 }
69
69
70 protected void WaitTransition() {
70 protected void WaitTransition() {
71 if (m_state == TRANSITIONAL_STATE) {
71 if (m_state == TransitionalState) {
72 SpinWait spin;
72 SpinWait spin;
73 do {
73 do {
74 spin.SpinOnce();
74 spin.SpinOnce();
75 } while (m_state == TRANSITIONAL_STATE);
75 } while (m_state == TransitionalState);
76 }
76 }
77 }
77 }
78
78
@@ -91,7 +91,7 namespace Implab {
91
91
92 #region synchronization traits
92 #region synchronization traits
93 protected void WaitResult(int timeout) {
93 protected void WaitResult(int timeout) {
94 if (!(IsFulfilled || GetFulfillSignal().Wait(timeout)))
94 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
95 throw new TimeoutException();
95 throw new TimeoutException();
96 }
96 }
97
97
@@ -102,13 +102,13 namespace Implab {
102
102
103 protected void AddHandler(THandler handler) {
103 protected void AddHandler(THandler handler) {
104
104
105 if (IsFulfilled) {
105 if (IsResolved) {
106 // the promise is in the resolved state, just invoke the handler
106 // the promise is in the resolved state, just invoke the handler
107 SignalHandler(handler);
107 SignalHandler(handler);
108 } else {
108 } else {
109 EnqueueHandler(handler);
109 EnqueueHandler(handler);
110
110
111 if (IsFulfilled && TryDequeueHandler(out handler))
111 if (IsResolved && TryDequeueHandler(out handler))
112 // if the promise have been resolved while we was adding the handler to the queue
112 // if the promise have been resolved while we was adding the handler to the queue
113 // we can't guarantee that someone is still processing it
113 // we can't guarantee that someone is still processing it
114 // therefore we need to fetch a handler from the queue and execute it
114 // therefore we need to fetch a handler from the queue and execute it
@@ -4,36 +4,21 using System.Reflection;
4 using Implab.Parallels;
4 using Implab.Parallels;
5
5
6 namespace Implab {
6 namespace Implab {
7 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise {
7 public class AbstractPromise : AbstractEvent<IResolvable>, IPromise {
8 public class HandlerDescriptor {
9 readonly Action m_resolve;
10 readonly Action<Exception> m_reject;
11
8
12 readonly IDeferred m_deferred;
9 class ResolvableSignal : IResolvable {
13 public HandlerDescriptor(Action success, Action<Exception> error) {
10 public Signal Signal { get; private set; }
14 m_resolve = success;
11 public ResolvableSignal() {
15 m_reject = error;
12 Signal = new Signal();
16 }
13 }
17
14
18 public void SignalSuccess() {
15
19 try {
16 public void Reject(Exception error) {
20 if (m_resolve != null)
17 Signal.Set();
21 m_resolve();
22 m_deferred.Resolve();
23 } catch (Exception ex) {
24 m_deferred.Reject(ex);
25 }
26 }
18 }
27
19
28 public void SignalError(Exception err) {
20 public void Resolve() {
29 if (m_reject != null) {
21 Signal.Set();
30 try {
31 m_reject(err);
32 m_deferred.Resolve();
33 } catch (Exception ex) {
34 m_deferred.Reject(ex);
35 }
36 }
37 }
22 }
38 }
23 }
39
24
@@ -47,9 +32,9 namespace Implab {
47 }
32 }
48 }
33 }
49
34
50 public bool IsResolved {
35 public bool IsFulfilled {
51 get {
36 get {
52 return m_state == PromiseState.Resolved;
37 return m_state == PromiseState.Fulfilled;
53 }
38 }
54 }
39 }
55
40
@@ -60,15 +45,29 namespace Implab {
60 }
45 }
61
46
62
47
48 internal void Resolve() {
49 if (BeginTransit())
50 CompleteResolve();
51 }
52
53 internal void Reject(Exception reason) {
54 if (BeginTransit()) {
55 m_error = reason;
56 m_state = PromiseState.Rejected;
57 CompleteTransit();
58 }
59 }
60
61
63 #region implemented abstract members of AbstractPromise
62 #region implemented abstract members of AbstractPromise
64
63
65 protected override void SignalHandler(HandlerDescriptor handler) {
64 protected override void SignalHandler(IResolvable handler) {
66 switch (m_state) {
65 switch (m_state) {
67 case PromiseState.Resolved:
66 case PromiseState.Fulfilled:
68 handler.SignalSuccess();
67 handler.Resolve();
69 break;
68 break;
70 case PromiseState.Rejected:
69 case PromiseState.Rejected:
71 handler.SignalError(RejectReason);
70 handler.Reject(RejectReason);
72 break;
71 break;
73 default:
72 default:
74 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
73 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
@@ -76,15 +75,15 namespace Implab {
76 }
75 }
77
76
78 protected override Signal GetFulfillSignal() {
77 protected override Signal GetFulfillSignal() {
79 var signal = new Signal();
78 var next = new ResolvableSignal();
80 On(signal.Set, e => signal.Set());
79 Then(next);
81 return signal;
80 return next.Signal;
82 }
81 }
83
82
84 #endregion
83 #endregion
85
84
86 protected void CompleteResolve() {
85 protected void CompleteResolve() {
87 m_state = PromiseState.Resolved;
86 m_state = PromiseState.Fulfilled;
88 CompleteTransit();
87 CompleteTransit();
89 }
88 }
90
89
@@ -94,27 +93,6 namespace Implab {
94 }
93 }
95 }
94 }
96
95
97 /// <summary>
98 /// Выполняет обещание, сообщая об ошибке
99 /// </summary>
100 /// <remarks>
101 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
102 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
103 /// будут проигнорированы.
104 /// </remarks>
105 /// <param name="error">Исключение возникшее при выполнении операции</param>
106 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
107 protected void SetError(Exception error) {
108 if (BeginTransit()) {
109 m_error = error;
110 m_state = PromiseState.Rejected;
111 CompleteTransit();
112 } else {
113 WaitTransition();
114 if (m_state == PromiseState.Resolved)
115 throw new InvalidOperationException("The promise is already resolved");
116 }
117 }
118
96
119 protected void Rethrow() {
97 protected void Rethrow() {
120 Debug.Assert(m_error != null);
98 Debug.Assert(m_error != null);
@@ -124,8 +102,8 namespace Implab {
124 throw new TargetInvocationException(m_error);
102 throw new TargetInvocationException(m_error);
125 }
103 }
126
104
127 public void On(Action success, Action<Exception> error) {
105 public void Then(IResolvable next) {
128 AddHandler(new HandlerDescriptor(success, error));
106 AddHandler(next);
129 }
107 }
130
108
131 public IPromise<T> Cast<T>() {
109 public IPromise<T> Cast<T>() {
@@ -1,7 +1,7
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class ActionChainTask : ActionChainTaskBase, IDeferred {
4 public class ActionChainTask : ActionChainTaskBase, IResolvable {
5 readonly Func<IPromise> m_task;
5 readonly Func<IPromise> m_task;
6
6
7 /// <summary>
7 /// <summary>
@@ -1,7 +1,7
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class ActionTask : ActionTaskBase, IDeferred {
4 public class ActionTask : ActionTaskBase, IResolvable {
5 readonly Action m_task;
5 readonly Action m_task;
6 public ActionTask(Action task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
6 public ActionTask(Action task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 m_task = task;
7 m_task = task;
@@ -1,6 +1,6
1 using System;
1 using System;
2 using System.Diagnostics.CodeAnalysis;
2 using System.Diagnostics.CodeAnalysis;
3
3
4 namespace Implab.Components {
4 namespace Implab.Components {
5 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
5 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
6 enum Commands {
6 enum Commands {
@@ -18,28 +18,28 namespace Implab.Components {
18 public static readonly ExecutionState[,] ReusableTransitions;
18 public static readonly ExecutionState[,] ReusableTransitions;
19 public static readonly ExecutionState[,] NonreusableTransitions;
19 public static readonly ExecutionState[,] NonreusableTransitions;
20
20
21 class StateBuilder {
21 class StateBuilder {
22 readonly ExecutionState[,] m_states;
22 readonly ExecutionState[,] m_states;
23
23
24 public ExecutionState[,] States {
24 public ExecutionState[,] States {
25 get { return m_states; }
25 get { return m_states; }
26 }
26 }
27 public StateBuilder(ExecutionState[,] states) {
27 public StateBuilder(ExecutionState[,] states) {
28 m_states = states;
28 m_states = states;
29 }
29 }
30
30
31 public StateBuilder() {
31 public StateBuilder() {
32 m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
32 m_states = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
33 }
33 }
34
34
35 public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
35 public StateBuilder Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
36 m_states[(int)s1, (int)cmd] = s2;
36 m_states[(int)s1, (int)cmd] = s2;
37 return this;
37 return this;
38 }
38 }
39
39
40 public StateBuilder Clone() {
40 public StateBuilder Clone() {
41 return new StateBuilder((ExecutionState[,])m_states.Clone());
41 return new StateBuilder((ExecutionState[,])m_states.Clone());
42 }
42 }
43 }
43 }
44
44
45 static StateMachine() {
45 static StateMachine() {
@@ -65,8 +65,8 namespace Implab.Components {
65 .Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose)
65 .Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose)
66
66
67 .Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose)
67 .Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose)
68 .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset)
68 .Edge(ExecutionState.Failed, ExecutionState.Initializing, Commands.Reset)
69
69
70 .Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail)
70 .Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail)
71 .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose)
71 .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Dispose)
72
72
@@ -74,11 +74,11 namespace Implab.Components {
74
74
75 var reusable = common
75 var reusable = common
76 .Clone()
76 .Clone()
77 .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok);
77 .Edge(ExecutionState.Stopping, ExecutionState.Ready, Commands.Ok);
78
78
79 var nonreusable = common
79 var nonreusable = common
80 .Clone()
80 .Clone()
81 .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
81 .Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
82
82
83 NonreusableTransitions = nonreusable.States;
83 NonreusableTransitions = nonreusable.States;
84 ReusableTransitions = reusable.States;
84 ReusableTransitions = reusable.States;
@@ -109,45 +109,45 namespace Implab.Components {
109 IPromise m_pending;
109 IPromise m_pending;
110 Exception m_lastError;
110 Exception m_lastError;
111
111
112 readonly StateMachine m_stateMachine;
112 readonly StateMachine m_stateMachine;
113 readonly bool m_reusable;
113 readonly bool m_reusable;
114 public event EventHandler<StateChangeEventArgs> StateChanged;
114 public event EventHandler<StateChangeEventArgs> StateChanged;
115
115
116 /// <summary>
116 /// <summary>
117 /// Initializes component state.
117 /// Initializes component state.
118 /// </summary>
118 /// </summary>
119 /// <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>
119 /// <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>
120 /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param>
120 /// <param name="reusable">If set, the component may start after it has been stopped, otherwise the component is disposed after being stopped.</param>
121 protected RunnableComponent(bool initialized, bool reusable) {
121 protected RunnableComponent(bool initialized, bool reusable) {
122 m_stateMachine = new StateMachine(
122 m_stateMachine = new StateMachine(
123 reusable ? StateMachine.ReusableTransitions : StateMachine.NonreusableTransitions,
123 reusable ? StateMachine.ReusableTransitions : StateMachine.NonreusableTransitions,
124 initialized ? ExecutionState.Ready : ExecutionState.Created
124 initialized ? ExecutionState.Ready : ExecutionState.Created
125 );
125 );
126 m_reusable = reusable;
126 m_reusable = reusable;
127 }
127 }
128
128
129 /// <summary>
129 /// <summary>
130 /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop.
130 /// Initializes component state. The component created with this constructor is not reusable, i.e. it will be disposed after stop.
131 /// </summary>
131 /// </summary>
132 /// <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>
132 /// <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>
133 protected RunnableComponent(bool initialized) : this(initialized, false) {
133 protected RunnableComponent(bool initialized) : this(initialized, false) {
134 }
134 }
135
135
136 void ThrowInvalidCommand(Commands cmd) {
136 void ThrowInvalidCommand(Commands cmd) {
137 if (m_stateMachine.State == ExecutionState.Disposed)
137 if (m_stateMachine.State == ExecutionState.Disposed)
138 throw new ObjectDisposedException(ToString());
138 throw new ObjectDisposedException(ToString());
139
139
140 throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
140 throw new InvalidOperationException(String.Format("Command {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
141 }
141 }
142
142
143 bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) {
143 bool MoveIfInState(Commands cmd, IPromise pending, Exception error, ExecutionState state) {
144 ExecutionState prev, current;
144 ExecutionState prev, current;
145 lock (m_stateMachine) {
145 lock (m_stateMachine) {
146 if (m_stateMachine.State != state)
146 if (m_stateMachine.State != state)
147 return false;
147 return false;
148
148
149 prev = m_stateMachine.State;
149 prev = m_stateMachine.State;
150 if (!m_stateMachine.Move(cmd))
150 if (!m_stateMachine.Move(cmd))
151 ThrowInvalidCommand(cmd);
151 ThrowInvalidCommand(cmd);
152 current = m_stateMachine.State;
152 current = m_stateMachine.State;
153
153
@@ -161,46 +161,46 namespace Implab.Components {
161
161
162 bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) {
162 bool MoveIfPending(Commands cmd, IPromise pending, Exception error, IPromise expected) {
163 ExecutionState prev, current;
163 ExecutionState prev, current;
164 lock (m_stateMachine) {
164 lock (m_stateMachine) {
165 if (m_pending != expected)
165 if (m_pending != expected)
166 return false;
166 return false;
167 prev = m_stateMachine.State;
167 prev = m_stateMachine.State;
168 if (!m_stateMachine.Move(cmd))
168 if (!m_stateMachine.Move(cmd))
169 ThrowInvalidCommand(cmd);
169 ThrowInvalidCommand(cmd);
170 current = m_stateMachine.State;
170 current = m_stateMachine.State;
171 m_pending = pending;
171 m_pending = pending;
172 m_lastError = error;
172 m_lastError = error;
173 }
173 }
174 if (prev != current)
174 if (prev != current)
175 OnStateChanged(prev, current, error);
175 OnStateChanged(prev, current, error);
176 return true;
176 return true;
177 }
177 }
178
178
179 IPromise Move(Commands cmd, IPromise pending, Exception error) {
179 IPromise Move(Commands cmd, IPromise pending, Exception error) {
180 ExecutionState prev, current;
180 ExecutionState prev, current;
181 IPromise ret;
181 IPromise ret;
182 lock (m_stateMachine) {
182 lock (m_stateMachine) {
183 prev = m_stateMachine.State;
183 prev = m_stateMachine.State;
184 if (!m_stateMachine.Move(cmd))
184 if (!m_stateMachine.Move(cmd))
185 ThrowInvalidCommand(cmd);
185 ThrowInvalidCommand(cmd);
186 current = m_stateMachine.State;
186 current = m_stateMachine.State;
187
187
188 ret = m_pending;
188 ret = m_pending;
189 m_pending = pending;
189 m_pending = pending;
190 m_lastError = error;
190 m_lastError = error;
191
191
192 }
192 }
193 if (prev != current)
193 if (prev != current)
194 OnStateChanged(prev, current, error);
194 OnStateChanged(prev, current, error);
195 return ret;
195 return ret;
196 }
196 }
197
197
198 /// <summary>
198 /// <summary>
199 /// Handles the state of the component change event, raises the <see cref="StateChanged"/> event, handles
199 /// Handles the state of the component change event, raises the <see cref="StateChanged"/> event, handles
200 /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method).
200 /// the transition to the <see cref="ExecutionState.Disposed"/> state (calls <see cref="Dispose(bool)"/> method).
201 /// </summary>
201 /// </summary>
202 /// <param name="previous">The previous state</param>
202 /// <param name="previous">The previous state</param>
203 /// <param name="current">The current state</param>
203 /// <param name="current">The current state</param>
204 /// <param name="error">The last error if any.</param>
204 /// <param name="error">The last error if any.</param>
205 /// <remarks>
205 /// <remarks>
206 /// <para>
206 /// <para>
@@ -212,31 +212,31 namespace Implab.Components {
212 /// the wrong behavior of the component.
212 /// the wrong behavior of the component.
213 /// </para>
213 /// </para>
214 /// </remarks>
214 /// </remarks>
215 protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) {
215 protected virtual void OnStateChanged(ExecutionState previous, ExecutionState current, Exception error) {
216 StateChanged.DispatchEvent(
216 StateChanged.DispatchEvent(
217 this,
217 this,
218 new StateChangeEventArgs {
218 new StateChangeEventArgs {
219 State = current,
219 State = current,
220 LastError = error
220 LastError = error
221 }
221 }
222 );
222 );
223 if (current == ExecutionState.Disposed) {
223 if (current == ExecutionState.Disposed) {
224 GC.SuppressFinalize(this);
224 GC.SuppressFinalize(this);
225 Dispose(true);
225 Dispose(true);
226 }
226 }
227 }
227 }
228
228
229 /// <summary>
229 /// <summary>
230 /// Moves the component from running to failed state.
230 /// Moves the component from running to failed state.
231 /// </summary>
231 /// </summary>
232 /// <param name="error">The exception which is describing the error.</param>
232 /// <param name="error">The exception which is describing the error.</param>
233 protected bool Fail(Exception error) {
233 protected bool Fail(Exception error) {
234 return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running);
234 return MoveIfInState(Commands.Fail, null, error, ExecutionState.Running);
235 }
235 }
236
236
237 /// <summary>
237 /// <summary>
238 /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>.
238 /// Tries to reset <see cref="ExecutionState.Failed"/> state to <see cref="ExecutionState.Ready"/>.
239 /// </summary>
239 /// </summary>
240 /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't
240 /// <returns>True if component is reset to <see cref="ExecutionState.Ready"/>, false if the componet wasn't
241 /// in <see cref="ExecutionState.Failed"/> state.</returns>
241 /// in <see cref="ExecutionState.Failed"/> state.</returns>
242 /// <remarks>
242 /// <remarks>
@@ -246,10 +246,10 namespace Implab.Components {
246 /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/>
246 /// to <see cref="ExecutionState.Ready"/> state, otherwise the component is moved to <see cref="ExecutionState.Failed"/>
247 /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller.
247 /// state. If <see cref="OnResetState()"/> throws an exception it will be propagated by this method to the caller.
248 /// </remarks>
248 /// </remarks>
249 protected bool ResetState() {
249 protected bool ResetState() {
250 if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed))
250 if (!MoveIfInState(Commands.Reset, null, null, ExecutionState.Failed))
251 return false;
251 return false;
252
252
253 try {
253 try {
254 OnResetState();
254 OnResetState();
255 Move(Commands.Ok, null, null);
255 Move(Commands.Ok, null, null);
@@ -257,38 +257,38 namespace Implab.Components {
257 } catch (Exception err) {
257 } catch (Exception err) {
258 Move(Commands.Fail, null, err);
258 Move(Commands.Fail, null, err);
259 throw;
259 throw;
260 }
260 }
261 }
261 }
262
262
263 /// <summary>
263 /// <summary>
264 /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state.
264 /// This method is called by <see cref="ResetState"/> to reinitialize component in the failed state.
265 /// </summary>
265 /// </summary>
266 /// <remarks>
266 /// <remarks>
267 /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component
267 /// Default implementation throws <see cref="NotImplementedException"/> which will cause the component
268 /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state.
268 /// fail to reset it's state and it left in <see cref="ExecutionState.Failed"/> state.
269 /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state.
269 /// If this method doesn't throw exceptions the component is moved to <see cref="ExecutionState.Ready"/> state.
270 /// </remarks>
270 /// </remarks>
271 protected virtual void OnResetState() {
271 protected virtual void OnResetState() {
272 throw new NotImplementedException();
272 throw new NotImplementedException();
273 }
273 }
274
274
275 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
275 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IResolvable> chain) {
276 IPromise promise = null;
276 IPromise promise = null;
277 IPromise prev;
277 IPromise prev;
278
278
279 var task = new ActionChainTask(action, null, null, true);
279 var task = new ActionChainTask(action, null, null, true);
280
280
281 Action<Exception> errorOrCancel = e => {
281 Action<Exception> errorOrCancel = e => {
282 if (e == null)
282 if (e == null)
283 e = new OperationCanceledException();
283 e = new OperationCanceledException();
284 MoveIfPending(Commands.Fail, null, e, promise);
284 MoveIfPending(Commands.Fail, null, e, promise);
285 throw new PromiseTransientException(e);
285 throw new PromiseTransientException(e);
286 };
286 };
287
287
288 promise = task.Then(
288 promise = task.Then(
289 () => MoveIfPending(Commands.Ok, null, null, promise),
289 () => MoveIfPending(Commands.Ok, null, null, promise),
290 errorOrCancel,
290 errorOrCancel,
291 errorOrCancel
291 errorOrCancel
292 );
292 );
293
293
294 prev = Move(cmd, promise, null);
294 prev = Move(cmd, promise, null);
@@ -305,8 +305,8 namespace Implab.Components {
305 #region IInitializable implementation
305 #region IInitializable implementation
306
306
307 public void Initialize() {
307 public void Initialize() {
308 Move(Commands.Init, null, null);
308 Move(Commands.Init, null, null);
309
309
310 try {
310 try {
311 OnInitialize();
311 OnInitialize();
312 Move(Commands.Ok, null, null);
312 Move(Commands.Ok, null, null);
@@ -344,7 +344,7 namespace Implab.Components {
344 /// </summary>
344 /// </summary>
345 /// <param name="current">Current.</param>
345 /// <param name="current">Current.</param>
346 /// <param name="stop">Stop.</param>
346 /// <param name="stop">Stop.</param>
347 protected virtual void StopPending(IPromise current, IDeferred stop) {
347 protected virtual void StopPending(IPromise current, IResolvable stop) {
348 if (current == null) {
348 if (current == null) {
349 stop.Resolve();
349 stop.Resolve();
350 } else {
350 } else {
@@ -398,11 +398,11 namespace Implab.Components {
398
398
399 #endregion
399 #endregion
400
400
401 /// <summary>
401 /// <summary>
402 /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
402 /// Releases all resources used by the component, called automatically, override this method to implement your cleanup.
403 /// </summary>
403 /// </summary>
404 /// <param name="disposing">true if this method is called during normal dispose process.</param>
404 /// <param name="disposing">true if this method is called during normal dispose process.</param>
405 /// <param name="pending">The operation which is currenty pending</param>
405 /// <param name="pending">The operation which is currenty pending</param>
406 protected virtual void Dispose(bool disposing) {
406 protected virtual void Dispose(bool disposing) {
407 }
407 }
408
408
@@ -1,7 +1,7
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IDeferred {
4 public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IResolvable {
5 readonly Func<IPromise<TResult>> m_task;
5 readonly Func<IPromise<TResult>> m_task;
6
6
7 public FuncChainTask(Func<IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable)
7 public FuncChainTask(Func<IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable)
@@ -2,7 +2,7
2 using System.Threading;
2 using System.Threading;
3
3
4 namespace Implab {
4 namespace Implab {
5 public class FuncTask<T> : FuncTaskBase<T>, IDeferred {
5 public class FuncTask<T> : FuncTaskBase<T>, IResolvable {
6 readonly Func<T> m_task;
6 readonly Func<T> m_task;
7
7
8 public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel, bool autoCancellable) : base(error, cancel, autoCancellable) {
8 public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel, bool autoCancellable) : base(error, cancel, autoCancellable) {
@@ -14,11 +14,11 namespace Implab {
14 /// <summary>
14 /// <summary>
15 /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено.
15 /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено.
16 /// </summary>
16 /// </summary>
17 bool IsFulfilled { get; }
17 bool IsResolved { get; }
18
18
19 bool IsRejected { get; }
19 bool IsRejected { get; }
20
20
21 bool IsResolved { get; }
21 bool IsFulfilled { get; }
22
22
23 /// <summary>
23 /// <summary>
24 /// Исключение возникшее в результате выполнения обещания, либо причина отмены.
24 /// Исключение возникшее в результате выполнения обещания, либо причина отмены.
@@ -31,23 +31,11 namespace Implab {
31 /// <param name="success">The handler called on the successful promise completion.</param>
31 /// <param name="success">The handler called on the successful promise completion.</param>
32 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
32 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
33 /// <returns>The current promise.</returns>
33 /// <returns>The current promise.</returns>
34 void On(Action success, Action<Exception> error);
34 void Then(IResolvable next);
35
35
36 /// <summary>
36 /// <summary>
37 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
37 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
38 /// </summary>
38 /// </summary>
39 IPromise<T> Cast<T>();
39 IPromise<T> Cast<T>();
40
41 /// <summary>
42 /// Синхронизирует текущий поток с обещанием.
43 /// </summary>
44 void Join();
45 /// <summary>
46 /// Синхронизирует текущий поток с обещанием.
47 /// </summary>
48 /// <param name="timeout">Время ожидания, по его истечению возникнет исключение.</param>
49 /// <exception cref="TimeoutException">Превышено время ожидания.</exception>
50 void Join(int timeout);
51
52 }
40 }
53 }
41 }
@@ -2,7 +2,7 namespace Implab {
2 public enum PromiseState {
2 public enum PromiseState {
3 Pending,
3 Pending,
4
4
5 Resolved,
5 Fulfilled,
6
6
7 Rejected
7 Rejected
8 }
8 }
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now