##// END OF EJS Templates
Added awaiters to promises...
cin -
r248:5cb4826c2c2a v3
parent child
Show More
@@ -0,0 +1,18
1 using System;
2 using System.Reflection;
3 using System.Runtime.ExceptionServices;
4
5 namespace Implab {
6 public static class ExceptionHelpers {
7 public static void Rethrow(this Exception that) {
8 ExceptionDispatchInfo.Capture(that).Throw();
9 }
10
11 public static void ThrowInvocationException(this Exception that) {
12 if (that is OperationCanceledException)
13 throw new OperationCanceledException("Operation cancelled", that);
14 else
15 throw new TargetInvocationException(that);
16 }
17 }
18 } No newline at end of file
@@ -0,0 +1,20
1 using System;
2 using System.Threading;
3
4 namespace Implab {
5 public class SyncContextDispatcher : IDispatcher {
6 SynchronizationContext m_context;
7 public SyncContextDispatcher(SynchronizationContext context) {
8 Safe.ArgumentNotNull(context, nameof(context));
9 m_context = context;
10 }
11
12 public void Enqueue(Action job) {
13 m_context.Post((o) => job(), null);
14 }
15
16 public void Enqueue<T>(Action<T> job, T arg) {
17 m_context.Post((o) => job((T)o), arg);
18 }
19 }
20 } No newline at end of file
@@ -0,0 +1,20
1 using System;
2 using System.Threading;
3
4 namespace Implab.Parallels {
5 public class ThreadPoolDispatcher : IDispatcher {
6
7 public static ThreadPoolDispatcher Instance { get; private set; } = new ThreadPoolDispatcher();
8
9 private ThreadPoolDispatcher() {
10 }
11
12 public void Enqueue(Action job) {
13 ThreadPool.QueueUserWorkItem((o) => job(), null);
14 }
15
16 public void Enqueue<T>(Action<T> job, T arg) {
17 ThreadPool.QueueUserWorkItem((o) => job((T)o), arg);
18 }
19 }
20 } No newline at end of file
@@ -0,0 +1,209
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Reflection;
5 using System.Threading.Tasks;
6 using Implab.Parallels;
7
8 namespace Implab {
9 public class Promise : AbstractEvent<IResolvable>, IPromise {
10 public static IDispatcher DefaultDispatcher {
11 get {
12 return ThreadPoolDispatcher.Instance;
13 }
14 }
15
16 class ResolvableSignal : IResolvable {
17 public Signal Signal { get; private set; }
18 public ResolvableSignal() {
19 Signal = new Signal();
20 }
21
22
23 public void Reject(Exception error) {
24 Signal.Set();
25 }
26
27 public void Resolve() {
28 Signal.Set();
29 }
30 }
31
32 PromiseState m_state;
33
34 Exception m_error;
35
36 public bool IsRejected {
37 get {
38 return m_state == PromiseState.Rejected;
39 }
40 }
41
42 public bool IsFulfilled {
43 get {
44 return m_state == PromiseState.Fulfilled;
45 }
46 }
47
48 public Exception RejectReason {
49 get {
50 return m_error;
51 }
52 }
53
54 internal Promise() {
55
56 }
57
58 internal void ResolvePromise() {
59 if (BeginTransit()) {
60 m_state = PromiseState.Fulfilled;
61 CompleteTransit();
62 }
63 }
64
65 internal void RejectPromise(Exception reason) {
66 if (BeginTransit()) {
67 m_error = reason;
68 m_state = PromiseState.Rejected;
69 CompleteTransit();
70 }
71 }
72
73
74 #region implemented abstract members of AbstractPromise
75
76 protected override void SignalHandler(IResolvable handler) {
77 switch (m_state) {
78 case PromiseState.Fulfilled:
79 handler.Resolve();
80 break;
81 case PromiseState.Rejected:
82 handler.Reject(RejectReason);
83 break;
84 default:
85 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
86 }
87 }
88
89 protected void WaitResult(int timeout) {
90 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
91 throw new TimeoutException();
92 }
93
94 protected Signal GetFulfillSignal() {
95 var next = new ResolvableSignal();
96 Then(next);
97 return next.Signal;
98 }
99
100 #endregion
101
102
103 public Type ResultType {
104 get {
105 return typeof(void);
106 }
107 }
108
109
110 protected void Rethrow() {
111 Debug.Assert(m_error != null);
112 if (m_error is OperationCanceledException)
113 throw new OperationCanceledException("Operation cancelled", m_error);
114 else
115 throw new TargetInvocationException(m_error);
116 }
117
118 public void Then(IResolvable next) {
119 AddHandler(next);
120 }
121
122 public IPromise<T> Cast<T>() {
123 throw new InvalidCastException();
124 }
125
126 public void Join() {
127 WaitResult(-1);
128 if (IsRejected)
129 Rethrow();
130 }
131
132 public void Join(int timeout) {
133 WaitResult(timeout);
134 if (IsRejected)
135 Rethrow();
136 }
137
138 public static ResolvedPromise Resolve() {
139 return new ResolvedPromise();
140 }
141
142 public static ResolvedPromise<T> Resolve<T>(T result) {
143 return new ResolvedPromise<T>(result);
144 }
145
146 public static RejectedPromise Reject(Exception reason) {
147 return new RejectedPromise(reason);
148 }
149
150 public static RejectedPromise<T> Reject<T>(Exception reason) {
151 return new RejectedPromise<T>(reason);
152 }
153
154 public static IPromise Create(PromiseExecutor executor) {
155 Safe.ArgumentNotNull(executor, nameof(executor));
156
157 var p = new Promise();
158 var d = new Deferred(p, DefaultDispatcher);
159
160 try {
161 executor(d);
162 } catch (Exception e) {
163 d.Reject(e);
164 }
165
166 return d.Promise;
167 }
168
169 public static IPromise<T> Create<T>(PromiseExecutor<T> executor) {
170 Safe.ArgumentNotNull(executor, nameof(executor));
171
172 var p = new Promise<T>();
173 var d = new Deferred<T>(p, DefaultDispatcher);
174
175 try {
176 executor(d);
177 } catch (Exception e) {
178 d.Reject(e);
179 }
180
181 return d.Promise;
182 }
183
184 public static IPromise All(IEnumerable<IPromise> promises) {
185 var d = new Deferred(DefaultDispatcher);
186 var all = new PromiseAll(d);
187 foreach (var promise in promises) {
188 all.AddPromise(promise);
189 if (all.Done)
190 break;
191 }
192 all.Complete();
193 return all.ResultPromise;
194 }
195
196 public static IPromise<T[]> All<T>(IEnumerable<IPromise<T>> promises, Func<T, IPromise> cleanup, Action cancel) {
197 var d = new Deferred<T[]>(DefaultDispatcher);
198 var all = new PromiseAll<T>(d, cleanup, cancel);
199 foreach (var promise in promises) {
200 all.AddPromise(promise);
201 if (all.Done)
202 break;
203 }
204 all.Complete();
205 return all.ResultPromise;
206 }
207 }
208 }
209
@@ -0,0 +1,40
1 using System;
2 using System.Threading;
3
4 namespace Implab
5 {
6 class PromiseAll : IResolvable {
7 int m_count;
8
9 readonly Deferred m_deferred;
10
11 public bool Done {
12 get { return m_deferred.Promise.IsResolved; }
13 }
14
15 public IPromise ResultPromise {
16 get { return m_deferred.Promise; }
17 }
18
19 public void AddPromise(IPromise promise) {
20 Interlocked.Increment(ref m_count);
21 }
22
23 public PromiseAll(Deferred deferred) {
24 m_deferred = deferred;
25 }
26
27 public void Resolve() {
28 if (Interlocked.Decrement(ref m_count) == 0)
29 m_deferred.Resolve();
30 }
31
32 public void Complete() {
33 Resolve();
34 }
35
36 public void Reject(Exception error) {
37 m_deferred.Reject(error);
38 }
39 }
40 } No newline at end of file
@@ -0,0 +1,90
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Threading;
5
6 namespace Implab {
7 class PromiseAll<T> : IResolvable {
8
9 int m_count;
10
11 readonly List<IPromise<T>> m_promises = new List<IPromise<T>>();
12
13 readonly Deferred<T[]> m_deferred;
14
15 IPromise<T[]> m_result;
16
17 readonly Func<T, IPromise> m_cleanup;
18
19 readonly Action m_cancel;
20
21 public bool Done {
22 get { return m_deferred.Promise.IsResolved && m_cleanup == null; }
23 }
24
25 public IPromise<T[]> ResultPromise {
26 get { return m_result; }
27 }
28
29 public void AddPromise(IPromise<T> promise) {
30 Interlocked.Increment(ref m_count);
31 promise.Then(this);
32 }
33
34 public PromiseAll(Deferred<T[]> deferred, Func<T, IPromise> cleanup, Action cancel) {
35 m_deferred = deferred;
36 m_cancel = cancel;
37 m_cleanup = cleanup;
38 }
39
40 public void Resolve() {
41 if (Interlocked.Decrement(ref m_count) == 0)
42 m_deferred.Resolve(GetResults());
43 }
44
45 public void Reject(Exception error) {
46 m_deferred.Reject(error);
47 }
48
49 public void Complete() {
50 if (m_cancel != null || m_cleanup != null)
51 m_result = m_deferred.Promise.Catch(CleanupResults);
52 else
53 m_result = m_deferred.Promise;
54 }
55
56 IPromise<T[]> CleanupResults(Exception reason) {
57 var errors = new List<Exception>();
58 errors.Add(reason);
59
60 if (m_cancel != null)
61 try {
62 m_cancel();
63 } catch (Exception e) {
64 errors.Add(e);
65 }
66
67 if (m_cleanup != null) {
68 return Promise.All(
69 m_promises.Select(p => p
70 .Then(m_cleanup, e => { })
71 .Catch(e => {
72 errors.Add(e);
73 })
74 )
75 ).Then<T[]>(new Func<T[]>(() => {
76 throw new AggregateException(errors);
77 }), (Func<Exception, T[]>)null);
78 } else {
79 return Promise.Reject<T[]>(errors.Count > 1 ? new AggregateException(errors) : reason);
80 }
81 }
82
83 T[] GetResults() {
84 var results = new T[m_promises.Count];
85 for (var i = 0; i < results.Length; i++)
86 results[i] = m_promises[i].Join();
87 return results;
88 }
89 }
90 } No newline at end of file
@@ -0,0 +1,62
1 using System;
2 using System.Runtime.CompilerServices;
3 using System.Threading;
4 using Implab.Parallels;
5
6 namespace Implab
7 {
8 public struct PromiseAwaiter : INotifyCompletion {
9 class PromiseEvent : IResolvable {
10 IDispatcher m_dispatcher;
11
12 Action m_handler;
13
14 public PromiseEvent(Action handler, IDispatcher dispatcher) {
15 m_handler = handler;
16 m_dispatcher = dispatcher;
17 }
18
19 public void Resolve() {
20 m_dispatcher.Enqueue(m_handler);
21 }
22
23 public void Reject(Exception error) {
24 m_dispatcher.Enqueue(m_handler);
25 }
26 }
27
28 readonly IPromise m_promise;
29 readonly IDispatcher m_dispatcher;
30
31 public PromiseAwaiter(IPromise promise, IDispatcher dispatcher) {
32 m_promise = promise;
33 m_dispatcher = dispatcher;
34 }
35
36 public PromiseAwaiter(IPromise promise) {
37 m_promise = promise;
38 m_dispatcher = GetDispatcher();
39 }
40
41 public void OnCompleted (Action continuation) {
42 if (m_promise != null)
43 m_promise.Then(new PromiseEvent(continuation, GetDispatcher()));
44 }
45
46 public void GetResult() {
47 m_promise.Join();
48 }
49
50 static IDispatcher GetDispatcher() {
51 if(SynchronizationContext.Current == null)
52 return ThreadPoolDispatcher.Instance;
53 return new SyncContextDispatcher(SynchronizationContext.Current);
54 }
55
56 public bool IsCompleted {
57 get {
58 return m_promise.IsResolved;
59 }
60 }
61 }
62 } No newline at end of file
@@ -0,0 +1,62
1 using System;
2 using System.Runtime.CompilerServices;
3 using System.Threading;
4 using Implab.Parallels;
5
6 namespace Implab {
7 public struct PromiseAwaiter<T> : INotifyCompletion {
8 class PromiseEvent : IResolvable<T> {
9 IDispatcher m_dispatcher;
10
11 Action m_handler;
12
13 public PromiseEvent(Action handler, IDispatcher dispatcher) {
14 m_handler = handler;
15 m_dispatcher = dispatcher;
16 }
17
18 public void Resolve(T result) {
19 m_dispatcher.Enqueue(m_handler);
20 }
21
22 public void Reject(Exception error) {
23 m_dispatcher.Enqueue(m_handler);
24 }
25 }
26
27 readonly IPromise<T> m_promise;
28
29 readonly IDispatcher m_dispatcher;
30
31 public PromiseAwaiter(IPromise<T> promise) {
32 m_promise = promise;
33 m_dispatcher = GetDispatcher();
34 }
35
36 public PromiseAwaiter(IPromise<T> promise, IDispatcher dispatcher) {
37 m_promise = promise;
38 m_dispatcher = dispatcher;
39 }
40
41 public void OnCompleted(Action continuation) {
42 if (m_promise != null)
43 m_promise.Then(new PromiseEvent(continuation, GetDispatcher()));
44 }
45
46 public T GetResult() {
47 return m_promise.Join();
48 }
49
50 static IDispatcher GetDispatcher() {
51 if (SynchronizationContext.Current == null)
52 return ThreadPoolDispatcher.Instance;
53 return new SyncContextDispatcher(SynchronizationContext.Current);
54 }
55
56 public bool IsCompleted {
57 get {
58 return m_promise.IsResolved;
59 }
60 }
61 }
62 } No newline at end of file
@@ -0,0 +1,3
1 namespace Implab {
2 public delegate void PromiseExecutor(Deferred deferred);
3 } No newline at end of file
@@ -0,0 +1,3
1 namespace Implab {
2 public delegate void PromiseExecutor<T>(Deferred<T> d);
3 } No newline at end of file
@@ -0,0 +1,56
1 using System;
2 using System.Diagnostics;
3
4 namespace Implab {
5 class PromiseFuncReaction<TIn, TRet> : PromiseReaction<TIn> {
6 readonly Deferred<TRet> m_next;
7
8 public IPromise<TRet> Promise {
9 get { return m_next.Promise; }
10 }
11
12 public PromiseFuncReaction(Func<TIn, TRet> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) : base(dispatcher) {
13 m_next = new Deferred<TRet>(dispatcher);
14 if (fulfilled != null)
15 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
16
17 if (rejected != null)
18 RejectHandler = PromiseHandler.Create(rejected, m_next);
19 }
20
21 public PromiseFuncReaction(Func<TIn, IPromise<TRet>> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) : base(dispatcher) {
22 m_next = new Deferred<TRet>(dispatcher);
23 if (fulfilled != null)
24 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
25
26 if (rejected != null)
27 RejectHandler = PromiseHandler.Create(rejected, m_next);
28 }
29
30 public PromiseFuncReaction(Func<TIn, TRet> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) : base(dispatcher) {
31 m_next = new Deferred<TRet>(dispatcher);
32 if (fulfilled != null)
33 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
34
35 if (rejected != null)
36 RejectHandler = PromiseHandler.Create(rejected, m_next);
37 }
38
39 public PromiseFuncReaction(Func<TIn, IPromise<TRet>> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) : base(dispatcher) {
40 m_next = new Deferred<TRet>(dispatcher);
41 if (fulfilled != null)
42 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
43
44 if (rejected != null)
45 RejectHandler = PromiseHandler.Create(rejected, m_next);
46 }
47
48 protected override void DefaultReject(Exception reason) {
49 m_next.Reject(reason);
50 }
51
52 protected override void DefaultResolve(TIn result) {
53 m_next.Resolve((TRet)(object)result);
54 }
55 }
56 } No newline at end of file
@@ -0,0 +1,102
1 using System;
2 using System.Diagnostics;
3
4 namespace Implab {
5 class PromiseHandler {
6 public static Action<T> Create<T>(Action<T> handler, Deferred next) {
7 Debug.Assert(handler != null);
8
9 return (v) => {
10 try {
11 handler(v);
12 next.Resolve();
13 } catch (Exception err) {
14 next.Reject(err);
15 }
16 };
17 }
18
19 public static Action<T> Create<T>(Func<T, IPromise> handler, Deferred next) {
20 Debug.Assert(handler != null);
21
22 return (v) => {
23 try {
24 next.Resolve(handler(v));
25 } catch (Exception err) {
26 next.Reject(err);
27 }
28 };
29 }
30
31 public static Action<T> Create<T, T2>(Func<T, T2> handler, Deferred<T2> next) {
32 Debug.Assert(handler != null);
33
34 return (v) => {
35 try {
36 next.Resolve(handler(v));
37 } catch (Exception err) {
38 next.Reject(err);
39 }
40 };
41 }
42
43 public static Action<T> Create<T, T2>(Func<T, IPromise<T2>> handler, Deferred<T2> next) {
44 Debug.Assert(handler != null);
45 return (v) => {
46 try {
47 next.Resolve(handler(v));
48 } catch (Exception err) {
49 next.Reject(err);
50 }
51 };
52 }
53
54 public static Action Create(Action handler, Deferred next) {
55 Debug.Assert(handler != null);
56
57 return () => {
58 try {
59 handler();
60 next.Resolve();
61 } catch (Exception err) {
62 next.Reject(err);
63 }
64 };
65 }
66
67 public static Action Create(Func<IPromise> handler, Deferred next) {
68 Debug.Assert(handler != null);
69
70 return () => {
71 try {
72 next.Resolve(handler());
73 } catch (Exception err) {
74 next.Reject(err);
75 }
76 };
77 }
78
79 public static Action Create<T2>(Func<T2> handler, Deferred<T2> next) {
80 Debug.Assert(handler != null);
81
82 return () => {
83 try {
84 next.Resolve(handler());
85 } catch (Exception err) {
86 next.Reject(err);
87 }
88 };
89 }
90
91 public static Action Create<T2>(Func<IPromise<T2>> handler, Deferred<T2> next) {
92 Debug.Assert(handler != null);
93 return () => {
94 try {
95 next.Resolve(handler());
96 } catch (Exception err) {
97 next.Reject(err);
98 }
99 };
100 }
101 }
102 } No newline at end of file
@@ -0,0 +1,159
1 using System;
2 using System.Diagnostics;
3 using System.Reflection;
4 using Implab.Parallels;
5
6 namespace Implab {
7 public class Promise<T> : AbstractEvent<IResolvable<T>>, IPromise<T> {
8
9 class ResolvableSignal : IResolvable<T> {
10 public Signal Signal { get; private set; }
11 public ResolvableSignal() {
12 Signal = new Signal();
13 }
14
15
16 public void Reject(Exception error) {
17 Signal.Set();
18 }
19
20 public void Resolve(T result) {
21 Signal.Set();
22 }
23 }
24
25 class ResolvableWrapper : IResolvable<T> {
26 readonly IResolvable m_resolvable;
27 public ResolvableWrapper(IResolvable resolvable) {
28 m_resolvable = resolvable;
29 }
30
31 public void Reject(Exception reason) {
32 m_resolvable.Reject(reason);
33 }
34
35 public void Resolve(T value) {
36 m_resolvable.Resolve();
37 }
38 }
39
40 PromiseState m_state;
41
42 T m_result;
43
44 Exception m_error;
45
46 public bool IsRejected {
47 get {
48 return m_state == PromiseState.Rejected;
49 }
50 }
51
52 public bool IsFulfilled {
53 get {
54 return m_state == PromiseState.Fulfilled;
55 }
56 }
57
58 public Exception RejectReason {
59 get {
60 return m_error;
61 }
62 }
63
64
65 internal void ResolvePromise(T result) {
66 if (BeginTransit()) {
67 m_result = result;
68 m_state = PromiseState.Fulfilled;
69 CompleteTransit();
70 }
71 }
72
73 internal void RejectPromise(Exception reason) {
74 if (BeginTransit()) {
75 m_error = reason;
76 m_state = PromiseState.Rejected;
77 CompleteTransit();
78 }
79 }
80
81
82 #region implemented abstract members of AbstractPromise
83
84 protected override void SignalHandler(IResolvable<T> handler) {
85 switch (m_state) {
86 case PromiseState.Fulfilled:
87 handler.Resolve(m_result);
88 break;
89 case PromiseState.Rejected:
90 handler.Reject(RejectReason);
91 break;
92 default:
93 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
94 }
95 }
96
97 protected void WaitResult(int timeout) {
98 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
99 throw new TimeoutException();
100 }
101
102 protected Signal GetFulfillSignal() {
103 var next = new ResolvableSignal();
104 Then(next);
105 return next.Signal;
106 }
107
108 #endregion
109
110 public Type ResultType {
111 get {
112 return typeof(void);
113 }
114 }
115
116
117 protected void Rethrow() {
118 if (m_error is OperationCanceledException)
119 throw new OperationCanceledException("Operation cancelled", m_error);
120 else
121 throw new TargetInvocationException(m_error);
122 }
123
124 public void Then(IResolvable<T> next) {
125 AddHandler(next);
126 }
127
128 public void Then(IResolvable next) {
129 AddHandler(new ResolvableWrapper(next));
130 }
131
132 public IPromise<T2> Cast<T2>() {
133 return (IPromise<T2>)this;
134 }
135
136 void IPromise.Join() {
137 Join();
138 }
139
140 void IPromise.Join(int timeout) {
141 Join(timeout);
142 }
143
144 public T Join() {
145 WaitResult(-1);
146 if (IsRejected)
147 Rethrow();
148 return m_result;
149 }
150
151 public T Join(int timeout) {
152 WaitResult(timeout);
153 if (IsRejected)
154 Rethrow();
155 return m_result;
156 }
157 }
158 }
159
@@ -0,0 +1,38
1 using System;
2
3 namespace Implab
4 {
5 public struct RejectedPromise : IPromise {
6 readonly Exception m_reason;
7
8 public Type ResultType => typeof(void);
9
10 public bool IsResolved => true;
11
12 public bool IsRejected => true;
13
14 public bool IsFulfilled => false;
15
16 public Exception RejectReason => m_reason;
17
18 public RejectedPromise(Exception reason) {
19 m_reason = reason;
20 }
21
22 public IPromise<T> Cast<T>() {
23 throw new InvalidCastException();
24 }
25
26 public void Join() {
27 m_reason.ThrowInvocationException();
28 }
29
30 public void Join(int timeout) {
31 m_reason.ThrowInvocationException();
32 }
33
34 public void Then(IResolvable next) {
35 next.Reject(m_reason);
36 }
37 }
38 } No newline at end of file
@@ -0,0 +1,52
1 using System;
2
3 namespace Implab
4 {
5 public struct RejectedPromise<T> : IPromise<T> {
6 readonly Exception m_reason;
7
8 public Type ResultType => typeof(void);
9
10 public bool IsResolved => true;
11
12 public bool IsRejected => true;
13
14 public bool IsFulfilled => false;
15
16 public Exception RejectReason => m_reason;
17
18 public RejectedPromise(Exception reason) {
19 m_reason = reason;
20 }
21
22 public IPromise<T2> Cast<T2>() {
23 return (IPromise<T2>)(IPromise<T>)this;
24 }
25
26 void IPromise.Join() {
27 m_reason.ThrowInvocationException();
28 }
29
30 void IPromise.Join(int timeout) {
31 m_reason.ThrowInvocationException();
32 }
33
34 public T Join() {
35 m_reason.ThrowInvocationException();
36 throw new Exception(); // unreachable code
37 }
38
39 public T Join(int timeout) {
40 m_reason.ThrowInvocationException();
41 throw new Exception(); // unreachable code
42 }
43
44 public void Then(IResolvable next) {
45 next.Reject(m_reason);
46 }
47
48 public void Then(IResolvable<T> next) {
49 next.Reject(m_reason);
50 }
51 }
52 } No newline at end of file
@@ -0,0 +1,30
1 using System;
2
3 namespace Implab
4 {
5 public struct ResolvedPromise : IPromise {
6 public Type ResultType => typeof(void);
7
8 public bool IsResolved => true;
9
10 public bool IsRejected => false;
11
12 public bool IsFulfilled => true;
13
14 public Exception RejectReason => null;
15
16 public IPromise<T> Cast<T>() {
17 throw new InvalidCastException();
18 }
19
20 public void Join() {
21 }
22
23 public void Join(int timeout) {
24 }
25
26 public void Then(IResolvable next) {
27 next.Resolve();
28 }
29 }
30 } No newline at end of file
@@ -0,0 +1,47
1 using System;
2
3 namespace Implab {
4 public struct ResolvedPromise<T> : IPromise<T> {
5 T m_result;
6
7 public Type ResultType => typeof(T);
8
9 public bool IsResolved => true;
10
11 public bool IsRejected => false;
12
13 public bool IsFulfilled => true;
14
15 public Exception RejectReason => null;
16
17 public ResolvedPromise(T result) {
18 m_result = result;
19 }
20
21 public IPromise<T2> Cast<T2>() {
22 return (IPromise<T2>)(IPromise<T>)this;
23 }
24
25 void IPromise.Join() {
26 }
27
28 void IPromise.Join(int timeout) {
29 }
30
31 public T Join() {
32 return m_result;
33 }
34
35 public T Join(int timeout) {
36 return m_result;
37 }
38
39 public void Then(IResolvable<T> next) {
40 next.Resolve(m_result);
41 }
42
43 public void Then(IResolvable next) {
44 next.Resolve();
45 }
46 }
47 } No newline at end of file
@@ -1,141 +1,130
1 using System;
1 using System;
2 using Implab.Parallels;
2 using Implab.Parallels;
3 using System.Threading;
3 using System.Threading;
4 using System.Reflection;
4 using System.Reflection;
5 using System.Diagnostics;
5 using System.Diagnostics;
6
6
7 namespace Implab {
7 namespace Implab {
8 /// <summary>
8 /// <summary>
9 /// Abstract class for creation of custom one-shot thread safe events.
9 /// Abstract class for creation of custom one-shot thread safe events.
10 /// </summary>
10 /// </summary>
11 /// <remarks>
11 /// <remarks>
12 /// <para>
12 /// <para>
13 /// An event is something that should happen in the future and the
13 /// An event is something that should happen in the future and the
14 /// triggering of the event causes execution of some pending actions
14 /// triggering of the event causes execution of some pending actions
15 /// which are formely event handlers. One-shot events occur only once
15 /// which are formely event handlers. One-shot events occur only once
16 /// and any handler added after the event is triggered should run
16 /// and any handler added after the event is triggered should run
17 /// without a delay.
17 /// without a delay.
18 /// </para>
18 /// </para>
19 /// <para>
19 /// <para>
20 /// The lifecycle of the one-shot event is tipically consists of following
20 /// The lifecycle of the one-shot event is tipically consists of following
21 /// phases.
21 /// phases.
22 /// <list>
22 /// <list>
23 /// <description>Pending state. This is the initial state of the event. Any
23 /// <description>Pending state. This is the initial state of the event. Any
24 /// handler added to the event will be queued for the future execution.
24 /// handler added to the event will be queued for the future execution.
25 /// </description>
25 /// </description>
26 /// <description>Transitional state. This is intermediate state between pending
26 /// <description>Transitional state. This is intermediate state between pending
27 /// and fulfilled states, during this state internal initialization and storing
27 /// and fulfilled states, during this state internal initialization and storing
28 /// of the result occurs.
28 /// of the result occurs.
29 /// </description>
29 /// </description>
30 /// <description>Fulfilled state. The event contains the result, all queued
30 /// <description>Fulfilled state. The event contains the result, all queued
31 /// handlers are signalled to run and newly added handlers are executed
31 /// handlers are signalled to run and newly added handlers are executed
32 /// immediatelly.
32 /// immediatelly.
33 /// </description>
33 /// </description>
34 /// </list>
34 /// </list>
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 PendingState = 0;
38 const int PendingState = 0;
39
39
40 const int TransitionalState = 1;
40 const int TransitionalState = 1;
41
41
42 const int ResolvedState = 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 IsResolved {
49 public bool IsResolved {
50 get {
50 get {
51 return m_state > TransitionalState;
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 PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
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 (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
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;
66 #endif
66 #endif
67 Signal();
67 Signal();
68 }
68 }
69
69
70 protected void WaitTransition() {
70 protected void WaitTransition() {
71 if (m_state == TransitionalState) {
71 if (m_state == TransitionalState) {
72 SpinWait spin;
72 SpinWait spin = new SpinWait();
73 do {
73 do {
74 spin.SpinOnce();
74 spin.SpinOnce();
75 } while (m_state == TransitionalState);
75 } while (m_state == TransitionalState);
76 }
76 }
77 }
77 }
78
78
79
79
80 protected abstract void SignalHandler(THandler handler);
80 protected abstract void SignalHandler(THandler handler);
81
81
82 void Signal() {
82 void Signal() {
83 THandler handler;
83 THandler handler;
84 while (TryDequeueHandler(out handler))
84 while (TryDequeueHandler(out handler))
85 SignalHandler(handler);
85 SignalHandler(handler);
86 }
86 }
87
87
88 #endregion
88 #endregion
89
89
90 protected abstract Signal GetFulfillSignal();
91
92 #region synchronization traits
93 protected void WaitResult(int timeout) {
94 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
95 throw new TimeoutException();
96 }
97
98
99 #endregion
100
101 #region handlers managment
90 #region handlers managment
102
91
103 protected void AddHandler(THandler handler) {
92 protected void AddHandler(THandler handler) {
104
93
105 if (IsResolved) {
94 if (IsResolved) {
106 // the promise is in the resolved state, just invoke the handler
95 // the promise is in the resolved state, just invoke the handler
107 SignalHandler(handler);
96 SignalHandler(handler);
108 } else {
97 } else {
109 EnqueueHandler(handler);
98 EnqueueHandler(handler);
110
99
111 if (IsResolved && TryDequeueHandler(out handler))
100 if (IsResolved && TryDequeueHandler(out handler))
112 // if the promise have been resolved while we was adding the handler to the queue
101 // 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
102 // we can't guarantee that someone is still processing it
114 // therefore we need to fetch a handler from the queue and execute it
103 // therefore we need to fetch a handler from the queue and execute it
115 // note that fetched handler may be not the one that we have added
104 // note that fetched handler may be not the one that we have added
116 // even we can fetch no handlers at all :)
105 // even we can fetch no handlers at all :)
117 SignalHandler(handler);
106 SignalHandler(handler);
118 }
107 }
119
108
120 }
109 }
121
110
122 void EnqueueHandler(THandler handler) {
111 void EnqueueHandler(THandler handler) {
123 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
112 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
124 if (m_extraHandlers == null)
113 if (m_extraHandlers == null)
125 // compare-exchange will protect from loosing already created queue
114 // compare-exchange will protect from loosing already created queue
126 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
115 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
127 m_extraHandlers.Enqueue(handler);
116 m_extraHandlers.Enqueue(handler);
128 }
117 }
129 }
118 }
130
119
131 bool TryDequeueHandler(out THandler handler) {
120 bool TryDequeueHandler(out THandler handler) {
132 handler = Interlocked.Exchange(ref m_handler, null);
121 handler = Interlocked.Exchange(ref m_handler, null);
133 if (handler != null)
122 if (handler != null)
134 return true;
123 return true;
135 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
124 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
136 }
125 }
137
126
138 #endregion
127 #endregion
139 }
128 }
140 }
129 }
141
130
@@ -1,65 +1,28
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3 using Implab.Parallels;
3 using Implab.Parallels;
4
4
5 namespace Implab {
5 namespace Implab {
6 public class CancellationToken : ICancellationToken {
6 /// <summary>
7 const int CANCEL_NOT_REQUESTED = 0;
7 /// The cancellation token signals to the worker that cancellation has been
8 const int CANCEL_REQUESTING = 1;
8 /// requested, after the signal is received the worker decides wheather to
9 const int CANCEL_REQUESTED = 2;
9 /// cancel its work or to continue.
10
10 /// </summary>
11 volatile int m_state = CANCEL_NOT_REQUESTED;
11 public class CancellationToken : AbstractEvent<Action<Exception>> {
12
12 public CancellationToken() {
13 Action<Exception> m_handler;
13
14
15 Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers;
16
17 public bool IsCancellationRequested {
18 get { return m_state == CANCEL_REQUESTED; }
19 }
14 }
20
15
21 public Exception CancellationReason {
16 public void RequestCancellation() {
22 get; set;
23 }
24
17
25 public void CancellationRequested(Action<Exception> handler) {
26 Safe.ArgumentNotNull(handler, nameof(handler));
27 if (IsCancellationRequested) {
28 handler(CancellationReason);
29 } else {
30 EnqueueHandler(handler);
31 if (IsCancellationRequested && TryDequeueHandler(out handler))
32 handler(CancellationReason);
33 }
34 }
18 }
35
19
36 bool TryDequeueHandler(out Action<Exception> handler) {
20 public void RequestCancellation(Exception reason) {
37 handler = Interlocked.Exchange(ref m_handler, null);
38 if (handler != null)
39 return true;
40 else if (m_handlers != null)
41 return m_handlers.TryDequeue(out handler);
42 else
43 return false;
44 }
45
21
46 void EnqueueHandler(Action<Exception> handler) {
47 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
48 if (m_handlers == null)
49 // compare-exchange will fprotect from loosing already created queue
50 Interlocked.CompareExchange(ref m_handlers, new SimpleAsyncQueue<Action<Exception>>(), null);
51 m_handlers.Enqueue(handler);
52 }
53 }
54
55 void RequestCancellation(Exception reason) {
56 if (Interlocked.CompareExchange(ref m_state, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED) == CANCEL_NOT_REQUESTED) {
57 if (reason == null)
58 reason = new OperationCanceledException();
59 CancellationReason = reason;
60 m_state = CANCEL_REQUESTED;
61 }
62 }
22 }
63
23
24 protected override void SignalHandler(Action<Exception> handler) {
25 throw new NotImplementedException();
26 }
64 }
27 }
65 } No newline at end of file
28 }
@@ -1,52 +1,58
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3
3
4 namespace Implab {
4 namespace Implab {
5 /// <summary>
5 /// <summary>
6 /// This class is responsible for the promise resolution, dispatching and chaining
6 /// This class is responsible for the promise resolution, dispatching and chaining
7 /// </summary>
7 /// </summary>
8 public class Deferred : IResolvable {
8 public class Deferred : IResolvable {
9
9
10 readonly AbstractPromise m_promise;
10 readonly Promise m_promise;
11 readonly IDispatcher m_dispatcher;
11 readonly IDispatcher m_dispatcher;
12
12
13 internal Deferred(AbstractPromise promise, IDispatcher dispatcher) {
13 internal Deferred(IDispatcher dispatcher) : this(new Promise(), dispatcher) {
14 }
15
16 internal Deferred(Promise promise, IDispatcher dispatcher) {
14 Debug.Assert(promise != null);
17 Debug.Assert(promise != null);
15 m_promise = promise;
18 m_promise = promise;
16 m_dispatcher = dispatcher;
19 m_dispatcher = dispatcher;
17 }
20 }
18
21
19 public IPromise Promise {
22 public IPromise Promise {
20 get { return m_promise; }
23 get { return m_promise; }
21 }
24 }
22
25
23 public void Reject(Exception error) {
26 public void Reject(Exception error) {
24 m_promise.Reject(error);
27 if (error is PromiseTransientException)
28 error = ((PromiseTransientException)error).InnerException;
29
30 m_promise.RejectPromise(error);
25 }
31 }
26
32
27 public void Resolve() {
33 public void Resolve() {
28 m_promise.Resolve();
34 m_promise.ResolvePromise();
29 }
35 }
30
36
31 public void Resolve(IPromise thenable) {
37 public void Resolve(IPromise thenable) {
32 if (thenable == null)
38 if (thenable == null)
33 Reject(new Exception("The promise or task are expected"));
39 Reject(new Exception("The promise or task are expected"));
34 if (thenable == m_promise)
40 if (thenable == m_promise)
35 Reject(new Exception("The promise cannot be resolved with oneself"));
41 Reject(new Exception("The promise cannot be resolved with oneself"));
36
42
37 else if (m_dispatcher != null)
43 else if (m_dispatcher != null)
38 // dispatch (see ecma-262/6.0: 25.4.1.3.2 Promise Resolve Functions)
44 // dispatch (see ecma-262/6.0: 25.4.1.3.2 Promise Resolve Functions)
39 m_dispatcher.Enqueue(() => Chain(thenable));
45 m_dispatcher.Enqueue(Chain, thenable);
40 else
46 else
41 Chain(thenable);
47 Chain(thenable);
42 }
48 }
43
49
44 void Chain(IPromise thenable) {
50 void Chain(IPromise thenable) {
45 try {
51 try {
46 thenable.Then(this);
52 thenable.Then(this);
47 } catch (Exception err) {
53 } catch (Exception err) {
48 Reject(err);
54 Reject(err);
49 }
55 }
50 }
56 }
51 }
57 }
52 } No newline at end of file
58 }
@@ -1,48 +1,54
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3
3
4 namespace Implab {
4 namespace Implab {
5 public class Deferred<T> : IResolvable<T> {
5 public class Deferred<T> : IResolvable<T> {
6 readonly AbstractPromise<T> m_promise;
6 readonly Promise<T> m_promise;
7 readonly IDispatcher m_dispatcher;
7 readonly IDispatcher m_dispatcher;
8
8
9 internal Deferred(AbstractPromise<T> promise, IDispatcher dispatcher) {
9 internal Deferred(IDispatcher dispatcher) : this(new Promise<T>(), dispatcher) {
10 }
11
12 internal Deferred(Promise<T> promise, IDispatcher dispatcher) {
10 Debug.Assert(promise != null);
13 Debug.Assert(promise != null);
11 m_promise = promise;
14 m_promise = promise;
12 m_dispatcher = dispatcher;
15 m_dispatcher = dispatcher;
13 }
16 }
14
17
15 public IPromise<T> Promise {
18 public IPromise<T> Promise {
16 get { return m_promise; }
19 get { return m_promise; }
17 }
20 }
18
21
19 public void Reject(Exception error) {
22 public void Reject(Exception error) {
20 m_promise.Reject(error);
23 if (error is PromiseTransientException)
24 error = ((PromiseTransientException)error).InnerException;
25
26 m_promise.RejectPromise(error);
21 }
27 }
22
28
23 public void Resolve(T value) {
29 public void Resolve(T value) {
24 m_promise.Resolve(value);
30 m_promise.ResolvePromise(value);
25 }
31 }
26
32
27 public void Resolve(IPromise<T> thenable) {
33 public void Resolve(IPromise<T> thenable) {
28 if (thenable == null)
34 if (thenable == null)
29 Reject(new Exception("The promise or task are expected"));
35 Reject(new Exception("The promise or task are expected"));
30 if (thenable == m_promise)
36 if (thenable == m_promise)
31 Reject(new Exception("The promise cannot be resolved with oneself"));
37 Reject(new Exception("The promise cannot be resolved with oneself"));
32
38
33 else if (m_dispatcher != null)
39 else if (m_dispatcher != null)
34 // dispatch (see ecma-262/6.0: 25.4.1.3.2 Promise Resolve Functions)
40 // dispatch (see ecma-262/6.0: 25.4.1.3.2 Promise Resolve Functions)
35 m_dispatcher.Enqueue(() => Chain(thenable));
41 m_dispatcher.Enqueue(Chain, thenable);
36 else
42 else
37 Chain(thenable);
43 Chain(thenable);
38 }
44 }
39
45
40 void Chain(IPromise<T> thenable) {
46 void Chain(IPromise<T> thenable) {
41 try {
47 try {
42 thenable.Then(this);
48 thenable.Then(this);
43 } catch (Exception err) {
49 } catch (Exception err) {
44 Reject(err);
50 Reject(err);
45 }
51 }
46 }
52 }
47 }
53 }
48 } No newline at end of file
54 }
@@ -1,7 +1,9
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public interface IDispatcher {
4 public interface IDispatcher {
5 void Enqueue(Action job);
5 void Enqueue(Action job);
6
7 void Enqueue<T>(Action<T> job, T arg);
6 }
8 }
7 } No newline at end of file
9 }
@@ -1,88 +1,57
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3
3
4 namespace Implab {
4 namespace Implab {
5 class PromiseActionReaction : PromiseReaction {
5 class PromiseActionReaction : PromiseReaction {
6 readonly Action m_fulfilled;
7
8 readonly Action<Exception> m_rejected;
9
6
10 readonly Deferred m_next;
7 readonly Deferred m_next;
11
8
12 public PromiseActionReaction(Action fulfilled, Action<Exception> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
9 public IPromise Promise {
10 get { return m_next.Promise; }
11 }
12
13 public PromiseActionReaction(Action fulfilled, Action<Exception> rejected, IDispatcher dispatcher) : base(dispatcher) {
14 m_next = new Deferred(dispatcher);
13 if (fulfilled != null)
15 if (fulfilled != null)
14 m_fulfilled = () => {
16 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
15 fulfilled();
16 next.Resolve();
17 };
18
17
19 if (rejected != null)
18 if (rejected != null)
20 m_rejected = (x) => {
19 RejectHandler = PromiseHandler.Create(rejected, m_next);
21 rejected(x);
22 next.Resolve();
23 };
24 m_next = next;
25 }
26
27 public PromiseActionReaction(Func<IPromise> fulfilled, Func<Exception, IPromise> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
28 if (fulfilled != null)
29 m_fulfilled = () => { next.Resolve(fulfilled()); };
30 if (rejected != null)
31 m_rejected = (e) => { next.Resolve(rejected(e)); };
32 m_next = next;
33 }
20 }
34
21
35 public PromiseActionReaction(Action fulfilled, Func<Exception, IPromise> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
22 public PromiseActionReaction(Func<IPromise> fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) : base(dispatcher) {
23 m_next = new Deferred(dispatcher);
36 if (fulfilled != null)
24 if (fulfilled != null)
37 m_fulfilled = () => {
25 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
38 fulfilled();
39 next.Resolve();
40 };
41
26
42 if (rejected != null)
27 if (rejected != null)
43 m_rejected = (e) => { next.Resolve(rejected(e)); };
28 RejectHandler = PromiseHandler.Create(rejected, m_next);
44 m_next = next;
45 }
29 }
46
30
47 public PromiseActionReaction(Func<IPromise> fulfilled, Action<Exception> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
31 public PromiseActionReaction(Action fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) : base(dispatcher) {
32 m_next = new Deferred(dispatcher);
48 if (fulfilled != null)
33 if (fulfilled != null)
49 m_fulfilled = () => { next.Resolve(fulfilled()); };
34 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
50
35
51 if (rejected != null)
36 if (rejected != null)
52 m_rejected = (x) => {
37 RejectHandler = PromiseHandler.Create(rejected, m_next);
53 rejected(x);
54 next.Resolve();
55 };
56 m_next = next;
57 }
38 }
58
39
40 public PromiseActionReaction(Func<IPromise> fulfilled, Action<Exception> rejected, IDispatcher dispatcher) : base(dispatcher) {
41 m_next = new Deferred(dispatcher);
42 if (fulfilled != null)
43 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
59
44
60 protected override bool HasFulfilHandler => m_fulfilled != null;
45 if (rejected != null)
61
46 RejectHandler = PromiseHandler.Create(rejected, m_next);
62 protected override bool HasRejectHandler => m_rejected != null;
47 }
63
48
64 protected override void DefaultReject(Exception reason) {
49 protected override void DefaultReject(Exception reason) {
65 m_next.Reject(reason);
50 m_next.Reject(reason);
66 }
51 }
67
52
68 protected override void DefaultResolve() {
53 protected override void DefaultResolve() {
69 m_next.Resolve();
54 m_next.Resolve();
70 }
55 }
71
72 protected override void RejectImpl(Exception reason) {
73 try {
74 m_rejected(reason);
75 } catch (Exception e){
76 m_next.Reject(e);
77 }
78 }
79
80 protected override void ResolveImpl() {
81 try {
82 m_fulfilled();
83 } catch (Exception e){
84 m_next.Reject(e);
85 }
86 }
87 }
56 }
88 } No newline at end of file
57 }
@@ -1,87 +1,56
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3
3
4 namespace Implab {
4 namespace Implab {
5 class PromiseActionReaction<T> : PromiseReaction<T> {
5 class PromiseActionReaction<T> : PromiseReaction<T> {
6 readonly Action<T> m_fulfilled;
7
8 readonly Action<Exception> m_rejected;
9
10 readonly Deferred m_next;
6 readonly Deferred m_next;
11
7
12 public PromiseActionReaction(Action<T> fulfilled, Action<Exception> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
8 public IPromise Promise {
9 get { return m_next.Promise; }
10 }
11
12 public PromiseActionReaction(Action<T> fulfilled, Action<Exception> rejected, IDispatcher dispatcher) : base(dispatcher) {
13 m_next = new Deferred(dispatcher);
13 if (fulfilled != null)
14 if (fulfilled != null)
14 m_fulfilled = (x) => {
15 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
15 fulfilled(x);
16 next.Resolve();
17 };
18
16
19 if (rejected != null)
17 if (rejected != null)
20 m_rejected = (x) => {
18 RejectHandler = PromiseHandler.Create(rejected, m_next);
21 rejected(x);
22 next.Resolve();
23 };
24 m_next = next;
25 }
19 }
26
20
27 public PromiseActionReaction(Func<T, IPromise> fulfilled, Func<Exception, IPromise> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
21 public PromiseActionReaction(Func<T, IPromise> fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) : base(dispatcher) {
22 m_next = new Deferred(dispatcher);
28 if (fulfilled != null)
23 if (fulfilled != null)
29 m_fulfilled = (x) => { next.Resolve(fulfilled(x)); };
24 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
30 if (rejected != null)
31 m_rejected = (e) => { next.Resolve(rejected(e)); };
32 m_next = next;
33 }
34
35 public PromiseActionReaction(Action<T> fulfilled, Func<Exception, IPromise> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
36 if (fulfilled != null)
37 m_fulfilled = (x) => {
38 fulfilled(x);
39 next.Resolve();
40 };
41
25
42 if (rejected != null)
26 if (rejected != null)
43 m_rejected = (e) => { next.Resolve(rejected(e)); };
27 RejectHandler = PromiseHandler.Create(rejected, m_next);
44 m_next = next;
45 }
28 }
46
29
47 public PromiseActionReaction(Func<T, IPromise> fulfilled, Action<Exception> rejected, Deferred next, IDispatcher dispatcher) : base(dispatcher) {
30 public PromiseActionReaction(Action<T> fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) : base(dispatcher) {
31 m_next = new Deferred(dispatcher);
48 if (fulfilled != null)
32 if (fulfilled != null)
49 m_fulfilled = (x) => { next.Resolve(fulfilled(x)); };
33 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
50
34
51 if (rejected != null)
35 if (rejected != null)
52 m_rejected = (x) => {
36 RejectHandler = PromiseHandler.Create(rejected, m_next);
53 rejected(x);
54 next.Resolve();
55 };
56 m_next = next;
57 }
37 }
58
38
59 protected override bool HasFulfilHandler => m_fulfilled != null;
39 public PromiseActionReaction(Func<T, IPromise> fulfilled, Action<Exception> rejected, IDispatcher dispatcher) : base(dispatcher) {
40 m_next = new Deferred(dispatcher);
41 if (fulfilled != null)
42 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
60
43
61 protected override bool HasRejectHandler => m_rejected != null;
44 if (rejected != null)
45 RejectHandler = PromiseHandler.Create(rejected, m_next);
46 }
62
47
63 protected override void DefaultReject(Exception reason) {
48 protected override void DefaultReject(Exception reason) {
64 m_next.Reject(reason);
49 m_next.Reject(reason);
65 }
50 }
66
51
67 protected override void DefaultResolve(T result) {
52 protected override void DefaultResolve(T result) {
68 m_next.Resolve();
53 m_next.Resolve();
69 }
54 }
70
71 protected override void RejectImpl(Exception reason) {
72 try {
73 m_rejected(reason);
74 } catch (Exception e) {
75 m_next.Reject(e);
76 }
77 }
78
79 protected override void ResolveImpl(T result) {
80 try {
81 m_fulfilled(result);
82 } catch (Exception e) {
83 m_next.Reject(e);
84 }
85 }
86 }
55 }
87 } No newline at end of file
56 }
This diff has been collapsed as it changes many lines, (508 lines changed) Show them Hide them
@@ -1,475 +1,131
1 using System.Threading;
1 using System.Threading;
2 using System;
2 using System;
3 using Implab.Diagnostics;
3 using Implab.Diagnostics;
4 using System.Collections.Generic;
4 using System.Collections.Generic;
5 using System.Linq;
5 using System.Linq;
6
6
7 namespace Implab {
7 namespace Implab {
8 public static class PromiseExtensions {
8 public static class PromiseExtensions {
9 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
10 Safe.ArgumentNotNull(that, "that");
11 var context = SynchronizationContext.Current;
12 if (context == null)
13 return that;
14
9
15 var p = new SyncContextPromise<T>(context);
10 public static IPromise Then(this IPromise that, Action fulfilled, Action<Exception> rejected) {
16 p.CancellationRequested(that.Cancel);
11 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
17
12 that.Then(reaction);
18 that.On(
13 return reaction.Promise;
19 p.Resolve,
20 p.Reject,
21 p.CancelOperation
22 );
23 return p;
24 }
25
26 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
27 Safe.ArgumentNotNull(that, "that");
28 Safe.ArgumentNotNull(context, "context");
29
30 var p = new SyncContextPromise<T>(context);
31 p.CancellationRequested(that.Cancel);
32
33 that.On(
34 p.Resolve,
35 p.Reject,
36 p.CancelOperation
37 );
38 return p;
39 }
40
41 /// <summary>
42 /// Ensures the dispatched.
43 /// </summary>
44 /// <returns>The dispatched.</returns>
45 /// <param name="that">That.</param>
46 /// <param name="head">Head.</param>
47 /// <param name="cleanup">Cleanup.</param>
48 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
49 /// <typeparam name="T">The 2nd type parameter.</typeparam>
50 public static TPromise EnsureDispatched<TPromise, T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise {
51 Safe.ArgumentNotNull(that, "that");
52 Safe.ArgumentNotNull(head, "head");
53
54 that.On(() => head.On(cleanup), PromiseEventType.Cancelled);
55
56 return that;
57 }
14 }
58
15
59 /// <summary>
16 public static IPromise Then(this IPromise that, Action fulfilled, Func<Exception, IPromise> rejected) {
60 /// Adds a cancellation point to the chain of promises. When a cancellation request reaches the cancellation point the operation is
17 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
61 /// cancelled immediatelly, and the request is passed towards. If the operation at the higher level can not be cancelled is't result
18 that.Then(reaction);
62 /// will be collected with <paramref name="cleanup"/> callback.
19 return reaction.Promise;
63 /// </summary>
64 /// <typeparam name="T">The type of the promise result.</typeparam>
65 /// <param name="that">The promise to which the cancellation point should be attached.</param>
66 /// <param name="cleanup">The callback which is used to cleanup the result of the operation if the cancellation point is cancelled already.</param>
67 /// <returns>The promise</returns>
68 public static IPromise<T> CancellationPoint<T>(this IPromise<T> that, Action<T> cleanup) {
69 var meduim = new Promise<T>();
70
71 that.On(meduim.Resolve, meduim.Reject, meduim.CancelOperation);
72
73 meduim.CancellationRequested(that.Cancel);
74 meduim.CancellationRequested(meduim.CancelOperation);
75
76 if (cleanup != null)
77 meduim.On((Action<T>)null, null, (e) => {
78 that.On(cleanup);
79 });
80
81 return meduim;
82 }
20 }
83
21
84 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult, T> callback) {
22 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Action<Exception> rejected) {
85 Safe.ArgumentNotNull(that, "that");
23 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
86 Safe.ArgumentNotNull(callback, "callback");
24 that.Then(reaction);
87 var op = TraceContext.Instance.CurrentOperation;
25 return reaction.Promise;
88 return ar => {
89 TraceContext.Instance.EnterLogicalOperation(op, false);
90 try {
91 that.Resolve(callback(ar));
92 } catch (Exception err) {
93 that.Reject(err);
94 } finally {
95 TraceContext.Instance.Leave();
96 }
97 };
98 }
26 }
99
27
100 static void CancelByTimeoutCallback(object cookie) {
28 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Func<Exception, IPromise> rejected) {
101 ((ICancellable)cookie).Cancel(new TimeoutException());
29 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
102 }
30 that.Then(reaction);
103
31 return reaction.Promise;
104 /// <summary>
105 /// Cancells promise after the specified timeout is elapsed.
106 /// </summary>
107 /// <param name="that">The promise to cancel on timeout.</param>
108 /// <param name="milliseconds">The timeout in milliseconds.</param>
109 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
110 public static TPromise Timeout<TPromise>(this TPromise that, int milliseconds) where TPromise : IPromise {
111 Safe.ArgumentNotNull(that, "that");
112 var timer = new Timer(CancelByTimeoutCallback, that, milliseconds, -1);
113 that.On(timer.Dispose, PromiseEventType.All);
114 return that;
115 }
32 }
116
33
117 public static IPromise PromiseAll(this IEnumerable<IPromise> that) {
34 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Action<Exception> rejected) {
118 Safe.ArgumentNotNull(that, "that");
35 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
119 return PromiseAll(that.ToList());
36 that.Then(reaction);
120 }
37 return reaction.Promise;
121
122 public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that) {
123 return PromiseAll(that, null);
124 }
125
126 public static IPromise<T[]> PromiseAll<T>(this IEnumerable<IPromise<T>> that, Action<T> cleanup) {
127 Safe.ArgumentNotNull(that, "that");
128 return PromiseAll(that.ToList(), cleanup);
129 }
38 }
130
39
131 public static IPromise PromiseAll(this ICollection<IPromise> that) {
40 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Func<Exception, IPromise> rejected) {
132 Safe.ArgumentNotNull(that, "that");
41 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
133
42 that.Then(reaction);
134 int count = that.Count;
43 return reaction.Promise;
135 int errors = 0;
136 var medium = new Promise();
137
138 if (count == 0) {
139 medium.Resolve();
140 return medium;
141 }
142
143 medium.On(() => {
144 foreach (var p2 in that)
145 p2.Cancel();
146 }, PromiseEventType.ErrorOrCancel);
147
148 foreach (var p in that)
149 p.On(
150 () => {
151 if (Interlocked.Decrement(ref count) == 0)
152 medium.Resolve();
153 },
154 error => {
155 if (Interlocked.Increment(ref errors) == 1)
156 medium.Reject(
157 new Exception("The dependency promise is failed", error)
158 );
159 },
160 reason => {
161 if (Interlocked.Increment(ref errors) == 1)
162 medium.Cancel(
163 new Exception("The dependency promise is cancelled")
164 );
165 }
166 );
167
168 return medium;
169 }
170
171 public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that) {
172 return PromiseAll(that, null);
173 }
44 }
174
45
175 /// <summary>
46 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Action<Exception> rejected) {
176 /// Creates a new promise which will be satisfied when all promises are satisfied.
47 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
177 /// </summary>
48 that.Then(reaction);
178 /// <typeparam name="T"></typeparam>
49 return reaction.Promise;
179 /// <param name="that"></param>
180 /// <param name="cleanup">A callback used to cleanup already resolved promises in case of an error</param>
181 /// <returns></returns>
182 public static IPromise<T[]> PromiseAll<T>(this ICollection<IPromise<T>> that, Action<T> cleanup) {
183 Safe.ArgumentNotNull(that, "that");
184
185 int count = that.Count;
186
187 if (count == 0)
188 return Promise<T[]>.FromResult(new T[0]);
189
190 int errors = 0;
191 var medium = new Promise<T[]>();
192 var results = new T[that.Count];
193
194 medium.On(() => {
195 foreach (var p2 in that) {
196 p2.Cancel();
197 if (cleanup != null)
198 p2.On(cleanup);
199 }
200 }, PromiseEventType.ErrorOrCancel);
201
202 int i = 0;
203 foreach (var p in that) {
204 var idx = i;
205 p.On(
206 x => {
207 results[idx] = x;
208 if (Interlocked.Decrement(ref count) == 0)
209 medium.Resolve(results);
210 },
211 error => {
212 if (Interlocked.Increment(ref errors) == 1)
213 medium.Reject(
214 new Exception("The dependency promise is failed", error)
215 );
216 },
217 reason => {
218 if (Interlocked.Increment(ref errors) == 1)
219 medium.Cancel(
220 new Exception("The dependency promise is cancelled", reason)
221 );
222 }
223 );
224 i++;
225 }
226
227 return medium;
228 }
50 }
229
51
230 public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) {
52 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Func<Exception, IPromise> rejected) {
231 Safe.ArgumentNotNull(that, "that");
53 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
54 that.Then(reaction);
55 return reaction.Promise;
56 }
232
57
233 var d = new ActionTask(success, error, cancel, false);
58 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, Tout> rejected) {
234 that.On(d.Resolve, d.Reject, d.CancelOperation);
59 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
235 d.CancellationRequested(that.Cancel);
60 that.Then(reaction);
236 return d;
61 return reaction.Promise;
237 }
62 }
238
63
239 public static IPromise Then(this IPromise that, Action success, Action<Exception> error) {
64 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
240 return Then(that, success, error, null);
65 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
241 }
66 that.Then(reaction);
242
67 return reaction.Promise;
243 public static IPromise Then(this IPromise that, Action success) {
244 return Then(that, success, null, null);
245 }
246
247 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
248 Safe.ArgumentNotNull(that, "that");
249
250 var d = new FuncTask<T>(success, error, cancel, false);
251 that.On(d.Resolve, d.Reject, d.CancelOperation);
252 d.CancellationRequested(that.Cancel);
253 return d;
254 }
255
256 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error) {
257 return Then(that, success, error, null);
258 }
259
260 public static IPromise<T> Then<T>(this IPromise that, Func<T> success) {
261 return Then(that, success, null, null);
262 }
68 }
263
69
264 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) {
70 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
265 Safe.ArgumentNotNull(that, "that");
71 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
266 Safe.ArgumentNotNull(success, "success");
72 that.Then(reaction);
267
73 return reaction.Promise;
268 var d = new FuncTask<T, T2>(success, error, cancel, false);
269 that.On(d.Resolve, d.Reject, d.CancelOperation);
270 d.CancellationRequested(that.Cancel);
271 return d;
272 }
273
274 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
275 Safe.ArgumentNotNull(that, "that");
276 var d = new FuncTask<T, T>(
277 x => {
278 success(x);
279 return x;
280 },
281 error,
282 cancel,
283 false
284 );
285 that.On(d.Resolve, d.Reject, d.CancelOperation);
286 d.CancellationRequested(that.Cancel);
287 return d;
288 }
289
290 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success, Func<Exception, T> error) {
291 return Then(that, success, error, null);
292 }
74 }
293
75
294 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success) {
76 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
295 return Then(that, success, null, null);
77 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
296 }
78 that.Then(reaction);
297
79 return reaction.Promise;
298 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) {
299 return Then(that, success, error, null);
300 }
301
302 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success) {
303 return Then(that, success, null, null);
304 }
80 }
305
81
306 public static IPromise<T> Always<T>(this IPromise<T> that, Action handler) {
82 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, Tout> rejected) {
307 Func<Exception, T> errorOrCancel;
83 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
308 if (handler != null)
84 that.Then(reaction);
309 errorOrCancel = e => {
85 return reaction.Promise;
310 handler();
311 throw new PromiseTransientException(e);
312 };
313 else
314 errorOrCancel = null;
315
316 return Then(
317 that,
318 x => {
319 handler();
320 return x;
321 },
322 errorOrCancel,
323 errorOrCancel);
324 }
86 }
325
87
326 public static IPromise Always(this IPromise that, Action handler) {
88 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
327 Action<Exception> errorOrCancel;
89 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
328 if (handler != null)
90 that.Then(reaction);
329 errorOrCancel = e => {
91 return reaction.Promise;
330 handler();
331 throw new PromiseTransientException(e);
332 };
333 else
334 errorOrCancel = null;
335
336 return Then(
337 that,
338 handler,
339 errorOrCancel,
340 errorOrCancel);
341 }
342
343 public static IPromise Error(this IPromise that, Action<Exception> handler, bool handleCancellation) {
344 Action<Exception> errorOrCancel;
345 if (handler != null)
346 errorOrCancel = e => {
347 handler(e);
348 throw new PromiseTransientException(e);
349 };
350 else
351 errorOrCancel = null;
352
353 return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null);
354 }
92 }
355
93
356 public static IPromise Error(this IPromise that, Action<Exception> handler) {
94 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
357 return Error(that, handler, false);
95 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
358 }
96 that.Then(reaction);
359
97 return reaction.Promise;
360 public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler, bool handleCancellation) {
361 Func<Exception, T> errorOrCancel;
362 if (handler != null)
363 errorOrCancel = e => {
364 handler(e);
365 throw new PromiseTransientException(e);
366 };
367 else
368 errorOrCancel = null;
369
370 return Then(that, null, errorOrCancel, handleCancellation ? errorOrCancel : null);
371 }
98 }
372
99
373 public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler) {
100 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
374 return Error(that, handler, false);
101 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
375 }
102 that.Then(reaction);
376
103 return reaction.Promise;
377 #region chain traits
378 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) {
379 Safe.ArgumentNotNull(that, "that");
380
381 var d = new ActionChainTask(success, error, cancel, false);
382 that.On(d.Resolve, d.Reject, d.CancelOperation);
383 d.CancellationRequested(that.Cancel);
384 return d;
385 }
386
387 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error) {
388 return Chain(that, success, error, null);
389 }
104 }
390
105
391 public static IPromise Chain(this IPromise that, Func<IPromise> success) {
106 public static IPromise Catch(this IPromise that, Action<Exception> rejected) {
392 return Chain(that, success, null, null);
107 return Then(that, null, rejected);
393 }
394
395 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error, Func<Exception, IPromise<T>> cancel) {
396 Safe.ArgumentNotNull(that, "that");
397
398 var d = new FuncChainTask<T>(success, error, cancel, false);
399 that.On(d.Resolve, d.Reject, d.CancelOperation);
400 if (success != null)
401 d.CancellationRequested(that.Cancel);
402 return d;
403 }
404
405 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error) {
406 return Chain(that, success, error, null);
407 }
408
409 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success) {
410 return Chain(that, success, null, null);
411 }
108 }
412
109
413 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) {
110 public static IPromise Catch(this IPromise that, Func<Exception, IPromise> rejected) {
414 Safe.ArgumentNotNull(that, "that");
111 return Then(that, null, rejected);
415 var d = new FuncChainTask<T, T2>(success, error, cancel, false);
416 that.On(d.Resolve, d.Reject, d.CancelOperation);
417 if (success != null)
418 d.CancellationRequested(that.Cancel);
419 return d;
420 }
112 }
421
113
422 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error) {
114 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, Tout> rejected) {
423 return Chain(that, success, error, null);
115 return Then(that, (Func<Tout>)null, rejected);
424 }
116 }
425
117
426 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) {
118 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, IPromise<Tout>> rejected) {
427 return Chain(that, success, null, null);
119 return Then(that, (Func<Tout>)null, rejected);
428 }
120 }
429
430 #endregion
431
432 public static IPromise<T2> Guard<T, T2>(this IPromise<T> that, Func<IPromise<T>, IPromise<T2>> continuation, Action<T> cleanup) {
433 Safe.ArgumentNotNull(that, "that");
434 Safe.ArgumentNotNull(continuation, "continuation");
435 return continuation(that).Error((err) => {
436 that.On(cleanup);
437 }, true);
438 }
439
440 #if NET_4_5
441
442 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
443 Safe.ArgumentNotNull(that, "that");
444
121
445 return new PromiseAwaiter<T>(that);
122 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, Tout> rejected) {
446 }
123 return Then(that, (Func<Tin, Tout>)null, rejected);
447
124 }
448 public static PromiseAwaiter GetAwaiter(this IPromise that) {
449 Safe.ArgumentNotNull(that, "that");
450
125
451 return new PromiseAwaiter(that);
126 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, IPromise<Tout>> rejected) {
452 }
127 return Then(that, (Func<Tin, Tout>)null, rejected);
453
128 }
454 public static IPromise BoundCancellationToken(this IPromise that, CancellationToken ct) {
455 Safe.ArgumentNotNull(that, "that");
456 ct.Register(that.Cancel);
457 return that.Then(null, null, (err) => {
458 ct.ThrowIfCancellationRequested();
459 throw new PromiseTransientException(err);
460 });
461 }
462
463 public static IPromise<T> BoundCancellationToken<T>(this IPromise<T> that, CancellationToken ct) {
464 Safe.ArgumentNotNull(that, "that");
465 ct.Register(that.Cancel);
466 return that.Then(null, null, (err) => {
467 ct.ThrowIfCancellationRequested();
468 throw new PromiseTransientException(err);
469 });
470 }
471
472 #endif
473 }
129 }
474 }
130 }
475
131
@@ -1,76 +1,56
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3
3
4 namespace Implab {
4 namespace Implab {
5 class PromiseFuncReaction<TRet> : PromiseReaction {
5 class PromiseFuncReaction<TRet> : PromiseReaction {
6 readonly Action m_fulfilled;
7
8 readonly Action<Exception> m_rejected;
9
10 readonly Deferred<TRet> m_next;
6 readonly Deferred<TRet> m_next;
11
7
12 public PromiseFuncReaction(Func<TRet> fulfilled, Func<Exception, TRet> rejected, Deferred<TRet> next, IDispatcher dispatcher) : base(dispatcher) {
8 public IPromise<TRet> Promise {
9 get { return m_next.Promise; }
10 }
11
12 public PromiseFuncReaction(Func<TRet> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) : base(dispatcher) {
13 m_next = new Deferred<TRet>(dispatcher);
13 if (fulfilled != null)
14 if (fulfilled != null)
14 m_fulfilled = () => { next.Resolve(fulfilled()); };
15 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
15
16
16 if (rejected != null)
17 if (rejected != null)
17 m_rejected = (e) => { next.Resolve(rejected(e)); };
18 RejectHandler = PromiseHandler.Create(rejected, m_next);
18 m_next = next;
19 }
20
21 public PromiseFuncReaction(Func<IPromise<TRet>> fulfilled, Func<Exception, IPromise<TRet>> rejected, Deferred<TRet> next, IDispatcher dispatcher) : base(dispatcher) {
22 if (fulfilled != null)
23 m_fulfilled = () => { next.Resolve(fulfilled()); };
24 if (rejected != null)
25 m_rejected = (e) => { next.Resolve(rejected(e)); };
26 m_next = next;
27 }
19 }
28
20
29 public PromiseFuncReaction(Func<TRet> fulfilled, Func<Exception, IPromise<TRet>> rejected, Deferred<TRet> next, IDispatcher dispatcher) : base(dispatcher) {
21 public PromiseFuncReaction(Func<IPromise<TRet>> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) : base(dispatcher) {
22 m_next = new Deferred<TRet>(dispatcher);
30 if (fulfilled != null)
23 if (fulfilled != null)
31 m_fulfilled = () => { next.Resolve(fulfilled()); };
24 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
25
32 if (rejected != null)
26 if (rejected != null)
33 m_rejected = (e) => { next.Resolve(rejected(e)); };
27 RejectHandler = PromiseHandler.Create(rejected, m_next);
34
35 m_next = next;
36 }
28 }
37
29
38 public PromiseFuncReaction(Func<IPromise<TRet>> fulfilled, Func<Exception, TRet> rejected, Deferred<TRet> next, IDispatcher dispatcher) : base(dispatcher) {
30 public PromiseFuncReaction(Func<TRet> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) : base(dispatcher) {
31 m_next = new Deferred<TRet>(dispatcher);
39 if (fulfilled != null)
32 if (fulfilled != null)
40 m_fulfilled = () => { next.Resolve(fulfilled()); };
33 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
34
41 if (rejected != null)
35 if (rejected != null)
42 m_rejected = (e) => { next.Resolve(rejected(e)); };
36 RejectHandler = PromiseHandler.Create(rejected, m_next);
43
44 m_next = next;
45 }
37 }
46
38
39 public PromiseFuncReaction(Func<IPromise<TRet>> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) : base(dispatcher) {
40 m_next = new Deferred<TRet>(dispatcher);
41 if (fulfilled != null)
42 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
47
43
48 protected override bool HasFulfilHandler => m_fulfilled != null;
44 if (rejected != null)
49
45 RejectHandler = PromiseHandler.Create(rejected, m_next);
50 protected override bool HasRejectHandler => m_rejected != null;
46 }
51
47
52 protected override void DefaultReject(Exception reason) {
48 protected override void DefaultReject(Exception reason) {
53 m_next.Reject(reason);
49 m_next.Reject(reason);
54 }
50 }
55
51
56 protected override void DefaultResolve() {
52 protected override void DefaultResolve() {
57 throw new NotImplementedException();
53 throw new NotImplementedException();
58 }
54 }
59
60 protected override void RejectImpl(Exception reason) {
61 try {
62 m_rejected(reason);
63 } catch (Exception e){
64 m_next.Reject(e);
65 }
66 }
67
68 protected override void ResolveImpl() {
69 try {
70 m_fulfilled();
71 } catch (Exception e){
72 m_next.Reject(e);
73 }
74 }
75 }
55 }
76 } No newline at end of file
56 }
@@ -1,45 +1,42
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 /// <summary>
5 /// Базовыйй класс для создания обработчиков результов выполнения обещаний.
6 /// Данный объект связывает обработчик и обешание, при этом для выполнения
7 /// обработчика будет использоваться диспетчер.
8 /// </summary>
4 abstract class PromiseReaction : IResolvable {
9 abstract class PromiseReaction : IResolvable {
5 readonly IDispatcher m_dispatcher;
10 readonly IDispatcher m_dispatcher;
6
11
7 protected PromiseReaction(IDispatcher dispatcher) {
12 protected PromiseReaction(IDispatcher dispatcher) {
8 m_dispatcher = dispatcher;
13 m_dispatcher = dispatcher;
9 }
14 }
10
15
11 protected abstract bool HasFulfilHandler {
16 protected Action FulfilHandler { get; set; }
12 get;
13 }
14
17
15 protected abstract bool HasRejectHandler {
18 protected Action<Exception> RejectHandler { get; set; }
16 get;
17 }
18
19
19 public void Reject(Exception error) {
20 public void Reject(Exception error) {
20 if (!HasRejectHandler)
21 if (RejectHandler == null)
21 DefaultReject(error);
22 DefaultReject(error);
22 else if (m_dispatcher != null)
23 else if (m_dispatcher != null)
23 m_dispatcher.Enqueue(() => RejectImpl(error));
24 m_dispatcher.Enqueue(RejectHandler, error);
24 else
25 else
25 RejectImpl(error);
26 RejectHandler(error);
26 }
27 }
27
28
28 public void Resolve() {
29 public void Resolve() {
29 if (!HasFulfilHandler)
30 if (FulfilHandler == null)
30 DefaultResolve();
31 DefaultResolve();
31 else if (m_dispatcher != null)
32 else if (m_dispatcher != null)
32 m_dispatcher.Enqueue(ResolveImpl);
33 m_dispatcher.Enqueue(FulfilHandler);
33 else
34 else
34 ResolveImpl();
35 FulfilHandler();
35 }
36 }
36
37
37 protected abstract void ResolveImpl();
38
39 protected abstract void RejectImpl(Exception reason);
40
41 protected abstract void DefaultResolve();
38 protected abstract void DefaultResolve();
42
39
43 protected abstract void DefaultReject(Exception reason);
40 protected abstract void DefaultReject(Exception reason);
44 }
41 }
45 } No newline at end of file
42 }
@@ -1,45 +1,42
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 /// <summary>
5 /// Базовыйй класс для создания обработчиков результов выполнения обещаний.
6 /// Данный объект связывает обработчик и обешание, при этом для выполнения
7 /// обработчика будет использоваться диспетчер.
8 /// </summary>
4 abstract class PromiseReaction<T> : IResolvable<T> {
9 abstract class PromiseReaction<T> : IResolvable<T> {
5 readonly IDispatcher m_dispatcher;
10 readonly IDispatcher m_dispatcher;
6
11
7 protected PromiseReaction(IDispatcher dispatcher) {
12 protected PromiseReaction(IDispatcher dispatcher) {
8 m_dispatcher = dispatcher;
13 m_dispatcher = dispatcher;
9 }
14 }
10
15
11 protected abstract bool HasFulfilHandler {
16 protected Action<T> FulfilHandler { get; set; }
12 get;
13 }
14
17
15 protected abstract bool HasRejectHandler {
18 protected Action<Exception> RejectHandler { get; set; }
16 get;
17 }
18
19
19 public void Reject(Exception error) {
20 public void Reject(Exception error) {
20 if (!HasRejectHandler)
21 if (RejectHandler == null)
21 DefaultReject(error);
22 DefaultReject(error);
22 else if (m_dispatcher != null)
23 else if (m_dispatcher != null)
23 m_dispatcher.Enqueue(() => RejectImpl(error));
24 m_dispatcher.Enqueue(RejectHandler, error);
24 else
25 else
25 RejectImpl(error);
26 RejectHandler(error);
26 }
27 }
27
28
28 public void Resolve(T result) {
29 public void Resolve(T result) {
29 if (!HasFulfilHandler)
30 if (FulfilHandler == null)
30 DefaultResolve(result);
31 DefaultResolve(result);
31 else if (m_dispatcher != null)
32 else if (m_dispatcher != null)
32 m_dispatcher.Enqueue(() => ResolveImpl(result));
33 m_dispatcher.Enqueue(FulfilHandler, result);
33 else
34 else
34 ResolveImpl(result);
35 FulfilHandler(result);
35 }
36 }
36
37
37 protected abstract void ResolveImpl(T result);
38
39 protected abstract void RejectImpl(Exception reason);
40
41 protected abstract void DefaultResolve(T result);
38 protected abstract void DefaultResolve(T result);
42
39
43 protected abstract void DefaultReject(Exception reason);
40 protected abstract void DefaultReject(Exception reason);
44 }
41 }
45 } No newline at end of file
42 }
@@ -1,164 +1,164
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Text.RegularExpressions;
5 using System.Text.RegularExpressions;
6 using System.Diagnostics;
6 using System.Diagnostics;
7 using System.Collections;
7 using System.Collections;
8 using System.Runtime.CompilerServices;
8 using System.Runtime.CompilerServices;
9
9
10 #if NET_4_5
10 #if NET_4_5
11 using System.Threading.Tasks;
11 using System.Threading.Tasks;
12 #endif
12 #endif
13
13
14 namespace Implab
14 namespace Implab
15 {
15 {
16 public static class Safe
16 public static class Safe
17 {
17 {
18 [MethodImpl(MethodImplOptions.AggressiveInlining)]
18 [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 public static void ArgumentAssert(bool condition, string paramName) {
19 public static void ArgumentAssert(bool condition, string paramName) {
20 if (!condition)
20 if (!condition)
21 throw new ArgumentException("The parameter is invalid", paramName);
21 throw new ArgumentException("The parameter is invalid", paramName);
22 }
22 }
23
23
24 [MethodImpl(MethodImplOptions.AggressiveInlining)]
24 [MethodImpl(MethodImplOptions.AggressiveInlining)]
25 public static void ArgumentMatch(string value, string paramName, Regex rx) {
25 public static void ArgumentMatch(string value, string paramName, Regex rx) {
26 if (rx == null)
26 if (rx == null)
27 throw new ArgumentNullException("rx");
27 throw new ArgumentNullException("rx");
28 if (!rx.IsMatch(value))
28 if (!rx.IsMatch(value))
29 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
29 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
30 }
30 }
31
31
32 [MethodImpl(MethodImplOptions.AggressiveInlining)]
32 [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 public static void ArgumentNotEmpty(string value, string paramName) {
33 public static void ArgumentNotEmpty(string value, string paramName) {
34 if (String.IsNullOrEmpty(value))
34 if (String.IsNullOrEmpty(value))
35 throw new ArgumentException("The parameter can't be empty", paramName);
35 throw new ArgumentException("The parameter can't be empty", paramName);
36 }
36 }
37
37
38 [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
39 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
40 if (value == null || value.Length == 0)
40 if (value == null || value.Length == 0)
41 throw new ArgumentException("The array must be not emty", paramName);
41 throw new ArgumentException("The array must be not emty", paramName);
42 }
42 }
43
43
44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 public static void ArgumentNotNull(object value, string paramName) {
45 public static void ArgumentNotNull(object value, string paramName) {
46 if (value == null)
46 if (value == null)
47 throw new ArgumentNullException(paramName);
47 throw new ArgumentNullException(paramName);
48 }
48 }
49
49
50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 internal static void ArgumentGreaterThan(int value, int min, string paramName) {
51 internal static void ArgumentGreaterThan(int value, int min, string paramName) {
52 if (value < min)
52 if (value < min)
53 throw new ArgumentOutOfRangeException(paramName);
53 throw new ArgumentOutOfRangeException(paramName);
54 }
54 }
55
55
56 [MethodImpl(MethodImplOptions.AggressiveInlining)]
56 [MethodImpl(MethodImplOptions.AggressiveInlining)]
57 public static void ArgumentInRange(int value, int min, int max, string paramName) {
57 public static void ArgumentInRange(int value, int min, int max, string paramName) {
58 if (value < min || value > max)
58 if (value < min || value > max)
59 throw new ArgumentOutOfRangeException(paramName);
59 throw new ArgumentOutOfRangeException(paramName);
60 }
60 }
61
61
62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
63 public static void ArgumentOfType(object value, Type type, string paramName) {
63 public static void ArgumentOfType(object value, Type type, string paramName) {
64 if (!type.IsInstanceOfType(value))
64 if (!type.IsInstanceOfType(value))
65 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
65 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
66 }
66 }
67
67
68 public static void Dispose(params IDisposable[] objects) {
68 public static void Dispose(params IDisposable[] objects) {
69 foreach (var d in objects)
69 foreach (var d in objects)
70 if (d != null)
70 if (d != null)
71 d.Dispose();
71 d.Dispose();
72 }
72 }
73
73
74 public static void Dispose(params object[] objects) {
74 public static void Dispose(params object[] objects) {
75 foreach (var obj in objects) {
75 foreach (var obj in objects) {
76 var d = obj as IDisposable;
76 var d = obj as IDisposable;
77 if (d != null)
77 if (d != null)
78 d.Dispose();
78 d.Dispose();
79 }
79 }
80 }
80 }
81
81
82 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
82 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
83 foreach (var d in objects)
83 foreach (var d in objects)
84 Dispose(d);
84 Dispose(d);
85 }
85 }
86
86
87 public static void DisposeCollection(IEnumerable objects) {
87 public static void DisposeCollection(IEnumerable objects) {
88 foreach (var d in objects)
88 foreach (var d in objects)
89 Dispose(d);
89 Dispose(d);
90 }
90 }
91
91
92 public static void Dispose(object obj) {
92 public static void Dispose(object obj) {
93 if (obj is IDisposable)
93 if (obj is IDisposable)
94 Dispose((IDisposable)obj);
94 Dispose((IDisposable)obj);
95
95
96 }
96 }
97
97
98 [DebuggerStepThrough]
98 [DebuggerStepThrough]
99 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
99 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
100 if (handler != null)
100 if (handler != null)
101 handler(sender, args);
101 handler(sender, args);
102 }
102 }
103
103
104 [DebuggerStepThrough]
104 [DebuggerStepThrough]
105 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
105 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
106 if (handler != null)
106 if (handler != null)
107 handler(sender, args);
107 handler(sender, args);
108 }
108 }
109
109
110 [DebuggerStepThrough]
110 [DebuggerStepThrough]
111 public static IPromise<T> Run<T>(Func<T> action) {
111 public static IPromise<T> Run<T>(Func<T> action) {
112 ArgumentNotNull(action, "action");
112 ArgumentNotNull(action, "action");
113
113
114 try {
114 try {
115 return Promise<T>.FromResult(action());
115 return Promise.Resolve(action());
116 } catch (Exception err) {
116 } catch (Exception err) {
117 return Promise<T>.FromException(err);
117 return Promise.Reject<T>(err);
118 }
118 }
119 }
119 }
120
120
121 [DebuggerStepThrough]
121 [DebuggerStepThrough]
122 public static IPromise Run(Action action) {
122 public static IPromise Run(Action action) {
123 ArgumentNotNull(action, "action");
123 ArgumentNotNull(action, "action");
124
124
125 try {
125 try {
126 action();
126 action();
127 return Promise.Success;
127 return Promise.Resolve();
128 } catch (Exception err) {
128 } catch (Exception err) {
129 return new FailedPromise(err);
129 return Promise.Reject(err);
130 }
130 }
131 }
131 }
132
132
133 [DebuggerStepThrough]
133 [DebuggerStepThrough]
134 public static IPromise Run(Func<IPromise> action) {
134 public static IPromise Run(Func<IPromise> action) {
135 ArgumentNotNull(action, "action");
135 ArgumentNotNull(action, "action");
136
136
137 try {
137 try {
138 return action() ?? new FailedPromise(new Exception("The action returned null"));
138 return action() ?? Promise.Reject(new Exception("The action returned null"));
139 } catch (Exception err) {
139 } catch (Exception err) {
140 return new FailedPromise(err);
140 return Promise.Reject(err);
141 }
141 }
142 }
142 }
143
143
144 public static void NoWait(IPromise promise) {
144 public static void NoWait(IPromise promise) {
145 }
145 }
146
146
147 [DebuggerStepThrough]
147 [DebuggerStepThrough]
148 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
148 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
149 ArgumentNotNull(action, "action");
149 ArgumentNotNull(action, "action");
150
150
151 try {
151 try {
152 return action() ?? Promise<T>.FromException(new Exception("The action returned null"));
152 return action() ?? Promise.Reject<T>(new Exception("The action returned null"));
153 } catch (Exception err) {
153 } catch (Exception err) {
154 return Promise<T>.FromException(err);
154 return Promise.Reject<T>(err);
155 }
155 }
156 }
156 }
157
157
158 #if NET_4_5
158 #if NET_4_5
159 public static void NoWait(Task t) {
159 public static void NoWait(Task t) {
160 }
160 }
161 #endif
161 #endif
162
162
163 }
163 }
164 }
164 }
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
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
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