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; |
|
|||
14 |
|
||||
15 | Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers; |
|
|||
16 |
|
13 | |||
17 | public bool IsCancellationRequested { |
|
|||
18 | get { return m_state == CANCEL_REQUESTED; } |
|
|||
19 | } |
|
|||
20 |
|
||||
21 | public Exception CancellationReason { |
|
|||
22 | get; set; |
|
|||
23 | } |
|
|||
24 |
|
||||
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 | } |
|
14 | } | |
35 |
|
15 | |||
36 | bool TryDequeueHandler(out Action<Exception> handler) { |
|
16 | public void RequestCancellation() { | |
37 | handler = Interlocked.Exchange(ref m_handler, null); |
|
17 | ||
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 | } |
|
18 | } | |
45 |
|
19 | |||
46 |
void |
|
20 | public void RequestCancellation(Exception reason) { | |
47 | if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) { |
|
21 | ||
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 | } |
|
22 | } | |
54 |
|
23 | |||
55 | void RequestCancellation(Exception reason) { |
|
24 | protected override void SignalHandler(Action<Exception> handler) { | |
56 | if (Interlocked.CompareExchange(ref m_state, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED) == CANCEL_NOT_REQUESTED) { |
|
25 | throw new NotImplementedException(); | |
57 | if (reason == null) |
|
|||
58 | reason = new OperationCanceledException(); |
|
|||
59 | CancellationReason = reason; |
|
|||
60 | m_state = CANCEL_REQUESTED; |
|
|||
61 |
|
|
26 | } | |
62 |
|
|
27 | } | |
63 |
|
||||
64 | } |
|
|||
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 | } |
@@ -6,470 +6,126 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 | } |
|
|||
116 |
|
||||
117 | public static IPromise PromiseAll(this IEnumerable<IPromise> that) { |
|
|||
118 | Safe.ArgumentNotNull(that, "that"); |
|
|||
119 | return PromiseAll(that.ToList()); |
|
|||
120 | } |
|
32 | } | |
121 |
|
33 | |||
122 |
public static IPromise |
|
34 | public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Action<Exception> rejected) { | |
123 | return PromiseAll(that, null); |
|
35 | var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher); | |
124 | } |
|
36 | that.Then(reaction); | |
125 |
|
37 | return reaction.Promise; | ||
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 | } |
|
|||
130 |
|
||||
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 |
|
|
38 | } | |
142 |
|
39 | |||
143 | medium.On(() => { |
|
40 | public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Func<Exception, IPromise> rejected) { | |
144 | foreach (var p2 in that) |
|
41 | var reaction = new PromiseActionReaction<T>(fulfilled, rejected, Promise.DefaultDispatcher); | |
145 | p2.Cancel(); |
|
42 | that.Then(reaction); | |
146 | }, PromiseEventType.ErrorOrCancel); |
|
43 | return reaction.Promise; | |
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 |
|
|
50 | } | |
226 |
|
51 | |||
227 | return medium; |
|
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; | |||
228 | } |
|
56 | } | |
229 |
|
57 | |||
230 |
public static IPromise Then(this IPromise that, |
|
58 | public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, Tout> rejected) { | |
231 | Safe.ArgumentNotNull(that, "that"); |
|
59 | var reaction = new PromiseFuncReaction<Tout>(fulfilled, rejected, Promise.DefaultDispatcher); | |
232 |
|
60 | that.Then(reaction); | ||
233 | var d = new ActionTask(success, error, cancel, false); |
|
61 | return reaction.Promise; | |
234 | that.On(d.Resolve, d.Reject, d.CancelOperation); |
|
|||
235 | d.CancellationRequested(that.Cancel); |
|
|||
236 | return d; |
|
|||
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 | } |
|
|||
372 |
|
||||
373 | public static IPromise<T> Error<T>(this IPromise<T> that, Action<Exception> handler) { |
|
|||
374 | return Error(that, handler, false); |
|
|||
375 | } |
|
98 | } | |
376 |
|
99 | |||
377 | #region chain traits |
|
100 | public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) { | |
378 | public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel) { |
|
101 | var reaction = new PromiseFuncReaction<Tin, Tout>(fulfilled, rejected, Promise.DefaultDispatcher); | |
379 | Safe.ArgumentNotNull(that, "that"); |
|
102 | that.Then(reaction); | |
380 |
|
103 | return reaction.Promise; | ||
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 | } |
|
|||
421 |
|
||||
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); |
|
|||
424 | } |
|
112 | } | |
425 |
|
113 | |||
426 |
public static IPromise<T |
|
114 | public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, Tout> rejected) { | |
427 |
return |
|
115 | return Then(that, (Func<Tout>)null, rejected); | |
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 | } |
|
116 | } | |
439 |
|
117 | |||
440 | #if NET_4_5 |
|
118 | public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, IPromise<Tout>> rejected) { | |
441 |
|
119 | return Then(that, (Func<Tout>)null, rejected); | ||
442 | public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) { |
|
|||
443 | Safe.ArgumentNotNull(that, "that"); |
|
|||
444 |
|
||||
445 | return new PromiseAwaiter<T>(that); |
|
|||
446 | } |
|
|||
447 |
|
||||
448 | public static PromiseAwaiter GetAwaiter(this IPromise that) { |
|
|||
449 | Safe.ArgumentNotNull(that, "that"); |
|
|||
450 |
|
||||
451 | return new PromiseAwaiter(that); |
|
|||
452 | } |
|
120 | } | |
453 |
|
121 | |||
454 |
public static IPromise |
|
122 | public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, Tout> rejected) { | |
455 | Safe.ArgumentNotNull(that, "that"); |
|
123 | return Then(that, (Func<Tin, Tout>)null, rejected); | |
456 | ct.Register(that.Cancel); |
|
|||
457 | return that.Then(null, null, (err) => { |
|
|||
458 | ct.ThrowIfCancellationRequested(); |
|
|||
459 | throw new PromiseTransientException(err); |
|
|||
460 | }); |
|
|||
461 | } |
|
124 | } | |
462 |
|
125 | |||
463 |
public static IPromise<T> |
|
126 | public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, IPromise<Tout>> rejected) { | |
464 | Safe.ArgumentNotNull(that, "that"); |
|
127 | return Then(that, (Func<Tin, Tout>)null, rejected); | |
465 | ct.Register(that.Cancel); |
|
|||
466 | return that.Then(null, null, (err) => { |
|
|||
467 | ct.ThrowIfCancellationRequested(); |
|
|||
468 | throw new PromiseTransientException(err); |
|
|||
469 | }); |
|
|||
470 | } |
|
128 | } | |
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