##// 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 1 using System;
2 2 using Implab.Parallels;
3 3 using System.Threading;
4 4 using System.Reflection;
5 5 using System.Diagnostics;
6 6
7 7 namespace Implab {
8 8 /// <summary>
9 9 /// Abstract class for creation of custom one-shot thread safe events.
10 10 /// </summary>
11 11 /// <remarks>
12 12 /// <para>
13 13 /// An event is something that should happen in the future and the
14 14 /// triggering of the event causes execution of some pending actions
15 15 /// which are formely event handlers. One-shot events occur only once
16 16 /// and any handler added after the event is triggered should run
17 17 /// without a delay.
18 18 /// </para>
19 19 /// <para>
20 20 /// The lifecycle of the one-shot event is tipically consists of following
21 21 /// phases.
22 22 /// <list>
23 23 /// <description>Pending state. This is the initial state of the event. Any
24 24 /// handler added to the event will be queued for the future execution.
25 25 /// </description>
26 26 /// <description>Transitional state. This is intermediate state between pending
27 27 /// and fulfilled states, during this state internal initialization and storing
28 28 /// of the result occurs.
29 29 /// </description>
30 30 /// <description>Fulfilled state. The event contains the result, all queued
31 31 /// handlers are signalled to run and newly added handlers are executed
32 32 /// immediatelly.
33 33 /// </description>
34 34 /// </list>
35 35 /// </para>
36 36 /// </remarks>
37 37 public abstract class AbstractEvent<THandler> where THandler : class {
38 38 const int PendingState = 0;
39 39
40 40 const int TransitionalState = 1;
41 41
42 42 const int ResolvedState = 2;
43 43
44 44 volatile int m_state;
45 45
46 46 THandler m_handler;
47 47 SimpleAsyncQueue<THandler> m_extraHandlers;
48 48
49 49 public bool IsResolved {
50 50 get {
51 51 return m_state > TransitionalState;
52 52 }
53 53 }
54 54
55 55 #region state managment
56 56 protected bool BeginTransit() {
57 57 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
58 58 }
59 59
60 60 protected void CompleteTransit() {
61 61 #if DEBUG
62 62 if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
63 63 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
64 64 #else
65 65 m_state = state;
66 66 #endif
67 67 Signal();
68 68 }
69 69
70 70 protected void WaitTransition() {
71 71 if (m_state == TransitionalState) {
72 SpinWait spin;
72 SpinWait spin = new SpinWait();
73 73 do {
74 74 spin.SpinOnce();
75 75 } while (m_state == TransitionalState);
76 76 }
77 77 }
78 78
79 79
80 80 protected abstract void SignalHandler(THandler handler);
81 81
82 82 void Signal() {
83 83 THandler handler;
84 84 while (TryDequeueHandler(out handler))
85 85 SignalHandler(handler);
86 86 }
87 87
88 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 90 #region handlers managment
102 91
103 92 protected void AddHandler(THandler handler) {
104 93
105 94 if (IsResolved) {
106 95 // the promise is in the resolved state, just invoke the handler
107 96 SignalHandler(handler);
108 97 } else {
109 98 EnqueueHandler(handler);
110 99
111 100 if (IsResolved && TryDequeueHandler(out handler))
112 101 // if the promise have been resolved while we was adding the handler to the queue
113 102 // we can't guarantee that someone is still processing it
114 103 // therefore we need to fetch a handler from the queue and execute it
115 104 // note that fetched handler may be not the one that we have added
116 105 // even we can fetch no handlers at all :)
117 106 SignalHandler(handler);
118 107 }
119 108
120 109 }
121 110
122 111 void EnqueueHandler(THandler handler) {
123 112 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
124 113 if (m_extraHandlers == null)
125 114 // compare-exchange will protect from loosing already created queue
126 115 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
127 116 m_extraHandlers.Enqueue(handler);
128 117 }
129 118 }
130 119
131 120 bool TryDequeueHandler(out THandler handler) {
132 121 handler = Interlocked.Exchange(ref m_handler, null);
133 122 if (handler != null)
134 123 return true;
135 124 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
136 125 }
137 126
138 127 #endregion
139 128 }
140 129 }
141 130
@@ -1,65 +1,28
1 1 using System;
2 2 using System.Threading;
3 3 using Implab.Parallels;
4 4
5 5 namespace Implab {
6 public class CancellationToken : ICancellationToken {
7 const int CANCEL_NOT_REQUESTED = 0;
8 const int CANCEL_REQUESTING = 1;
9 const int CANCEL_REQUESTED = 2;
10
11 volatile int m_state = CANCEL_NOT_REQUESTED;
12
13 Action<Exception> m_handler;
14
15 Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers;
16
17 public bool IsCancellationRequested {
18 get { return m_state == CANCEL_REQUESTED; }
6 /// <summary>
7 /// The cancellation token signals to the worker that cancellation has been
8 /// requested, after the signal is received the worker decides wheather to
9 /// cancel its work or to continue.
10 /// </summary>
11 public class CancellationToken : AbstractEvent<Action<Exception>> {
12 public CancellationToken() {
13
19 14 }
20
21 public Exception CancellationReason {
22 get; set;
23 }
15
16 public void RequestCancellation() {
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) {
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 }
20 public void RequestCancellation(Exception reason) {
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 28 } No newline at end of file
@@ -1,52 +1,58
1 1 using System;
2 2 using System.Diagnostics;
3 3
4 4 namespace Implab {
5 5 /// <summary>
6 6 /// This class is responsible for the promise resolution, dispatching and chaining
7 7 /// </summary>
8 8 public class Deferred : IResolvable {
9 9
10 readonly AbstractPromise m_promise;
10 readonly Promise m_promise;
11 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 17 Debug.Assert(promise != null);
15 18 m_promise = promise;
16 19 m_dispatcher = dispatcher;
17 20 }
18 21
19 22 public IPromise Promise {
20 23 get { return m_promise; }
21 24 }
22 25
23 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 33 public void Resolve() {
28 m_promise.Resolve();
34 m_promise.ResolvePromise();
29 35 }
30 36
31 37 public void Resolve(IPromise thenable) {
32 38 if (thenable == null)
33 39 Reject(new Exception("The promise or task are expected"));
34 40 if (thenable == m_promise)
35 41 Reject(new Exception("The promise cannot be resolved with oneself"));
36 42
37 43 else if (m_dispatcher != null)
38 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 46 else
41 47 Chain(thenable);
42 48 }
43 49
44 50 void Chain(IPromise thenable) {
45 51 try {
46 52 thenable.Then(this);
47 53 } catch (Exception err) {
48 54 Reject(err);
49 55 }
50 56 }
51 57 }
52 58 } No newline at end of file
@@ -1,48 +1,54
1 1 using System;
2 2 using System.Diagnostics;
3 3
4 4 namespace Implab {
5 5 public class Deferred<T> : IResolvable<T> {
6 readonly AbstractPromise<T> m_promise;
6 readonly Promise<T> m_promise;
7 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 13 Debug.Assert(promise != null);
11 14 m_promise = promise;
12 15 m_dispatcher = dispatcher;
13 16 }
14 17
15 18 public IPromise<T> Promise {
16 19 get { return m_promise; }
17 20 }
18 21
19 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 29 public void Resolve(T value) {
24 m_promise.Resolve(value);
30 m_promise.ResolvePromise(value);
25 31 }
26 32
27 33 public void Resolve(IPromise<T> thenable) {
28 34 if (thenable == null)
29 35 Reject(new Exception("The promise or task are expected"));
30 36 if (thenable == m_promise)
31 37 Reject(new Exception("The promise cannot be resolved with oneself"));
32 38
33 39 else if (m_dispatcher != null)
34 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 42 else
37 43 Chain(thenable);
38 44 }
39 45
40 46 void Chain(IPromise<T> thenable) {
41 47 try {
42 48 thenable.Then(this);
43 49 } catch (Exception err) {
44 50 Reject(err);
45 51 }
46 52 }
47 53 }
48 54 } No newline at end of file
@@ -1,7 +1,9
1 1 using System;
2 2
3 3 namespace Implab {
4 4 public interface IDispatcher {
5 5 void Enqueue(Action job);
6
7 void Enqueue<T>(Action<T> job, T arg);
6 8 }
7 9 } No newline at end of file
@@ -1,88 +1,57
1 1 using System;
2 2 using System.Diagnostics;
3 3
4 4 namespace Implab {
5 5 class PromiseActionReaction : PromiseReaction {
6 readonly Action m_fulfilled;
7
8 readonly Action<Exception> m_rejected;
9 6
10 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 15 if (fulfilled != null)
14 m_fulfilled = () => {
15 fulfilled();
16 next.Resolve();
17 };
16 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
18 17
19 18 if (rejected != null)
20 m_rejected = (x) => {
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;
19 RejectHandler = PromiseHandler.Create(rejected, m_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 24 if (fulfilled != null)
37 m_fulfilled = () => {
38 fulfilled();
39 next.Resolve();
40 };
25 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
41 26
42 27 if (rejected != null)
43 m_rejected = (e) => { next.Resolve(rejected(e)); };
44 m_next = next;
28 RejectHandler = PromiseHandler.Create(rejected, m_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 33 if (fulfilled != null)
49 m_fulfilled = () => { next.Resolve(fulfilled()); };
34 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
50 35
51 36 if (rejected != null)
52 m_rejected = (x) => {
53 rejected(x);
54 next.Resolve();
55 };
56 m_next = next;
37 RejectHandler = PromiseHandler.Create(rejected, m_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;
61
62 protected override bool HasRejectHandler => m_rejected != null;
45 if (rejected != null)
46 RejectHandler = PromiseHandler.Create(rejected, m_next);
47 }
63 48
64 49 protected override void DefaultReject(Exception reason) {
65 50 m_next.Reject(reason);
66 51 }
67 52
68 53 protected override void DefaultResolve() {
69 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 57 } No newline at end of file
@@ -1,87 +1,56
1 1 using System;
2 2 using System.Diagnostics;
3 3
4 4 namespace Implab {
5 5 class PromiseActionReaction<T> : PromiseReaction<T> {
6 readonly Action<T> m_fulfilled;
7
8 readonly Action<Exception> m_rejected;
9
10 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 14 if (fulfilled != null)
14 m_fulfilled = (x) => {
15 fulfilled(x);
16 next.Resolve();
17 };
15 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
18 16
19 17 if (rejected != null)
20 m_rejected = (x) => {
21 rejected(x);
22 next.Resolve();
23 };
24 m_next = next;
18 RejectHandler = PromiseHandler.Create(rejected, m_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 23 if (fulfilled != null)
29 m_fulfilled = (x) => { next.Resolve(fulfilled(x)); };
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 };
24 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
41 25
42 26 if (rejected != null)
43 m_rejected = (e) => { next.Resolve(rejected(e)); };
44 m_next = next;
27 RejectHandler = PromiseHandler.Create(rejected, m_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 32 if (fulfilled != null)
49 m_fulfilled = (x) => { next.Resolve(fulfilled(x)); };
33 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
50 34
51 35 if (rejected != null)
52 m_rejected = (x) => {
53 rejected(x);
54 next.Resolve();
55 };
56 m_next = next;
36 RejectHandler = PromiseHandler.Create(rejected, m_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 48 protected override void DefaultReject(Exception reason) {
64 49 m_next.Reject(reason);
65 50 }
66 51
67 52 protected override void DefaultResolve(T result) {
68 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 56 } No newline at end of file
This diff has been collapsed as it changes many lines, (508 lines changed) Show them Hide them
@@ -1,475 +1,131
1 1 using System.Threading;
2 2 using System;
3 3 using Implab.Diagnostics;
4 4 using System.Collections.Generic;
5 using System.Linq;
6
5 using System.Linq;
6
7 7 namespace Implab {
8 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);
16 p.CancellationRequested(that.Cancel);
17
18 that.On(
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;
10 public static IPromise Then(this IPromise that, Action fulfilled, Action<Exception> rejected) {
11 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
12 that.Then(reaction);
13 return reaction.Promise;
57 14 }
58 15
59 /// <summary>
60 /// Adds a cancellation point to the chain of promises. When a cancellation request reaches the cancellation point the operation is
61 /// cancelled immediatelly, and the request is passed towards. If the operation at the higher level can not be cancelled is't result
62 /// will be collected with <paramref name="cleanup"/> callback.
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;
16 public static IPromise Then(this IPromise that, Action fulfilled, Func<Exception, IPromise> rejected) {
17 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
18 that.Then(reaction);
19 return reaction.Promise;
82 20 }
83 21
84 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult, T> callback) {
85 Safe.ArgumentNotNull(that, "that");
86 Safe.ArgumentNotNull(callback, "callback");
87 var op = TraceContext.Instance.CurrentOperation;
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 };
22 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Action<Exception> rejected) {
23 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
24 that.Then(reaction);
25 return reaction.Promise;
98 26 }
99 27
100 static void CancelByTimeoutCallback(object cookie) {
101 ((ICancellable)cookie).Cancel(new TimeoutException());
102 }
103
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;
28 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Func<Exception, IPromise> rejected) {
29 var reaction = new PromiseActionReaction(fulfilled, rejected, Promise.DefaultDispatcher);
30 that.Then(reaction);
31 return reaction.Promise;
115 32 }
116 33
117 public static IPromise PromiseAll(this IEnumerable<IPromise> that) {
118 Safe.ArgumentNotNull(that, "that");
119 return PromiseAll(that.ToList());
120 }
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);
34 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Action<Exception> rejected) {
35 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
36 that.Then(reaction);
37 return reaction.Promise;
129 38 }
130 39
131 public static IPromise PromiseAll(this ICollection<IPromise> that) {
132 Safe.ArgumentNotNull(that, "that");
133
134 int count = that.Count;
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);
40 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Func<Exception, IPromise> rejected) {
41 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
42 that.Then(reaction);
43 return reaction.Promise;
173 44 }
174 45
175 /// <summary>
176 /// Creates a new promise which will be satisfied when all promises are satisfied.
177 /// </summary>
178 /// <typeparam name="T"></typeparam>
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;
46 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Action<Exception> rejected) {
47 var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher);
48 that.Then(reaction);
49 return reaction.Promise;
228 50 }
229 51
230 public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) {
231 Safe.ArgumentNotNull(that, "that");
52 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Func<Exception, IPromise> rejected) {
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);
234 that.On(d.Resolve, d.Reject, d.CancelOperation);
235 d.CancellationRequested(that.Cancel);
236 return d;
58 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, Tout> rejected) {
59 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
60 that.Then(reaction);
61 return reaction.Promise;
237 62 }
238 63
239 public static IPromise Then(this IPromise that, Action success, Action<Exception> error) {
240 return Then(that, success, error, null);
241 }
242
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);
64 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
65 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
66 that.Then(reaction);
67 return reaction.Promise;
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) {
265 Safe.ArgumentNotNull(that, "that");
266 Safe.ArgumentNotNull(success, "success");
267
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);
70 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
71 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
72 that.Then(reaction);
73 return reaction.Promise;
292 74 }
293 75
294 public static IPromise<T> Then<T>(this IPromise<T> that, Action<T> success) {
295 return Then(that, success, null, null);
296 }
297
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);
76 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
77 var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
78 that.Then(reaction);
79 return reaction.Promise;
304 80 }
305 81
306 public static IPromise<T> Always<T>(this IPromise<T> that, Action handler) {
307 Func<Exception, T> errorOrCancel;
308 if (handler != null)
309 errorOrCancel = e => {
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);
82 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, Tout> rejected) {
83 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
84 that.Then(reaction);
85 return reaction.Promise;
324 86 }
325 87
326 public static IPromise Always(this IPromise that, Action handler) {
327 Action<Exception> errorOrCancel;
328 if (handler != null)
329 errorOrCancel = e => {
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);
88 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
89 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
90 that.Then(reaction);
91 return reaction.Promise;
354 92 }
355 93
356 public static IPromise Error(this IPromise that, Action<Exception> handler) {
357 return Error(that, handler, false);
358 }
359
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);
94 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
95 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
96 that.Then(reaction);
97 return reaction.Promise;
371 98 }
372 99
373 public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler) {
374 return Error(that, handler, false);
375 }
376
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);
100 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
101 var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher);
102 that.Then(reaction);
103 return reaction.Promise;
389 104 }
390 105
391 public static IPromise Chain(this IPromise that, Func<IPromise> success) {
392 return Chain(that, success, null, null);
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);
106 public static IPromise Catch(this IPromise that, Action<Exception> rejected) {
107 return Then(that, null, rejected);
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) {
414 Safe.ArgumentNotNull(that, "that");
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;
110 public static IPromise Catch(this IPromise that, Func<Exception, IPromise> rejected) {
111 return Then(that, null, rejected);
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) {
423 return Chain(that, success, error, null);
114 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, Tout> rejected) {
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) {
427 return Chain(that, success, null, null);
428 }
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");
118 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, IPromise<Tout>> rejected) {
119 return Then(that, (Func<Tout>)null, rejected);
120 }
444 121
445 return new PromiseAwaiter<T>(that);
446 }
447
448 public static PromiseAwaiter GetAwaiter(this IPromise that) {
449 Safe.ArgumentNotNull(that, "that");
122 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, Tout> rejected) {
123 return Then(that, (Func<Tin, Tout>)null, rejected);
124 }
450 125
451 return new PromiseAwaiter(that);
452 }
453
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
126 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, IPromise<Tout>> rejected) {
127 return Then(that, (Func<Tin, Tout>)null, rejected);
128 }
473 129 }
474 130 }
475 131
@@ -1,76 +1,56
1 1 using System;
2 2 using System.Diagnostics;
3 3
4 4 namespace Implab {
5 5 class PromiseFuncReaction<TRet> : PromiseReaction {
6 readonly Action m_fulfilled;
7
8 readonly Action<Exception> m_rejected;
9
10 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 14 if (fulfilled != null)
14 m_fulfilled = () => { next.Resolve(fulfilled()); };
15 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
15 16
16 17 if (rejected != null)
17 m_rejected = (e) => { next.Resolve(rejected(e)); };
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;
18 RejectHandler = PromiseHandler.Create(rejected, m_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 23 if (fulfilled != null)
31 m_fulfilled = () => { next.Resolve(fulfilled()); };
24 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
25
32 26 if (rejected != null)
33 m_rejected = (e) => { next.Resolve(rejected(e)); };
34
35 m_next = next;
27 RejectHandler = PromiseHandler.Create(rejected, m_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 32 if (fulfilled != null)
40 m_fulfilled = () => { next.Resolve(fulfilled()); };
33 FulfilHandler = PromiseHandler.Create(fulfilled, m_next);
34
41 35 if (rejected != null)
42 m_rejected = (e) => { next.Resolve(rejected(e)); };
43
44 m_next = next;
36 RejectHandler = PromiseHandler.Create(rejected, m_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;
49
50 protected override bool HasRejectHandler => m_rejected != null;
44 if (rejected != null)
45 RejectHandler = PromiseHandler.Create(rejected, m_next);
46 }
51 47
52 48 protected override void DefaultReject(Exception reason) {
53 49 m_next.Reject(reason);
54 50 }
55 51
56 52 protected override void DefaultResolve() {
57 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 56 } No newline at end of file
@@ -1,45 +1,42
1 1 using System;
2 2
3 3 namespace Implab {
4 /// <summary>
5 /// Базовыйй класс для создания обработчиков результов выполнения обещаний.
6 /// Данный объект связывает обработчик и обешание, при этом для выполнения
7 /// обработчика будет использоваться диспетчер.
8 /// </summary>
4 9 abstract class PromiseReaction : IResolvable {
5 10 readonly IDispatcher m_dispatcher;
6 11
7 12 protected PromiseReaction(IDispatcher dispatcher) {
8 13 m_dispatcher = dispatcher;
9 14 }
10 15
11 protected abstract bool HasFulfilHandler {
12 get;
13 }
16 protected Action FulfilHandler { get; set; }
14 17
15 protected abstract bool HasRejectHandler {
16 get;
17 }
18 protected Action<Exception> RejectHandler { get; set; }
18 19
19 20 public void Reject(Exception error) {
20 if (!HasRejectHandler)
21 if (RejectHandler == null)
21 22 DefaultReject(error);
22 23 else if (m_dispatcher != null)
23 m_dispatcher.Enqueue(() => RejectImpl(error));
24 m_dispatcher.Enqueue(RejectHandler, error);
24 25 else
25 RejectImpl(error);
26 RejectHandler(error);
26 27 }
27 28
28 29 public void Resolve() {
29 if (!HasFulfilHandler)
30 if (FulfilHandler == null)
30 31 DefaultResolve();
31 32 else if (m_dispatcher != null)
32 m_dispatcher.Enqueue(ResolveImpl);
33 m_dispatcher.Enqueue(FulfilHandler);
33 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 38 protected abstract void DefaultResolve();
42 39
43 40 protected abstract void DefaultReject(Exception reason);
44 41 }
45 42 } No newline at end of file
@@ -1,45 +1,42
1 1 using System;
2 2
3 3 namespace Implab {
4 /// <summary>
5 /// Базовыйй класс для создания обработчиков результов выполнения обещаний.
6 /// Данный объект связывает обработчик и обешание, при этом для выполнения
7 /// обработчика будет использоваться диспетчер.
8 /// </summary>
4 9 abstract class PromiseReaction<T> : IResolvable<T> {
5 10 readonly IDispatcher m_dispatcher;
6 11
7 12 protected PromiseReaction(IDispatcher dispatcher) {
8 13 m_dispatcher = dispatcher;
9 14 }
10 15
11 protected abstract bool HasFulfilHandler {
12 get;
13 }
16 protected Action<T> FulfilHandler { get; set; }
14 17
15 protected abstract bool HasRejectHandler {
16 get;
17 }
18 protected Action<Exception> RejectHandler { get; set; }
18 19
19 20 public void Reject(Exception error) {
20 if (!HasRejectHandler)
21 if (RejectHandler == null)
21 22 DefaultReject(error);
22 23 else if (m_dispatcher != null)
23 m_dispatcher.Enqueue(() => RejectImpl(error));
24 m_dispatcher.Enqueue(RejectHandler, error);
24 25 else
25 RejectImpl(error);
26 RejectHandler(error);
26 27 }
27 28
28 29 public void Resolve(T result) {
29 if (!HasFulfilHandler)
30 if (FulfilHandler == null)
30 31 DefaultResolve(result);
31 32 else if (m_dispatcher != null)
32 m_dispatcher.Enqueue(() => ResolveImpl(result));
33 m_dispatcher.Enqueue(FulfilHandler, result);
33 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 38 protected abstract void DefaultResolve(T result);
42 39
43 40 protected abstract void DefaultReject(Exception reason);
44 41 }
45 42 } No newline at end of file
@@ -1,164 +1,164
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Text.RegularExpressions;
6 6 using System.Diagnostics;
7 7 using System.Collections;
8 8 using System.Runtime.CompilerServices;
9 9
10 10 #if NET_4_5
11 11 using System.Threading.Tasks;
12 12 #endif
13 13
14 14 namespace Implab
15 15 {
16 16 public static class Safe
17 17 {
18 18 [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 19 public static void ArgumentAssert(bool condition, string paramName) {
20 20 if (!condition)
21 21 throw new ArgumentException("The parameter is invalid", paramName);
22 22 }
23 23
24 24 [MethodImpl(MethodImplOptions.AggressiveInlining)]
25 25 public static void ArgumentMatch(string value, string paramName, Regex rx) {
26 26 if (rx == null)
27 27 throw new ArgumentNullException("rx");
28 28 if (!rx.IsMatch(value))
29 29 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
30 30 }
31 31
32 32 [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 33 public static void ArgumentNotEmpty(string value, string paramName) {
34 34 if (String.IsNullOrEmpty(value))
35 35 throw new ArgumentException("The parameter can't be empty", paramName);
36 36 }
37 37
38 38 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 39 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
40 40 if (value == null || value.Length == 0)
41 41 throw new ArgumentException("The array must be not emty", paramName);
42 42 }
43 43
44 44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 45 public static void ArgumentNotNull(object value, string paramName) {
46 46 if (value == null)
47 47 throw new ArgumentNullException(paramName);
48 48 }
49 49
50 50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 51 internal static void ArgumentGreaterThan(int value, int min, string paramName) {
52 52 if (value < min)
53 53 throw new ArgumentOutOfRangeException(paramName);
54 54 }
55 55
56 56 [MethodImpl(MethodImplOptions.AggressiveInlining)]
57 57 public static void ArgumentInRange(int value, int min, int max, string paramName) {
58 58 if (value < min || value > max)
59 59 throw new ArgumentOutOfRangeException(paramName);
60 60 }
61 61
62 62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
63 63 public static void ArgumentOfType(object value, Type type, string paramName) {
64 64 if (!type.IsInstanceOfType(value))
65 65 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
66 66 }
67 67
68 68 public static void Dispose(params IDisposable[] objects) {
69 69 foreach (var d in objects)
70 70 if (d != null)
71 71 d.Dispose();
72 72 }
73 73
74 74 public static void Dispose(params object[] objects) {
75 75 foreach (var obj in objects) {
76 76 var d = obj as IDisposable;
77 77 if (d != null)
78 78 d.Dispose();
79 79 }
80 80 }
81 81
82 82 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
83 83 foreach (var d in objects)
84 84 Dispose(d);
85 85 }
86 86
87 87 public static void DisposeCollection(IEnumerable objects) {
88 88 foreach (var d in objects)
89 89 Dispose(d);
90 90 }
91 91
92 92 public static void Dispose(object obj) {
93 93 if (obj is IDisposable)
94 94 Dispose((IDisposable)obj);
95 95
96 96 }
97 97
98 98 [DebuggerStepThrough]
99 99 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
100 100 if (handler != null)
101 101 handler(sender, args);
102 102 }
103 103
104 104 [DebuggerStepThrough]
105 105 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
106 106 if (handler != null)
107 107 handler(sender, args);
108 108 }
109 109
110 110 [DebuggerStepThrough]
111 111 public static IPromise<T> Run<T>(Func<T> action) {
112 112 ArgumentNotNull(action, "action");
113 113
114 114 try {
115 return Promise<T>.FromResult(action());
115 return Promise.Resolve(action());
116 116 } catch (Exception err) {
117 return Promise<T>.FromException(err);
117 return Promise.Reject<T>(err);
118 118 }
119 119 }
120 120
121 121 [DebuggerStepThrough]
122 122 public static IPromise Run(Action action) {
123 123 ArgumentNotNull(action, "action");
124 124
125 125 try {
126 126 action();
127 return Promise.Success;
127 return Promise.Resolve();
128 128 } catch (Exception err) {
129 return new FailedPromise(err);
129 return Promise.Reject(err);
130 130 }
131 131 }
132 132
133 133 [DebuggerStepThrough]
134 134 public static IPromise Run(Func<IPromise> action) {
135 135 ArgumentNotNull(action, "action");
136 136
137 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 139 } catch (Exception err) {
140 return new FailedPromise(err);
140 return Promise.Reject(err);
141 141 }
142 142 }
143 143
144 144 public static void NoWait(IPromise promise) {
145 145 }
146 146
147 147 [DebuggerStepThrough]
148 148 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
149 149 ArgumentNotNull(action, "action");
150 150
151 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 153 } catch (Exception err) {
154 return Promise<T>.FromException(err);
154 return Promise.Reject<T>(err);
155 155 }
156 156 }
157 157
158 158 #if NET_4_5
159 159 public static void NoWait(Task t) {
160 160 }
161 161 #endif
162 162
163 163 }
164 164 }
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 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