Auto status change to "Under Review"
| @@ -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 | |||
| @@ -69,7 +69,7 namespace Implab { | |||||
| 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); | |
| @@ -87,17 +87,6 namespace Implab { | |||||
| 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) { | |
| @@ -3,63 +3,26 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 |
|
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 |
b |
|
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 | } | |
| @@ -7,10 +7,13 namespace Implab { | |||||
| 7 | /// </summary> |
|
7 | /// </summary> | |
| 8 | public class Deferred : IResolvable { |
|
8 | public class Deferred : IResolvable { | |
| 9 |
|
9 | |||
| 10 |
readonly |
|
10 | readonly Promise m_promise; | |
| 11 | readonly IDispatcher m_dispatcher; |
|
11 | readonly IDispatcher m_dispatcher; | |
| 12 |
|
12 | |||
| 13 |
internal Deferred( |
|
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; | |
| @@ -21,11 +24,14 namespace Implab { | |||||
| 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) { | |
| @@ -36,7 +42,7 namespace Implab { | |||||
| 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( |
|
45 | m_dispatcher.Enqueue(Chain, thenable); | |
| 40 | else |
|
46 | else | |
| 41 | Chain(thenable); |
|
47 | Chain(thenable); | |
| 42 | } |
|
48 | } | |
| @@ -3,10 +3,13 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 |
|
6 | readonly Promise<T> m_promise; | |
| 7 | readonly IDispatcher m_dispatcher; |
|
7 | readonly IDispatcher m_dispatcher; | |
| 8 |
|
8 | |||
| 9 |
internal Deferred( |
|
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; | |
| @@ -17,11 +20,14 namespace Implab { | |||||
| 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) { | |
| @@ -32,7 +38,7 namespace Implab { | |||||
| 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( |
|
41 | m_dispatcher.Enqueue(Chain, thenable); | |
| 36 | else |
|
42 | else | |
| 37 | Chain(thenable); |
|
43 | Chain(thenable); | |
| 38 | } |
|
44 | } | |
| @@ -3,5 +3,7 using System; | |||||
| 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 | } | |
| @@ -3,63 +3,48 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( |
|
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 |
|
|
28 | RejectHandler = PromiseHandler.Create(rejected, m_next); | |
| 44 | m_next = next; |
|
|||
| 45 | } |
|
29 | } | |
| 46 |
|
30 | |||
| 47 |
public PromiseActionReaction( |
|
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 |
|
|
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); | |
| @@ -68,21 +53,5 namespace Implab { | |||||
| 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 | } | |
| @@ -3,62 +3,47 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, |
|
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 |
|
|
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 |
|
|
27 | RejectHandler = PromiseHandler.Create(rejected, m_next); | |
| 44 | m_next = next; |
|
|||
| 45 | } |
|
28 | } | |
| 46 |
|
29 | |||
| 47 |
public PromiseActionReaction(Func< |
|
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 |
|
|
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); | |
| @@ -67,21 +52,5 namespace Implab { | |||||
| 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 | |||||
| @@ -2,474 +2,130 | |||||
| 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 |
|
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, |
|
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 |
|
61 | return reaction.Promise; | |
| 237 | } |
|
62 | } | |
| 238 |
|
63 | |||
| 239 |
public static IPromise Then(this IPromise that, |
|
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<T |
|
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 |
|
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> |
|
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 |
|
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> |
|
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 C |
|
106 | public static IPromise Catch(this IPromise that, Action<Exception> rejected) { | |
| 392 |
return |
|
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 |
|
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<T |
|
114 | public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, Tout> rejected) { | |
| 423 |
return |
|
115 | return Then(that, (Func<Tout>)null, rejected); | |
| 424 | } |
|
116 | } | |
| 425 |
|
117 | |||
| 426 |
public static IPromise<T |
|
118 | public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, IPromise<Tout>> rejected) { | |
| 427 |
return |
|
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 | |||
| @@ -3,51 +3,47 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 |
|
|
15 | FulfilHandler = PromiseHandler.Create(fulfilled, m_next); | |
| 15 |
|
16 | |||
| 16 | if (rejected != null) |
|
17 | if (rejected != null) | |
| 17 |
|
|
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, |
|
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 |
|
|
24 | FulfilHandler = PromiseHandler.Create(fulfilled, m_next); | |
|
|
25 | ||||
| 32 | if (rejected != null) |
|
26 | if (rejected != null) | |
| 33 |
|
|
27 | RejectHandler = PromiseHandler.Create(rejected, m_next); | |
| 34 |
|
||||
| 35 | m_next = next; |
|
|||
| 36 | } |
|
28 | } | |
| 37 |
|
29 | |||
| 38 |
public PromiseFuncReaction(Func< |
|
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 |
|
|
33 | FulfilHandler = PromiseHandler.Create(fulfilled, m_next); | |
|
|
34 | ||||
| 41 | if (rejected != null) |
|
35 | if (rejected != null) | |
| 42 |
|
|
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); | |
| @@ -56,21 +52,5 namespace Implab { | |||||
| 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,6 +1,11 | |||||
| 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 | |||
| @@ -8,36 +13,28 namespace Implab { | |||||
| 8 | m_dispatcher = dispatcher; |
|
13 | m_dispatcher = dispatcher; | |
| 9 | } |
|
14 | } | |
| 10 |
|
15 | |||
| 11 |
protected |
|
16 | protected Action FulfilHandler { get; set; } | |
| 12 | get; |
|
|||
| 13 | } |
|
|||
| 14 |
|
17 | |||
| 15 |
protected |
|
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 ( |
|
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( |
|
24 | m_dispatcher.Enqueue(RejectHandler, error); | |
| 24 | else |
|
25 | else | |
| 25 |
Reject |
|
26 | RejectHandler(error); | |
| 26 | } |
|
27 | } | |
| 27 |
|
28 | |||
| 28 | public void Resolve() { |
|
29 | public void Resolve() { | |
| 29 |
if ( |
|
30 | if (FulfilHandler == null) | |
| 30 | DefaultResolve(); |
|
31 | DefaultResolve(); | |
| 31 | else if (m_dispatcher != null) |
|
32 | else if (m_dispatcher != null) | |
| 32 |
m_dispatcher.Enqueue( |
|
33 | m_dispatcher.Enqueue(FulfilHandler); | |
| 33 | else |
|
34 | else | |
| 34 |
|
|
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); | |
| @@ -1,6 +1,11 | |||||
| 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 | |||
| @@ -8,36 +13,28 namespace Implab { | |||||
| 8 | m_dispatcher = dispatcher; |
|
13 | m_dispatcher = dispatcher; | |
| 9 | } |
|
14 | } | |
| 10 |
|
15 | |||
| 11 |
protected |
|
16 | protected Action<T> FulfilHandler { get; set; } | |
| 12 | get; |
|
|||
| 13 | } |
|
|||
| 14 |
|
17 | |||
| 15 |
protected |
|
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 ( |
|
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( |
|
24 | m_dispatcher.Enqueue(RejectHandler, error); | |
| 24 | else |
|
25 | else | |
| 25 |
Reject |
|
26 | RejectHandler(error); | |
| 26 | } |
|
27 | } | |
| 27 |
|
28 | |||
| 28 | public void Resolve(T result) { |
|
29 | public void Resolve(T result) { | |
| 29 |
if ( |
|
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( |
|
33 | m_dispatcher.Enqueue(FulfilHandler, result); | |
| 33 | else |
|
34 | else | |
| 34 |
|
|
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); | |
| @@ -112,9 +112,9 namespace Implab | |||||
| 112 | ArgumentNotNull(action, "action"); |
|
112 | ArgumentNotNull(action, "action"); | |
| 113 |
|
113 | |||
| 114 | try { |
|
114 | try { | |
| 115 |
return Promise |
|
115 | return Promise.Resolve(action()); | |
| 116 | } catch (Exception err) { |
|
116 | } catch (Exception err) { | |
| 117 |
return Promise<T> |
|
117 | return Promise.Reject<T>(err); | |
| 118 | } |
|
118 | } | |
| 119 | } |
|
119 | } | |
| 120 |
|
120 | |||
| @@ -124,9 +124,9 namespace Implab | |||||
| 124 |
|
124 | |||
| 125 | try { |
|
125 | try { | |
| 126 | action(); |
|
126 | action(); | |
| 127 |
return Promise. |
|
127 | return Promise.Resolve(); | |
| 128 | } catch (Exception err) { |
|
128 | } catch (Exception err) { | |
| 129 |
return |
|
129 | return Promise.Reject(err); | |
| 130 | } |
|
130 | } | |
| 131 | } |
|
131 | } | |
| 132 |
|
132 | |||
| @@ -135,9 +135,9 namespace Implab | |||||
| 135 | ArgumentNotNull(action, "action"); |
|
135 | ArgumentNotNull(action, "action"); | |
| 136 |
|
136 | |||
| 137 | try { |
|
137 | try { | |
| 138 |
return action() ?? |
|
138 | return action() ?? Promise.Reject(new Exception("The action returned null")); | |
| 139 | } catch (Exception err) { |
|
139 | } catch (Exception err) { | |
| 140 |
return |
|
140 | return Promise.Reject(err); | |
| 141 | } |
|
141 | } | |
| 142 | } |
|
142 | } | |
| 143 |
|
143 | |||
| @@ -149,9 +149,9 namespace Implab | |||||
| 149 | ArgumentNotNull(action, "action"); |
|
149 | ArgumentNotNull(action, "action"); | |
| 150 |
|
150 | |||
| 151 | try { |
|
151 | try { | |
| 152 |
return action() ?? Promise<T> |
|
152 | return action() ?? Promise.Reject<T>(new Exception("The action returned null")); | |
| 153 | } catch (Exception err) { |
|
153 | } catch (Exception err) { | |
| 154 |
return Promise<T> |
|
154 | return Promise.Reject<T>(err); | |
| 155 | } |
|
155 | } | |
| 156 | } |
|
156 | } | |
| 157 |
|
157 | |||
| 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
ok, latest stable version should be in default
You need to be logged in to leave comments.
Login now
