##// 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;
@@ -272,7 +272,7 namespace Implab.Components {
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
@@ -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 {
@@ -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