##// END OF EJS Templates
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
cin -
r138:f75cfa58e3d4 v2
parent child
Show More
@@ -19,11 +19,11 namespace Implab.Fx {
19 base.SignalSuccess(handler);
19 base.SignalSuccess(handler);
20 }
20 }
21
21
22 protected override void SignalCancelled(IDeferred<T> handler) {
22 protected override void SignalCancelled(IDeferred<T> handler, Exception reason) {
23 if (m_target.InvokeRequired)
23 if (m_target.InvokeRequired)
24 m_target.BeginInvoke(new Action<IDeferred<T>>(base.SignalCancelled), handler);
24 m_target.BeginInvoke(new Action<IDeferred<T>,Exception>(base.SignalCancelled), handler, reason);
25 else
25 else
26 base.SignalCancelled(handler);
26 base.SignalCancelled(handler, reason);
27 }
27 }
28
28
29 protected override void SignalError(IDeferred<T> handler, Exception error) {
29 protected override void SignalError(IDeferred<T> handler, Exception error) {
@@ -53,7 +53,7 namespace Implab.Test {
53 var p = new Promise<bool>();
53 var p = new Promise<bool>();
54 p.Cancel();
54 p.Cancel();
55
55
56 var p2 = p.Cancelled(() => {
56 var p2 = p.Then(x => x, null, reason => {
57 throw new ApplicationException("CANCELLED");
57 throw new ApplicationException("CANCELLED");
58 });
58 });
59
59
@@ -72,10 +72,10 namespace Implab.Test {
72 p.Cancel();
72 p.Cancel();
73
73
74 var p2 = p
74 var p2 = p
75 .Cancelled<bool>(() => {
75 .Then<bool>(x => x, null, reason => {
76 throw new ApplicationException("CANCELLED");
76 throw new ApplicationException("CANCELLED");
77 })
77 })
78 .Error(e => true);
78 .Then(x => x, e => true);
79
79
80 Assert.AreEqual(true, p2.Join());
80 Assert.AreEqual(true, p2.Join());
81 }
81 }
@@ -116,7 +116,7 namespace Implab.Test {
116 public void FixErrorTest() {
116 public void FixErrorTest() {
117 var p = new Promise<int>();
117 var p = new Promise<int>();
118
118
119 var p2 = p.Error(e => 101);
119 var p2 = p.Then(x => x, e => 101);
120
120
121 p.Reject(new Exception());
121 p.Reject(new Exception());
122
122
@@ -760,7 +760,7 namespace Implab.Test {
760 });
760 });
761
761
762 result
762 result
763 .Cancelled(() => pSurvive.Resolve(true));
763 .On(() => pSurvive.Resolve(true), PromiseEventType.Cancelled);
764
764
765 return result;
765 return result;
766 });
766 });
@@ -68,9 +68,15 namespace Implab {
68 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
68 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
69 protected void SetError(Exception error) {
69 protected void SetError(Exception error) {
70 if (BeginTransit()) {
70 if (BeginTransit()) {
71 m_error = error is PromiseTransientException ? error.InnerException : error;
71 if (error is OperationCanceledException) {
72 CompleteTransit(REJECTED_STATE);
72 CompleteTransit(CANCELLED_STATE);
73 OnError();
73 m_error = error.InnerException;
74 OnCancelled();
75 } else {
76 m_error = error is PromiseTransientException ? error.InnerException : error;
77 CompleteTransit(REJECTED_STATE);
78 OnError();
79 }
74 } else {
80 } else {
75 WaitTransition();
81 WaitTransition();
76 if (m_state == SUCCEEDED_STATE)
82 if (m_state == SUCCEEDED_STATE)
@@ -82,8 +88,9 namespace Implab {
82 /// Отменяет операцию, если это возможно.
88 /// Отменяет операцию, если это возможно.
83 /// </summary>
89 /// </summary>
84 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
90 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
85 protected void SetCancelled() {
91 protected void SetCancelled(Exception reason) {
86 if (BeginTransit()) {
92 if (BeginTransit()) {
93 m_error = reason;
87 CompleteTransit(CANCELLED_STATE);
94 CompleteTransit(CANCELLED_STATE);
88 OnCancelled();
95 OnCancelled();
89 }
96 }
@@ -93,7 +100,7 namespace Implab {
93
100
94 protected abstract void SignalError(THandler handler, Exception error);
101 protected abstract void SignalError(THandler handler, Exception error);
95
102
96 protected abstract void SignalCancelled(THandler handler);
103 protected abstract void SignalCancelled(THandler handler, Exception reason);
97
104
98 void OnSuccess() {
105 void OnSuccess() {
99 var hp = m_handlerPointer;
106 var hp = m_handlerPointer;
@@ -137,7 +144,7 namespace Implab {
137 var slot = hp +1 ;
144 var slot = hp +1 ;
138 while (slot < m_handlersCommited) {
145 while (slot < m_handlersCommited) {
139 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
146 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
140 SignalCancelled(m_handlers[slot]);
147 SignalCancelled(m_handlers[slot], m_error);
141 }
148 }
142 hp = m_handlerPointer;
149 hp = m_handlerPointer;
143 slot = hp +1 ;
150 slot = hp +1 ;
@@ -146,7 +153,7 namespace Implab {
146 if (m_extraHandlers != null) {
153 if (m_extraHandlers != null) {
147 THandler handler;
154 THandler handler;
148 while (m_extraHandlers.TryDequeue(out handler))
155 while (m_extraHandlers.TryDequeue(out handler))
149 SignalCancelled(handler);
156 SignalCancelled(handler, m_error);
150 }
157 }
151 }
158 }
152
159
@@ -241,7 +248,7 namespace Implab {
241 SignalSuccess(handler);
248 SignalSuccess(handler);
242 break;
249 break;
243 case CANCELLED_STATE:
250 case CANCELLED_STATE:
244 SignalCancelled(handler);
251 SignalCancelled(handler, m_error);
245 break;
252 break;
246 case REJECTED_STATE:
253 case REJECTED_STATE:
247 SignalError(handler, m_error);
254 SignalError(handler, m_error);
@@ -282,10 +289,20 namespace Implab {
282 #region ICancellable implementation
289 #region ICancellable implementation
283
290
284 public void Cancel() {
291 public void Cancel() {
285 SetCancelled();
292 SetCancelled(null);
293 }
294
295 public void Cancel(Exception reason) {
296 SetCancelled(reason);
286 }
297 }
287
298
288 #endregion
299 #endregion
300
301 public Exception Error {
302 get {
303 return m_error;
304 }
305 }
289 }
306 }
290 }
307 }
291
308
@@ -17,9 +17,9
17 TraceLog.EndLogicalOperation();
17 TraceLog.EndLogicalOperation();
18 TraceContext.Instance.Leave();
18 TraceContext.Instance.Leave();
19 },
19 },
20 () => {
20 reason => {
21 TraceContext.Instance.EnterLogicalOperation(op,true);
21 TraceContext.Instance.EnterLogicalOperation(op,true);
22 TraceLog.TraceInformation("promise cancelled");
22 TraceLog.TraceInformation("promise cancelled {0}", reason.Message);
23 TraceLog.EndLogicalOperation();
23 TraceLog.EndLogicalOperation();
24 TraceContext.Instance.Leave();
24 TraceContext.Instance.Leave();
25 }
25 }
@@ -6,5 +6,6 using System.Text;
6 namespace Implab {
6 namespace Implab {
7 public interface ICancellable {
7 public interface ICancellable {
8 void Cancel();
8 void Cancel();
9 void Cancel(Exception reason);
9 }
10 }
10 }
11 }
@@ -8,6 +8,16 namespace Implab {
8
8
9 void Resolve();
9 void Resolve();
10
10
11 /// <summary>
12 /// Reject the promise with the specified error.
13 /// </summary>
14 /// <param name="error">The reason why the promise is rejected.</param>
15 /// <remarks>
16 /// Some exceptions are treated in a special case:
17 /// <see cref="OperationCanceledException"/> is interpreted as call to <see cref="Cancel()"/> method,
18 /// and <see cref="PromiseTransientException"/> is always unwrapped and its
19 /// <see cref="PromiseTransientException.InnerException"> is used as the reason to reject promise.
20 /// </remarks>
11 void Reject(Exception error);
21 void Reject(Exception error);
12 }
22 }
13 }
23 }
@@ -22,6 +22,11 namespace Implab {
22 bool IsCancelled { get; }
22 bool IsCancelled { get; }
23
23
24 /// <summary>
24 /// <summary>
25 /// Исключение возникшее в результате выполнения обещания, либо причина отмены.
26 /// </summary>
27 Exception Error { get; }
28
29 /// <summary>
25 /// Creates a new promise dependend on the current one and resolved on
30 /// Creates a new promise dependend on the current one and resolved on
26 /// executing the specified handlers.
31 /// executing the specified handlers.
27 /// </summary>
32 /// </summary>
@@ -43,19 +48,21 namespace Implab {
43 /// exception then the dependant promise will be resolved successfully, otherwise the exception
48 /// exception then the dependant promise will be resolved successfully, otherwise the exception
44 /// raised by the handler will be transmitted to the dependent promise. If the handler wants
49 /// raised by the handler will be transmitted to the dependent promise. If the handler wants
45 /// to passthrough the original exception it needs to wrap the exception with
50 /// to passthrough the original exception it needs to wrap the exception with
46 /// the <see cref="PromiseTransientException"/>.
51 /// the <see cref="PromiseTransientException"/>. The handler may raise <see cref="OperationCanceledException"/>
52 /// to cancel the dependant promise, the innner exception specifies the reason why the promise
53 /// is canceled.
47 /// </para>
54 /// </para>
48 /// <para>
55 /// <para>
49 /// If the cancelation handler is specified and the current promise is cancelled then the dependent
56 /// If the cancelation handler is specified and the current promise is cancelled then the dependent
50 /// promise will be resolved after the handler is executed. If the cancelation hendler raises the
57 /// promise will be resolved after the handler is executed. If the cancelation handler raises the
51 /// exception it will be passed to the dependent promise.
58 /// exception it will be passed to the dependent promise.
52 /// </para>
59 /// </para>
53 /// </remarks>
60 /// </remarks>
54 IPromise Then(Action success, Action<Exception> error, Action cancel);
61 IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel);
55 IPromise Then(Action success, Action<Exception> error);
62 IPromise Then(Action success, Action<Exception> error);
56 IPromise Then(Action success);
63 IPromise Then(Action success);
57
64
58 IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<IPromise> cancel);
65 IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel);
59 IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error);
66 IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error);
60 IPromise Chain(Func<IPromise> chained);
67 IPromise Chain(Func<IPromise> chained);
61
68
@@ -66,7 +73,7 namespace Implab {
66 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
73 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
67 /// <param name="cancel">The handler is called in case of promise cancellation.</param>
74 /// <param name="cancel">The handler is called in case of promise cancellation.</param>
68 /// <returns>The current promise.</returns>
75 /// <returns>The current promise.</returns>
69 IPromise On(Action success, Action<Exception> error, Action cancel);
76 IPromise On(Action success, Action<Exception> error, Action<Exception> cancel);
70 IPromise On(Action success, Action<Exception> error);
77 IPromise On(Action success, Action<Exception> error);
71 IPromise On(Action success);
78 IPromise On(Action success);
72
79
@@ -80,42 +87,6 namespace Implab {
80 IPromise On(Action handler, PromiseEventType events);
87 IPromise On(Action handler, PromiseEventType events);
81
88
82 /// <summary>
89 /// <summary>
83 /// Adds the specified error handler to the current promise
84 /// and creates the new dependant promise.
85 /// </summary>
86 /// <param name="error">
87 /// The error handler. If the error handler returns without
88 /// an error the dependant promise will be successfully resolved.
89 /// </param>
90 /// <returns>
91 /// The new dependant promise which will be resolved after the error
92 /// handler is executed.
93 /// </returns>
94 /// <remarks>
95 /// The successfull result of the current promise will be ignored.
96 /// </remarks>
97 IPromise Error(Action<Exception> error);
98
99 /// <summary>
100 /// Adds the specified cncellation handler to the current promise
101 /// and creates the new dependant promise.
102 /// </summary>
103 /// <returns>
104 /// The new dependant promise which will be resolved after the cancellation
105 /// handler is executed.
106 /// </returns>
107 /// <param name="handler">
108 /// The cancellation handler.
109 /// </param>
110 /// <remarks>
111 /// If the cancellation handler is executed without an error the dependent
112 /// promise will be successfully resolved, otherwise the raised exception
113 /// will be passed to the dependant promise. The successful result of the
114 /// current promise will be ignored.
115 /// </remarks>
116 IPromise Cancelled(Action handler);
117
118 /// <summary>
119 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
90 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
120 /// </summary>
91 /// </summary>
121 IPromise<T> Cast<T>();
92 IPromise<T> Cast<T>();
@@ -7,7 +7,7 namespace Implab {
7
7
8 new T Join(int timeout);
8 new T Join(int timeout);
9
9
10 IPromise<T> On(Action<T> success, Action<Exception> error, Action cancel);
10 IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel);
11
11
12 IPromise<T> On(Action<T> success, Action<Exception> error);
12 IPromise<T> On(Action<T> success, Action<Exception> error);
13
13
@@ -15,20 +15,16 namespace Implab {
15
15
16 new IPromise<T> On(Action handler, PromiseEventType events);
16 new IPromise<T> On(Action handler, PromiseEventType events);
17
17
18 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error, Func<T2> cancel);
18 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel);
19
19
20 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error);
20 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error);
21
21
22 IPromise<T2> Then<T2>(Func<T, T2> mapper);
22 IPromise<T2> Then<T2>(Func<T, T2> mapper);
23
23
24 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception,IPromise<T2>> error, Func<IPromise<T2>> cancel);
24 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel);
25
25
26 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception,IPromise<T2>> error);
26 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error);
27
27
28 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained);
28 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained);
29
30 IPromise<T2> Error<T2>(Func<Exception,T2> error);
31
32 IPromise<T2> Cancelled<T2>(Func<T2> handler);
33 }
29 }
34 }
30 }
@@ -7,10 +7,10 namespace Implab {
7 public struct HandlerDescriptor {
7 public struct HandlerDescriptor {
8 readonly Action m_success;
8 readonly Action m_success;
9 readonly Action<Exception> m_error;
9 readonly Action<Exception> m_error;
10 readonly Action m_cancel;
10 readonly Action<Exception> m_cancel;
11 readonly IDeferred m_deferred;
11 readonly IDeferred m_deferred;
12
12
13 public HandlerDescriptor(Action success, Action<Exception> error, Action cancel, IDeferred deferred) {
13 public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel, IDeferred deferred) {
14 m_success = success;
14 m_success = success;
15 m_error = error;
15 m_error = error;
16 m_cancel = cancel;
16 m_cancel = cancel;
@@ -45,10 +45,18 namespace Implab {
45 }
45 }
46 }
46 }
47
47
48 public void SignalCancel() {
48 public void SignalCancel(Exception reason) {
49 if (m_cancel != null) {
49 if (m_cancel != null) {
50 try {
50 try {
51 m_cancel();
51 m_cancel(reason);
52 if (m_deferred != null)
53 m_deferred.Resolve();
54 } catch (Exception err) {
55 SignalError(err);
56 }
57 } else if (reason != null && m_error != null) {
58 try {
59 m_error(new OperationCanceledException("The operation was canceled.", reason));
52 if (m_deferred != null)
60 if (m_deferred != null)
53 m_deferred.Resolve();
61 m_deferred.Resolve();
54 } catch (Exception err) {
62 } catch (Exception err) {
@@ -56,7 +64,7 namespace Implab {
56 }
64 }
57 } else {
65 } else {
58 if (m_deferred != null)
66 if (m_deferred != null)
59 m_deferred.Cancel();
67 m_deferred.Cancel(reason);
60 }
68 }
61 }
69 }
62 }
70 }
@@ -80,15 +88,15 namespace Implab {
80 handler.SignalError(error);
88 handler.SignalError(error);
81 }
89 }
82
90
83 protected override void SignalCancelled(HandlerDescriptor handler) {
91 protected override void SignalCancelled(HandlerDescriptor handler, Exception reason) {
84 handler.SignalCancel();
92 handler.SignalCancel(reason);
85 }
93 }
86
94
87 protected override void Listen(PromiseEventType events, Action handler) {
95 protected override void Listen(PromiseEventType events, Action handler) {
88 AddHandler(new HandlerDescriptor(
96 AddHandler(new HandlerDescriptor(
89 events.HasFlag(PromiseEventType.Success) ? handler : null,
97 events.HasFlag(PromiseEventType.Success) ? handler : null,
90 events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null,
98 events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null,
91 events.HasFlag(PromiseEventType.Cancelled) ? handler : null,
99 events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null,
92 null
100 null
93 ));
101 ));
94 }
102 }
@@ -102,7 +110,7 namespace Implab {
102 }
110 }
103 }
111 }
104
112
105 public IPromise Then(Action success, Action<Exception> error, Action cancel) {
113 public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) {
106 var promise = new Promise();
114 var promise = new Promise();
107 if (success != null)
115 if (success != null)
108 promise.On(Cancel, PromiseEventType.Cancelled);
116 promise.On(Cancel, PromiseEventType.Cancelled);
@@ -120,7 +128,7 namespace Implab {
120 return Then(success, null, null);
128 return Then(success, null, null);
121 }
129 }
122
130
123 public IPromise On(Action success, Action<Exception> error, Action cancel) {
131 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) {
124 AddHandler(new HandlerDescriptor(success, error, cancel, null));
132 AddHandler(new HandlerDescriptor(success, error, cancel, null));
125 return this;
133 return this;
126 }
134 }
@@ -137,7 +145,7 namespace Implab {
137 return On(
145 return On(
138 events.HasFlag(PromiseEventType.Success) ? handler : null,
146 events.HasFlag(PromiseEventType.Success) ? handler : null,
139 events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null,
147 events.HasFlag(PromiseEventType.Error) ? new Action<Exception>(err => handler()) : null,
140 events.HasFlag(PromiseEventType.Cancelled) ? handler : null
148 events.HasFlag(PromiseEventType.Cancelled) ? new Action<Exception>(reason => handler()) : null
141 );
149 );
142 }
150 }
143
151
@@ -145,7 +153,7 namespace Implab {
145 throw new InvalidCastException();
153 throw new InvalidCastException();
146 }
154 }
147
155
148 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<IPromise> cancel) {
156 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception,IPromise> cancel) {
149 var medium = new Promise();
157 var medium = new Promise();
150
158
151 On(
159 On(
@@ -168,13 +176,13 namespace Implab {
168 medium.Reject(ex);
176 medium.Reject(ex);
169 }
177 }
170 },
178 },
171 () => {
179 reason => {
172 if (medium.IsCancelled)
180 if (medium.IsCancelled)
173 return;
181 return;
174 if (cancel != null)
182 if (cancel != null)
175 ConnectPromise(cancel(), medium);
183 ConnectPromise(cancel(reason), medium);
176 else
184 else
177 medium.Cancel();
185 medium.Cancel(reason);
178 }
186 }
179 );
187 );
180
188
@@ -189,9 +197,9 namespace Implab {
189 result.On(
197 result.On(
190 medium.Resolve,
198 medium.Resolve,
191 medium.Reject,
199 medium.Reject,
192 () => medium.Reject(new OperationCanceledException())
200 medium.Cancel
193 );
201 );
194 medium.On(result.Cancel, PromiseEventType.Cancelled);
202 medium.On(null,null,result.Cancel);
195 } else {
203 } else {
196 medium.Reject(
204 medium.Reject(
197 new NullReferenceException(
205 new NullReferenceException(
@@ -209,50 +217,6 namespace Implab {
209 public IPromise Chain(Func<IPromise> chained) {
217 public IPromise Chain(Func<IPromise> chained) {
210 return Chain(chained, null, null);
218 return Chain(chained, null, null);
211 }
219 }
212
213 public IPromise Error(Action<Exception> error) {
214 var promise = new Promise();
215 On(
216 null,
217 err => {
218 if (error != null)
219 try {
220 error(err);
221 promise.Resolve();
222 } catch (Exception err2) {
223 promise.Reject(err2);
224 }
225 else
226 promise.Reject(err);
227 }
228 );
229
230 return promise;
231 }
232
233 public IPromise Cancelled(Action handler) {
234 var promise = new Promise();
235 On(
236 null,
237 null,
238 () => {
239 if (handler != null) {
240 try {
241 handler();
242 promise.Resolve();
243 } catch (Exception err) {
244 promise.Reject(err);
245 }
246 } else {
247 promise.Cancel();
248 }
249 }
250 );
251
252 return promise;
253 }
254
255
256 }
220 }
257 }
221 }
258
222
@@ -56,7 +56,7 namespace Implab {
56 Safe.ArgumentNotNull(that, "that");
56 Safe.ArgumentNotNull(that, "that");
57 Safe.ArgumentNotNull(head, "head");
57 Safe.ArgumentNotNull(head, "head");
58
58
59 that.On(null,null,() => head.On(cleanup));
59 that.On(() => head.On(cleanup), PromiseEventType.Cancelled);
60
60
61 return that;
61 return that;
62 }
62 }
@@ -123,9 +123,9 namespace Implab {
123 new Exception("The dependency promise is failed", error)
123 new Exception("The dependency promise is failed", error)
124 );
124 );
125 },
125 },
126 () => {
126 reason => {
127 if (Interlocked.Increment(ref errors) == 1)
127 if (Interlocked.Increment(ref errors) == 1)
128 medium.Reject(
128 medium.Cancel(
129 new Exception("The dependency promise is cancelled")
129 new Exception("The dependency promise is cancelled")
130 );
130 );
131 }
131 }
@@ -162,10 +162,10 namespace Implab {
162 new Exception("The dependency promise is failed", error)
162 new Exception("The dependency promise is failed", error)
163 );
163 );
164 },
164 },
165 () => {
165 reason => {
166 if (Interlocked.Increment(ref errors) == 1)
166 if (Interlocked.Increment(ref errors) == 1)
167 medium.Reject(
167 medium.Cancel(
168 new Exception("The dependency promise is cancelled")
168 new Exception("The dependency promise is cancelled", reason)
169 );
169 );
170 }
170 }
171 );
171 );
@@ -181,7 +181,7 namespace Implab {
181 Safe.ArgumentNotNull(that, "that");
181 Safe.ArgumentNotNull(that, "that");
182 var tcs = new TaskCompletionSource<T>();
182 var tcs = new TaskCompletionSource<T>();
183
183
184 that.On(tcs.SetResult, tcs.SetException, tcs.SetCanceled);
184 that.On(tcs.SetResult, tcs.SetException, r => tcs.SetCanceled());
185
185
186 return tcs.Task;
186 return tcs.Task;
187 }
187 }
@@ -39,7 +39,7 namespace Implab {
39 /// </remarks>
39 /// </remarks>
40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> {
40 public class Promise<T> : AbstractPromise<IDeferred<T>>, IPromise<T>, IDeferred<T> {
41
41
42 class StubDeferred : IDeferred<T> {
42 class StubDeferred : IDeferred, IDeferred<T> {
43 public static readonly StubDeferred instance = new StubDeferred();
43 public static readonly StubDeferred instance = new StubDeferred();
44
44
45 StubDeferred() {
45 StubDeferred() {
@@ -50,6 +50,9 namespace Implab {
50 public void Resolve(T value) {
50 public void Resolve(T value) {
51 }
51 }
52
52
53 public void Resolve() {
54 }
55
53 public void Reject(Exception error) {
56 public void Reject(Exception error) {
54 }
57 }
55
58
@@ -60,6 +63,9 namespace Implab {
60 public void Cancel() {
63 public void Cancel() {
61 }
64 }
62
65
66 public void Cancel(Exception reason) {
67 }
68
63 #endregion
69 #endregion
64
70
65
71
@@ -67,11 +73,11 namespace Implab {
67
73
68 class RemapDescriptor<T2> : IDeferred<T> {
74 class RemapDescriptor<T2> : IDeferred<T> {
69 readonly Func<T,T2> m_remap;
75 readonly Func<T,T2> m_remap;
70 readonly Func<Exception,T2> m_failed;
76 readonly Func<Exception, T2> m_failed;
71 readonly Func<T2> m_cancel;
77 readonly Func<Exception, T2> m_cancel;
72 readonly IDeferred<T2> m_deferred;
78 readonly IDeferred<T2> m_deferred;
73
79
74 public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<T2> cancel, IDeferred<T2> deferred ) {
80 public RemapDescriptor(Func<T,T2> remap, Func<Exception,T2> failed, Func<Exception, T2> cancel, IDeferred<T2> deferred ) {
75 Debug.Assert(deferred != null);
81 Debug.Assert(deferred != null);
76 m_remap = remap;
82 m_remap = remap;
77 m_failed = failed;
83 m_failed = failed;
@@ -110,18 +116,21 namespace Implab {
110
116
111 #region ICancellable implementation
117 #region ICancellable implementation
112
118
113 public void Cancel() {
119 public void Cancel(Exception reason) {
114 if (m_cancel != null) {
120 if (m_cancel != null) {
115 try {
121 try {
116 m_deferred.Resolve(m_cancel());
122 m_deferred.Resolve(m_cancel(reason));
117 } catch (Exception ex) {
123 } catch (Exception ex) {
118 Reject(ex);
124 Reject(ex);
119 }
125 }
120 } else {
126 } else {
121 m_deferred.Cancel();
127 m_deferred.Cancel(reason);
122 }
128 }
123 }
129 }
124
130
131 public void Cancel() {
132 Cancel(null);
133 }
125 #endregion
134 #endregion
126 }
135 }
127
136
@@ -163,6 +172,10 namespace Implab {
163 #region ICancellable implementation
172 #region ICancellable implementation
164
173
165 public void Cancel() {
174 public void Cancel() {
175 Cancel(null);
176 }
177
178 public void Cancel(Exception reason) {
166 if (m_events.HasFlag(PromiseEventType.Cancelled)){
179 if (m_events.HasFlag(PromiseEventType.Cancelled)){
167 try {
180 try {
168 m_handler();
181 m_handler();
@@ -178,10 +191,10 namespace Implab {
178 class ValueEventDescriptor : IDeferred<T> {
191 class ValueEventDescriptor : IDeferred<T> {
179 readonly Action<T> m_success;
192 readonly Action<T> m_success;
180 readonly Action<Exception> m_failed;
193 readonly Action<Exception> m_failed;
181 readonly Action m_cancelled;
194 readonly Action<Exception> m_cancelled;
182 readonly IDeferred<T> m_deferred;
195 readonly IDeferred<T> m_deferred;
183
196
184 public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action cancelled, IDeferred<T> deferred) {
197 public ValueEventDescriptor(Action<T> success, Action<Exception> failed, Action<Exception> cancelled, IDeferred<T> deferred) {
185 Debug.Assert(deferred != null);
198 Debug.Assert(deferred != null);
186
199
187 m_success = success;
200 m_success = success;
@@ -220,29 +233,33 namespace Implab {
220
233
221 #region ICancellable implementation
234 #region ICancellable implementation
222
235
223 public void Cancel() {
236 public void Cancel(Exception reason) {
224 if (m_cancelled != null) {
237 if (m_cancelled != null) {
225 try {
238 try {
226 m_cancelled();
239 m_cancelled(reason);
227 m_deferred.Resolve(default(T));
240 m_deferred.Resolve(default(T));
228 } catch(Exception ex) {
241 } catch (Exception ex) {
229 Reject(ex);
242 Reject(ex);
230 }
243 }
231 } else {
244 } else {
232 m_deferred.Cancel();
245 m_deferred.Cancel(reason);
233 }
246 }
234 }
247 }
235
248
249 public void Cancel() {
250 Cancel(null);
251 }
252
236 #endregion
253 #endregion
237 }
254 }
238
255
239 public class EventDescriptor : IDeferred<T> {
256 public class EventDescriptor : IDeferred<T> {
240 readonly Action m_success;
257 readonly Action m_success;
241 readonly Action<Exception> m_failed;
258 readonly Action<Exception> m_failed;
242 readonly Action m_cancelled;
259 readonly Action<Exception> m_cancelled;
243 readonly IDeferred<T> m_deferred;
260 readonly IDeferred m_deferred;
244
261
245 public EventDescriptor(Action success, Action<Exception> failed, Action cancelled, IDeferred<T> deferred) {
262 public EventDescriptor(Action success, Action<Exception> failed, Action<Exception> cancelled, IDeferred deferred) {
246 Debug.Assert(deferred != null);
263 Debug.Assert(deferred != null);
247
264
248 m_success = success;
265 m_success = success;
@@ -257,7 +274,7 namespace Implab {
257 if (m_success != null) {
274 if (m_success != null) {
258 try {
275 try {
259 m_success();
276 m_success();
260 m_deferred.Resolve(value);
277 m_deferred.Resolve();
261 } catch (Exception ex) {
278 } catch (Exception ex) {
262 Reject(ex);
279 Reject(ex);
263 }
280 }
@@ -268,34 +285,36 namespace Implab {
268 if (m_failed != null) {
285 if (m_failed != null) {
269 try {
286 try {
270 m_failed(error);
287 m_failed(error);
271 m_deferred.Resolve(default(T));
288 m_deferred.Resolve();
272 }catch (Exception ex)
289 } catch (Exception ex) {
273 {
274 m_deferred.Reject(ex);
290 m_deferred.Reject(ex);
275 }
291 }
276 } else {
292 } else {
277 m_deferred.Reject(error);
293 m_deferred.Reject(error);
278 }
294 }
279
280 }
295 }
281
296
282 #endregion
297 #endregion
283
298
284 #region ICancellable implementation
299 #region ICancellable implementation
285
300
286 public void Cancel() {
301 public void Cancel(Exception reason) {
287 if (m_cancelled != null) {
302 if (m_cancelled != null) {
288 try {
303 try {
289 m_cancelled();
304 m_cancelled(reason);
290 m_deferred.Resolve(default(T));
305 m_deferred.Resolve();
291 } catch (Exception ex) {
306 } catch (Exception ex) {
292 Reject(ex);
307 Reject(ex);
293 }
308 }
294 } else {
309 } else {
295 m_deferred.Cancel();
310 m_deferred.Cancel(reason);
296 }
311 }
297 }
312 }
298
313
314 public void Cancel() {
315 Cancel(null);
316 }
317
299 #endregion
318 #endregion
300 }
319 }
301
320
@@ -327,7 +346,7 namespace Implab {
327 return m_result;
346 return m_result;
328 }
347 }
329
348
330 public IPromise<T> On(Action<T> success, Action<Exception> error, Action cancel) {
349 public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) {
331 AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance));
350 AddHandler(new ValueEventDescriptor(success, error, cancel, StubDeferred.instance));
332 return this;
351 return this;
333 }
352 }
@@ -347,10 +366,10 namespace Implab {
347 return this;
366 return this;
348 }
367 }
349
368
350 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<T2> cancel) {
369 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error, Func<Exception, T2> cancel) {
351 var promise = new Promise<T2>();
370 var promise = new Promise<T2>();
352 if (mapper != null)
371 if (mapper != null)
353 promise.On(Cancel, PromiseEventType.Cancelled);
372 promise.On((Action)null, null, Cancel);
354 AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise));
373 AddHandler(new RemapDescriptor<T2>(mapper, error, cancel, promise));
355 return promise;
374 return promise;
356 }
375 }
@@ -358,7 +377,7 namespace Implab {
358 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) {
377 public IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception, T2> error) {
359 var promise = new Promise<T2>();
378 var promise = new Promise<T2>();
360 if (mapper != null)
379 if (mapper != null)
361 promise.On(Cancel, PromiseEventType.Cancelled);
380 promise.On((Action)null, null, Cancel);
362 AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise));
381 AddHandler(new RemapDescriptor<T2>(mapper, error, null, promise));
363 return promise;
382 return promise;
364 }
383 }
@@ -366,12 +385,12 namespace Implab {
366 public IPromise<T2> Then<T2>(Func<T, T2> mapper) {
385 public IPromise<T2> Then<T2>(Func<T, T2> mapper) {
367 var promise = new Promise<T2>();
386 var promise = new Promise<T2>();
368 if (mapper != null)
387 if (mapper != null)
369 promise.On(Cancel, PromiseEventType.Cancelled);
388 promise.On((Action)null, null, Cancel);
370 AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise));
389 AddHandler(new RemapDescriptor<T2>(mapper, null, null, promise));
371 return promise;
390 return promise;
372 }
391 }
373
392
374 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<IPromise<T2>> cancel) {
393 public IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) {
375 // this promise will be resolved when an asyc operation is started
394 // this promise will be resolved when an asyc operation is started
376 var promise = new Promise<IPromise<T2>>();
395 var promise = new Promise<IPromise<T2>>();
377
396
@@ -404,7 +423,7 namespace Implab {
404 result.On(
423 result.On(
405 medium.Resolve,
424 medium.Resolve,
406 medium.Reject,
425 medium.Reject,
407 () => medium.Reject(new OperationCanceledException())
426 medium.Cancel
408 );
427 );
409 medium.On(result.Cancel, PromiseEventType.Cancelled);
428 medium.On(result.Cancel, PromiseEventType.Cancelled);
410 } else {
429 } else {
@@ -425,46 +444,10 namespace Implab {
425 return Chain(chained, null, null);
444 return Chain(chained, null, null);
426 }
445 }
427
446
428 public IPromise<T2> Error<T2>(Func<Exception, T2> error) {
447 public IPromise Then(Action success, Action<Exception> error, Action<Exception> cancel) {
429 var promise = new Promise<T2>();
448 var promise = new Promise();
430 if (error != null)
431 On(
432 (Action<T>)null,
433 ex => {
434 try {
435 promise.Resolve(error(ex));
436 } catch (Exception ex2) {
437 promise.Reject(ex2);
438 }
439 }
440 );
441 else
442 Listen(PromiseEventType.Error, () => promise.Resolve(default(T2)));
443 return promise;
444 }
445
446 public IPromise<T2> Cancelled<T2>(Func<T2> handler) {
447 var promise = new Promise<T2>();
448 if (handler != null)
449 On(
450 (Action<T>)null,
451 null,
452 () => {
453 try {
454 promise.Resolve(handler());
455 } catch (Exception ex) {
456 promise.Reject(ex);
457 }
458 });
459 else
460 Listen(PromiseEventType.Cancelled, () => promise.Resolve(default(T2)));
461 return promise;
462 }
463
464 public IPromise Then(Action success, Action<Exception> error, Action cancel) {
465 var promise = new Promise<T>();
466 if (success != null)
449 if (success != null)
467 promise.On(Cancel, PromiseEventType.Cancelled);
450 promise.On(null, null, Cancel);
468
451
469 AddHandler(new EventDescriptor(success, error, cancel, promise));
452 AddHandler(new EventDescriptor(success, error, cancel, promise));
470
453
@@ -479,7 +462,7 namespace Implab {
479 return Then(success, null, null);
462 return Then(success, null, null);
480 }
463 }
481
464
482 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<IPromise> cancel) {
465 public IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) {
483 var promise = new Promise<IPromise>();
466 var promise = new Promise<IPromise>();
484
467
485 AddHandler(
468 AddHandler(
@@ -493,7 +476,7 namespace Implab {
493
476
494 var medium = new Promise();
477 var medium = new Promise();
495 if (chained != null)
478 if (chained != null)
496 medium.On(Cancel, PromiseEventType.Cancelled);
479 medium.On(null, null, Cancel);
497
480
498 promise.On(
481 promise.On(
499 result => ConnectPromise(result, medium),
482 result => ConnectPromise(result, medium),
@@ -509,9 +492,9 namespace Implab {
509 result.On(
492 result.On(
510 medium.Resolve,
493 medium.Resolve,
511 medium.Reject,
494 medium.Reject,
512 () => medium.Reject(new OperationCanceledException())
495 medium.Cancel
513 );
496 );
514 medium.On(result.Cancel, PromiseEventType.Cancelled);
497 medium.On(null, null, result.Cancel);
515 } else {
498 } else {
516 medium.Reject(
499 medium.Reject(
517 new NullReferenceException(
500 new NullReferenceException(
@@ -530,7 +513,7 namespace Implab {
530 return Chain(chained, null, null);
513 return Chain(chained, null, null);
531 }
514 }
532
515
533 public IPromise On(Action success, Action<Exception> error, Action cancel) {
516 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) {
534 AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance));
517 AddHandler(new EventDescriptor(success,error,cancel, StubDeferred.instance));
535 return this;
518 return this;
536 }
519 }
@@ -550,43 +533,6 namespace Implab {
550 return this;
533 return this;
551 }
534 }
552
535
553 public IPromise Error(Action<Exception> error) {
554 var promise = new Promise();
555 if (error != null)
556 On(
557 (Action<T>)null,
558 ex => {
559 try {
560 error(ex);
561 promise.Resolve();
562 } catch (Exception ex2) {
563 promise.Reject(ex2);
564 }
565 });
566 else
567 Listen(PromiseEventType.Error, promise.Resolve);
568 return promise;
569 }
570
571 public IPromise Cancelled(Action handler) {
572 var promise = new Promise();
573 if (handler != null)
574 On(
575 (Action<T>)null,
576 null,
577 () => {
578 try {
579 handler();
580 promise.Resolve();
581 } catch (Exception ex) {
582 promise.Reject(ex);
583 }
584 });
585 else
586 Listen(PromiseEventType.Cancelled, promise.Resolve);
587 return promise;
588 }
589
590 public IPromise<T2> Cast<T2>() {
536 public IPromise<T2> Cast<T2>() {
591 return (IPromise<T2>)this;
537 return (IPromise<T2>)this;
592 }
538 }
@@ -601,8 +547,8 namespace Implab {
601 handler.Reject(error);
547 handler.Reject(error);
602 }
548 }
603
549
604 protected override void SignalCancelled(IDeferred<T> handler) {
550 protected override void SignalCancelled(IDeferred<T> handler, Exception reason) {
605 handler.Cancel();
551 handler.Cancel(reason);
606 }
552 }
607
553
608 protected override void Listen(PromiseEventType events, Action handler) {
554 protected override void Listen(PromiseEventType events, Action handler) {
@@ -1,7 +1,6
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4
5 [Serializable]
4 [Serializable]
6 public class PromiseTransientException : Exception {
5 public class PromiseTransientException : Exception {
7 /// <summary>
6 /// <summary>
@@ -1,4 +1,5
1 using System.Threading;
1 using System.Threading;
2 using System;
2
3
3 namespace Implab {
4 namespace Implab {
4 public class SyncContextPromise<T> : Promise<T> {
5 public class SyncContextPromise<T> : Promise<T> {
@@ -13,12 +14,12 namespace Implab {
13 m_context.Post(x => base.SignalSuccess(handler), null);
14 m_context.Post(x => base.SignalSuccess(handler), null);
14 }
15 }
15
16
16 protected override void SignalError(IDeferred<T> handler, System.Exception error) {
17 protected override void SignalError(IDeferred<T> handler, Exception error) {
17 m_context.Post(x => base.SignalError(handler, error), null);
18 m_context.Post(x => base.SignalError(handler, error), null);
18 }
19 }
19
20
20 protected override void SignalCancelled(IDeferred<T> handler) {
21 protected override void SignalCancelled(IDeferred<T> handler, Exception reason) {
21 m_context.Post(x => base.SignalCancelled(handler), null);
22 m_context.Post(x => base.SignalCancelled(handler, reason), null);
22 }
23 }
23 }
24 }
24 }
25 }
@@ -99,6 +99,13 namespace Implab
99 }
99 }
100 }
100 }
101
101
102 public void Cancel(Exception reason) {
103 lock (m_lock) {
104 if (!m_cancelled)
105 m_cancelled = true;
106 }
107 }
108
102 protected virtual void OnCancelled() {
109 protected virtual void OnCancelled() {
103 var temp = Cancelled;
110 var temp = Cancelled;
104 if (temp != null) {
111 if (temp != null) {
@@ -69,7 +69,7 namespace MonoPlay {
69
69
70 var readers = new IPromise[readThreads];
70 var readers = new IPromise[readThreads];
71 for (int i = 0; i < readThreads; i++)
71 for (int i = 0; i < readThreads; i++)
72 readers[i] = AsyncPool.RunThread(reader1);
72 readers[i] = AsyncPool.RunThread(reader2);
73
73
74 var writers = new IPromise[writeThreads];
74 var writers = new IPromise[writeThreads];
75 for (int i = 0; i < writeThreads; i++)
75 for (int i = 0; i < writeThreads; i++)
General Comments 0
You need to be logged in to leave comments. Login now