##// END OF EJS Templates
code cleanup...
cin -
r101:279e226dffdd v2
parent child
Show More
@@ -1,86 +1,86
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5
5
6 namespace Implab {
6 namespace Implab {
7 public interface IPromise: ICancellable {
7 public interface IPromise: ICancellable {
8 /// <summary>
8 /// <summary>
9 /// Check whereather the promise has no more than one dependent promise.
9 /// Check whereather the promise has no more than one dependent promise.
10 /// </summary>
10 /// </summary>
11 bool IsExclusive {
11 bool IsExclusive {
12 get;
12 get;
13 }
13 }
14
14
15 /// <summary>
15 /// <summary>
16 /// Тип результата, получаемого через данное обещание.
16 /// Тип результата, получаемого через данное обещание.
17 /// </summary>
17 /// </summary>
18 Type PromiseType { get; }
18 Type PromiseType { get; }
19
19
20 /// <summary>
20 /// <summary>
21 /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено.
21 /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено.
22 /// </summary>
22 /// </summary>
23 bool IsResolved { get; }
23 bool IsResolved { get; }
24
24
25 /// <summary>
25 /// <summary>
26 /// Обещание было отменено.
26 /// Обещание было отменено.
27 /// </summary>
27 /// </summary>
28 bool IsCancelled { get; }
28 bool IsCancelled { get; }
29
29
30 IPromise Then(Action success, ErrorHandler error, Action cancel);
30 IPromise Then(Action success, Action<Exception> error, Action cancel);
31 IPromise Then(Action success, ErrorHandler error);
31 IPromise Then(Action success, Action<Exception> error);
32 IPromise Then(Action success);
32 IPromise Then(Action success);
33
33
34 IPromise Chain(Func<IPromise> chained, ErrorHandler<IPromise> error, Action cancel);
34 IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error, Action cancel);
35 IPromise Chain(Func<IPromise> chained, ErrorHandler<IPromise> error);
35 IPromise Chain(Func<IPromise> chained, Func<Exception, IPromise> error);
36 IPromise Chain(Func<IPromise> chained);
36 IPromise Chain(Func<IPromise> chained);
37
37
38 /// <summary>
38 /// <summary>
39 /// Добавляет последнй обработчик в цепочку обещаний, не создает промежуточных обещаний.
39 /// Добавляет последнй обработчик в цепочку обещаний, не создает промежуточных обещаний.
40 /// </summary>
40 /// </summary>
41 /// <param name="success">Success.</param>
41 /// <param name="success">Success.</param>
42 /// <param name="error">Error.</param>
42 /// <param name="error">Error.</param>
43 /// <param name="cancel">Cancel.</param>
43 /// <param name="cancel">Cancel.</param>
44 void Last(Action success, ErrorHandler error, Action cancel);
44 void Last(Action success, Action<Exception> error, Action cancel);
45 void Last(Action success, ErrorHandler error);
45 void Last(Action success, Action<Exception> error);
46 void Last(Action success);
46 void Last(Action success);
47
47
48 IPromise Error(ErrorHandler error);
48 IPromise Error(Action<Exception> error);
49 /// <summary>
49 /// <summary>
50 /// Обрабатывает либо ошибку, либо результат. Событие отмены не обрабатывается.
50 /// Обрабатывает либо ошибку, либо результат, либо отмену.
51 /// </summary>
51 /// </summary>
52 /// <param name="handler">Обработчик.</param>
52 /// <param name="handler">Обработчик.</param>
53 /// <remarks>После обработке ошибки, она передается дальше.</remarks>
53 /// <remarks>После обработке ошибки, она передается дальше.</remarks>
54 /// <summary>
54 /// <summary>
55 /// Обрабатывает либо ошибку, либо результат, либо отмену обещания.
55 /// Обрабатывает либо ошибку, либо результат, либо отмену обещания.
56 /// </summary>
56 /// </summary>
57 /// <param name="handler">Обработчик.</param>
57 /// <param name="handler">Обработчик.</param>
58 /// <remarks>После обработке ошибки, она передается дальше.</remarks>
58 /// <remarks>После обработке ошибки, она передается дальше.</remarks>
59 IPromise Anyway(Action handler);
59 IPromise Anyway(Action handler);
60 /// <summary>
60 /// <summary>
61 /// Обработчик для регистрации отмены обещания, событие отмены не может быть подавлено.
61 /// Обработчик для регистрации отмены обещания.
62 /// </summary>
62 /// </summary>
63 /// <returns>Новое обещание, связанное с текущим.</returns>
63 /// <returns>Новое обещание, связанное с текущим, выполнится после указанного обработчика.</returns>
64 /// <param name="handler">Обработчик события.</param>
64 /// <param name="handler">Обработчик события.</param>
65 /// <remarks>Если обработчик вызывает исключение, то оно передается обработчику ошибки, результат работы
65 /// <remarks>Если обработчик вызывает исключение, то оно передается обработчику ошибки, результат работы
66 /// которого будет передан связанному обещанию</remarks>
66 /// которого будет передан связанному обещанию</remarks>
67 IPromise Cancelled(Action handler);
67 IPromise Cancelled(Action handler);
68
68
69 /// <summary>
69 /// <summary>
70 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
70 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
71 /// </summary>
71 /// </summary>
72 IPromise<T> Cast<T>();
72 IPromise<T> Cast<T>();
73
73
74 /// <summary>
74 /// <summary>
75 /// Синхронизирует текущий поток с обещанием.
75 /// Синхронизирует текущий поток с обещанием.
76 /// </summary>
76 /// </summary>
77 void Join();
77 void Join();
78 /// <summary>
78 /// <summary>
79 /// Синхронизирует текущий поток с обещанием.
79 /// Синхронизирует текущий поток с обещанием.
80 /// </summary>
80 /// </summary>
81 /// <param name="timeout">Время ожидания, по его истечению возникнет исключение.</param>
81 /// <param name="timeout">Время ожидания, по его истечению возникнет исключение.</param>
82 /// <exception cref="TimeoutException">Превышено время ожидания.</exception>
82 /// <exception cref="TimeoutException">Превышено время ожидания.</exception>
83 void Join(int timeout);
83 void Join(int timeout);
84
84
85 }
85 }
86 }
86 }
@@ -1,40 +1,40
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public interface IPromise<T> : IPromise {
4 public interface IPromise<T> : IPromise {
5
5
6 new T Join();
6 new T Join();
7
7
8 new T Join(int timeout);
8 new T Join(int timeout);
9
9
10 void Last(ResultHandler<T> success, ErrorHandler error, Action cancel);
10 void Last(Action<T> success, Action<Exception> error, Action cancel);
11
11
12 void Last(ResultHandler<T> success, ErrorHandler error);
12 void Last(Action<T> success, Action<Exception> error);
13
13
14 void Last(ResultHandler<T> success);
14 void Last(Action<T> success);
15
15
16 IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel);
16 IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel);
17
17
18 IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error);
18 IPromise<T> Then(Action<T> success, Func<Exception,T> error);
19
19
20 IPromise<T> Then(ResultHandler<T> success);
20 IPromise<T> Then(Action<T> success);
21
21
22 IPromise<T2> Then<T2>(ResultMapper<T, T2> mapper, ErrorHandler<T2> error, Action cancel);
22 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error, Action cancel);
23
23
24 IPromise<T2> Then<T2>(ResultMapper<T, T2> mapper, ErrorHandler<T2> error);
24 IPromise<T2> Then<T2>(Func<T, T2> mapper, Func<Exception,T2> error);
25
25
26 IPromise<T2> Then<T2>(ResultMapper<T, T2> mapper);
26 IPromise<T2> Then<T2>(Func<T, T2> mapper);
27
27
28 IPromise<T2> Chain<T2>(ResultMapper<T, IPromise<T2>> chained, ErrorHandler<IPromise<T2>> error, Action cancel);
28 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception,IPromise<T2>> error, Action cancel);
29
29
30 IPromise<T2> Chain<T2>(ResultMapper<T, IPromise<T2>> chained, ErrorHandler<IPromise<T2>> error);
30 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained, Func<Exception,IPromise<T2>> error);
31
31
32 IPromise<T2> Chain<T2>(ResultMapper<T, IPromise<T2>> chained);
32 IPromise<T2> Chain<T2>(Func<T, IPromise<T2>> chained);
33
33
34 IPromise<T> Error(ErrorHandler<T> error);
34 IPromise<T> Error(Func<Exception,T> error);
35
35
36 new IPromise<T> Cancelled(Action handler);
36 new IPromise<T> Cancelled(Action handler);
37
37
38 new IPromise<T> Anyway(Action handler);
38 new IPromise<T> Anyway(Action handler);
39 }
39 }
40 }
40 }
@@ -1,210 +1,207
1 using Implab.Diagnostics;
1 using Implab.Diagnostics;
2 using System;
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
3 using System.Diagnostics;
5 using System.Linq;
6 using System.Text;
7 using System.Threading;
4 using System.Threading;
8
5
9 namespace Implab.Parallels {
6 namespace Implab.Parallels {
10 public static class ArrayTraits {
7 public static class ArrayTraits {
11 class ArrayIterator<TSrc> : DispatchPool<int> {
8 class ArrayIterator<TSrc> : DispatchPool<int> {
12 readonly Action<TSrc> m_action;
9 readonly Action<TSrc> m_action;
13 readonly TSrc[] m_source;
10 readonly TSrc[] m_source;
14 readonly Promise<int> m_promise = new Promise<int>();
11 readonly Promise<int> m_promise = new Promise<int>();
15 readonly LogicalOperation m_logicalOperation;
12 readonly LogicalOperation m_logicalOperation;
16
13
17 int m_pending;
14 int m_pending;
18 int m_next;
15 int m_next;
19
16
20 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
17 public ArrayIterator(TSrc[] source, Action<TSrc> action, int threads)
21 : base(threads) {
18 : base(threads) {
22
19
23 Debug.Assert(source != null);
20 Debug.Assert(source != null);
24 Debug.Assert(action != null);
21 Debug.Assert(action != null);
25
22
26 m_logicalOperation = TraceContext.Instance.CurrentOperation;
23 m_logicalOperation = TraceContext.Instance.CurrentOperation;
27 m_next = 0;
24 m_next = 0;
28 m_source = source;
25 m_source = source;
29 m_pending = source.Length;
26 m_pending = source.Length;
30 m_action = action;
27 m_action = action;
31
28
32 m_promise.Anyway(Dispose);
29 m_promise.Anyway(Dispose);
33
30
34 InitPool();
31 InitPool();
35 }
32 }
36
33
37 public Promise<int> Promise {
34 public Promise<int> Promise {
38 get {
35 get {
39 return m_promise;
36 return m_promise;
40 }
37 }
41 }
38 }
42
39
43 protected override void Worker() {
40 protected override void Worker() {
44 TraceContext.Instance.EnterLogicalOperation(m_logicalOperation, false);
41 TraceContext.Instance.EnterLogicalOperation(m_logicalOperation, false);
45 try {
42 try {
46 base.Worker();
43 base.Worker();
47 } finally {
44 } finally {
48 TraceContext.Instance.Leave();
45 TraceContext.Instance.Leave();
49 }
46 }
50 }
47 }
51
48
52 protected override bool TryDequeue(out int unit) {
49 protected override bool TryDequeue(out int unit) {
53 unit = Interlocked.Increment(ref m_next) - 1;
50 unit = Interlocked.Increment(ref m_next) - 1;
54 return unit < m_source.Length;
51 return unit < m_source.Length;
55 }
52 }
56
53
57 protected override void InvokeUnit(int unit) {
54 protected override void InvokeUnit(int unit) {
58 try {
55 try {
59 m_action(m_source[unit]);
56 m_action(m_source[unit]);
60 var pending = Interlocked.Decrement(ref m_pending);
57 var pending = Interlocked.Decrement(ref m_pending);
61 if (pending == 0)
58 if (pending == 0)
62 m_promise.Resolve(m_source.Length);
59 m_promise.Resolve(m_source.Length);
63 } catch (Exception e) {
60 } catch (Exception e) {
64 m_promise.Reject(e);
61 m_promise.Reject(e);
65 }
62 }
66 }
63 }
67 }
64 }
68
65
69 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
66 class ArrayMapper<TSrc, TDst>: DispatchPool<int> {
70 readonly Func<TSrc, TDst> m_transform;
67 readonly Func<TSrc, TDst> m_transform;
71 readonly TSrc[] m_source;
68 readonly TSrc[] m_source;
72 readonly TDst[] m_dest;
69 readonly TDst[] m_dest;
73 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
70 readonly Promise<TDst[]> m_promise = new Promise<TDst[]>();
74 readonly LogicalOperation m_logicalOperation;
71 readonly LogicalOperation m_logicalOperation;
75
72
76 int m_pending;
73 int m_pending;
77 int m_next;
74 int m_next;
78
75
79 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
76 public ArrayMapper(TSrc[] source, Func<TSrc, TDst> transform, int threads)
80 : base(threads) {
77 : base(threads) {
81
78
82 Debug.Assert (source != null);
79 Debug.Assert (source != null);
83 Debug.Assert( transform != null);
80 Debug.Assert( transform != null);
84
81
85 m_next = 0;
82 m_next = 0;
86 m_source = source;
83 m_source = source;
87 m_dest = new TDst[source.Length];
84 m_dest = new TDst[source.Length];
88 m_pending = source.Length;
85 m_pending = source.Length;
89 m_transform = transform;
86 m_transform = transform;
90 m_logicalOperation = TraceContext.Instance.CurrentOperation;
87 m_logicalOperation = TraceContext.Instance.CurrentOperation;
91
88
92 m_promise.Anyway(Dispose);
89 m_promise.Anyway(Dispose);
93
90
94 InitPool();
91 InitPool();
95 }
92 }
96
93
97 public Promise<TDst[]> Promise {
94 public Promise<TDst[]> Promise {
98 get {
95 get {
99 return m_promise;
96 return m_promise;
100 }
97 }
101 }
98 }
102
99
103 protected override void Worker() {
100 protected override void Worker() {
104 TraceContext.Instance.EnterLogicalOperation(m_logicalOperation,false);
101 TraceContext.Instance.EnterLogicalOperation(m_logicalOperation,false);
105 try {
102 try {
106 base.Worker();
103 base.Worker();
107 } finally {
104 } finally {
108 TraceContext.Instance.Leave();
105 TraceContext.Instance.Leave();
109 }
106 }
110 }
107 }
111
108
112 protected override bool TryDequeue(out int unit) {
109 protected override bool TryDequeue(out int unit) {
113 unit = Interlocked.Increment(ref m_next) - 1;
110 unit = Interlocked.Increment(ref m_next) - 1;
114 return unit < m_source.Length;
111 return unit < m_source.Length;
115 }
112 }
116
113
117 protected override void InvokeUnit(int unit) {
114 protected override void InvokeUnit(int unit) {
118 try {
115 try {
119 m_dest[unit] = m_transform(m_source[unit]);
116 m_dest[unit] = m_transform(m_source[unit]);
120 var pending = Interlocked.Decrement(ref m_pending);
117 var pending = Interlocked.Decrement(ref m_pending);
121 if (pending == 0)
118 if (pending == 0)
122 m_promise.Resolve(m_dest);
119 m_promise.Resolve(m_dest);
123 } catch (Exception e) {
120 } catch (Exception e) {
124 m_promise.Reject(e);
121 m_promise.Reject(e);
125 }
122 }
126 }
123 }
127 }
124 }
128
125
129 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
126 public static IPromise<TDst[]> ParallelMap<TSrc, TDst> (this TSrc[] source, Func<TSrc,TDst> transform, int threads) {
130 if (source == null)
127 if (source == null)
131 throw new ArgumentNullException("source");
128 throw new ArgumentNullException("source");
132 if (transform == null)
129 if (transform == null)
133 throw new ArgumentNullException("transform");
130 throw new ArgumentNullException("transform");
134
131
135 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
132 var mapper = new ArrayMapper<TSrc, TDst>(source, transform, threads);
136 return mapper.Promise;
133 return mapper.Promise;
137 }
134 }
138
135
139 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
136 public static IPromise<int> ParallelForEach<TSrc>(this TSrc[] source, Action<TSrc> action, int threads) {
140 if (source == null)
137 if (source == null)
141 throw new ArgumentNullException("source");
138 throw new ArgumentNullException("source");
142 if (action == null)
139 if (action == null)
143 throw new ArgumentNullException("action");
140 throw new ArgumentNullException("action");
144
141
145 var iter = new ArrayIterator<TSrc>(source, action, threads);
142 var iter = new ArrayIterator<TSrc>(source, action, threads);
146 return iter.Promise;
143 return iter.Promise;
147 }
144 }
148
145
149 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, ResultMapper<TSrc, IPromise<TDst>> transform, int threads) {
146 public static IPromise<TDst[]> ChainedMap<TSrc, TDst>(this TSrc[] source, Func<TSrc, IPromise<TDst>> transform, int threads) {
150 if (source == null)
147 if (source == null)
151 throw new ArgumentNullException("source");
148 throw new ArgumentNullException("source");
152 if (transform == null)
149 if (transform == null)
153 throw new ArgumentNullException("transform");
150 throw new ArgumentNullException("transform");
154 if (threads <= 0)
151 if (threads <= 0)
155 throw new ArgumentOutOfRangeException("Threads number must be greater then zero");
152 throw new ArgumentOutOfRangeException("threads","Threads number must be greater then zero");
156
153
157 if (source.Length == 0)
154 if (source.Length == 0)
158 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
155 return Promise<TDst[]>.ResultToPromise(new TDst[0]);
159
156
160 var promise = new Promise<TDst[]>();
157 var promise = new Promise<TDst[]>();
161 var res = new TDst[source.Length];
158 var res = new TDst[source.Length];
162 var pending = source.Length;
159 var pending = source.Length;
163
160
164 object locker = new object();
161 object locker = new object();
165 int slots = threads;
162 int slots = threads;
166
163
167 // Analysis disable AccessToDisposedClosure
164 // Analysis disable AccessToDisposedClosure
168 AsyncPool.InvokeNewThread(() => {
165 AsyncPool.InvokeNewThread(() => {
169 for (int i = 0; i < source.Length; i++) {
166 for (int i = 0; i < source.Length; i++) {
170 if(promise.IsResolved)
167 if(promise.IsResolved)
171 break; // stop processing in case of error or cancellation
168 break; // stop processing in case of error or cancellation
172 var idx = i;
169 var idx = i;
173
170
174 if (Interlocked.Decrement(ref slots) < 0) {
171 if (Interlocked.Decrement(ref slots) < 0) {
175 lock(locker) {
172 lock(locker) {
176 while(slots < 0)
173 while(slots < 0)
177 Monitor.Wait(locker);
174 Monitor.Wait(locker);
178 }
175 }
179 }
176 }
180
177
181 try {
178 try {
182 transform(source[i])
179 transform(source[i])
183 .Anyway(() => {
180 .Anyway(() => {
184 Interlocked.Increment(ref slots);
181 Interlocked.Increment(ref slots);
185 lock (locker) {
182 lock (locker) {
186 Monitor.Pulse(locker);
183 Monitor.Pulse(locker);
187 }
184 }
188 })
185 })
189 .Last(
186 .Last(
190 x => {
187 x => {
191 res[idx] = x;
188 res[idx] = x;
192 var left = Interlocked.Decrement(ref pending);
189 var left = Interlocked.Decrement(ref pending);
193 if (left == 0)
190 if (left == 0)
194 promise.Resolve(res);
191 promise.Resolve(res);
195 },
192 },
196 promise.Reject
193 promise.Reject
197 );
194 );
198
195
199 } catch (Exception e) {
196 } catch (Exception e) {
200 promise.Reject(e);
197 promise.Reject(e);
201 }
198 }
202 }
199 }
203 return 0;
200 return 0;
204 });
201 });
205
202
206 return promise;
203 return promise;
207 }
204 }
208
205
209 }
206 }
210 }
207 }
@@ -1,914 +1,908
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Reflection;
3 using System.Reflection;
4 using System.Diagnostics;
5 using System.Threading;
4 using System.Threading;
6 using Implab.Parallels;
5 using Implab.Parallels;
7
6
8 namespace Implab {
7 namespace Implab {
9
8
10 public delegate void ErrorHandler(Exception e);
11 public delegate T ErrorHandler<out T>(Exception e);
12 public delegate void ResultHandler<in T>(T result);
13 public delegate TNew ResultMapper<in TSrc,out TNew>(TSrc result);
14
15 /// <summary>
9 /// <summary>
16 /// Класс для асинхронного получения результатов. Так называемое "обещание".
10 /// Класс для асинхронного получения результатов. Так называемое "обещание".
17 /// </summary>
11 /// </summary>
18 /// <typeparam name="T">Тип получаемого результата</typeparam>
12 /// <typeparam name="T">Тип получаемого результата</typeparam>
19 /// <remarks>
13 /// <remarks>
20 /// <para>Сервис при обращении к его методу дает обещаиние о выполнении операции,
14 /// <para>Сервис при обращении к его методу дает обещаиние о выполнении операции,
21 /// клиент получив такое обещание может установить ряд обратных вызово для получения
15 /// клиент получив такое обещание может установить ряд обратных вызово для получения
22 /// событий выполнения обещания, тоесть завершения операции и предоставлении результатов.</para>
16 /// событий выполнения обещания, тоесть завершения операции и предоставлении результатов.</para>
23 /// <para>
17 /// <para>
24 /// Обещение может быть как выполнено, так и выполнено с ошибкой. Для подписки на
18 /// Обещение может быть как выполнено, так и выполнено с ошибкой. Для подписки на
25 /// данные события клиент должен использовать методы <c>Then</c>.
19 /// данные события клиент должен использовать методы <c>Then</c>.
26 /// </para>
20 /// </para>
27 /// <para>
21 /// <para>
28 /// Сервис, в свою очередь, по окончанию выполнения операции (возможно с ошибкой),
22 /// Сервис, в свою очередь, по окончанию выполнения операции (возможно с ошибкой),
29 /// использует методы <c>Resolve</c> либо <c>Reject</c> для оповещения клиетна о
23 /// использует методы <c>Resolve</c> либо <c>Reject</c> для оповещения клиетна о
30 /// выполнении обещания.
24 /// выполнении обещания.
31 /// </para>
25 /// </para>
32 /// <para>
26 /// <para>
33 /// Если сервер успел выполнить обещание еще до того, как клиент на него подписался,
27 /// Если сервер успел выполнить обещание еще до того, как клиент на него подписался,
34 /// то в момент подписки клиента будут вызваны соответсвующие события в синхронном
28 /// то в момент подписки клиента будут вызваны соответсвующие события в синхронном
35 /// режиме и клиент будет оповещен в любом случае. Иначе, обработчики добавляются в
29 /// режиме и клиент будет оповещен в любом случае. Иначе, обработчики добавляются в
36 /// список в порядке подписания и в этом же порядке они будут вызваны при выполнении
30 /// список в порядке подписания и в этом же порядке они будут вызваны при выполнении
37 /// обещания.
31 /// обещания.
38 /// </para>
32 /// </para>
39 /// <para>
33 /// <para>
40 /// Обрабатывая результаты обещания можно преобразовывать результаты либо инициировать
34 /// Обрабатывая результаты обещания можно преобразовывать результаты либо инициировать
41 /// связанные асинхронные операции, которые также возвращают обещания. Для этого следует
35 /// связанные асинхронные операции, которые также возвращают обещания. Для этого следует
42 /// использовать соответствующую форму методе <c>Then</c>.
36 /// использовать соответствующую форму методе <c>Then</c>.
43 /// </para>
37 /// </para>
44 /// <para>
38 /// <para>
45 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать
39 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать
46 /// только инициатор обещания иначе могут возникнуть противоречия.
40 /// только инициатор обещания иначе могут возникнуть противоречия.
47 /// </para>
41 /// </para>
48 /// </remarks>
42 /// </remarks>
49 public class Promise<T> : IPromise<T> {
43 public class Promise<T> : IPromise<T> {
50
44
51 protected struct HandlerDescriptor {
45 protected struct HandlerDescriptor {
52 public ResultHandler<T> resultHandler;
46 public Action<T> resultHandler;
53 public ErrorHandler<T> errorHandler;
47 public Func<Exception,T> errorHandler;
54 public Action cancellHandler;
48 public Action cancellHandler;
55 public Promise<T> medium;
49 public Promise<T> medium;
56
50
57 public void Resolve(T result) {
51 public void Resolve(T result) {
58 if (resultHandler != null) {
52 if (resultHandler != null) {
59 try {
53 try {
60 resultHandler(result);
54 resultHandler(result);
61 } catch (Exception e) {
55 } catch (Exception e) {
62 Reject(e);
56 Reject(e);
63 return;
57 return;
64 }
58 }
65 }
59 }
66 if (medium != null)
60 if (medium != null)
67 medium.Resolve(result);
61 medium.Resolve(result);
68 }
62 }
69
63
70 public void Reject(Exception err) {
64 public void Reject(Exception err) {
71 if (errorHandler != null) {
65 if (errorHandler != null) {
72 try {
66 try {
73 var res = errorHandler(err);
67 var res = errorHandler(err);
74 if (medium != null)
68 if (medium != null)
75 medium.Resolve(res);
69 medium.Resolve(res);
76 /*} catch (TransientPromiseException err2) {
70 /*} catch (TransientPromiseException err2) {
77 if (medium != null)
71 if (medium != null)
78 medium.Reject(err2.InnerException);*/
72 medium.Reject(err2.InnerException);*/
79 } catch (Exception err2) {
73 } catch (Exception err2) {
80 if (medium != null)
74 if (medium != null)
81 medium.Reject(err2);
75 medium.Reject(err2);
82 }
76 }
83 } else if (medium != null)
77 } else if (medium != null)
84 medium.Reject(err);
78 medium.Reject(err);
85 }
79 }
86
80
87 public void Cancel() {
81 public void Cancel() {
88 if (cancellHandler != null) {
82 if (cancellHandler != null) {
89 try {
83 try {
90 cancellHandler();
84 cancellHandler();
91 } catch (Exception err) {
85 } catch (Exception err) {
92 Reject(err);
86 Reject(err);
93 return;
87 return;
94 }
88 }
95 }
89 }
96 if (medium != null)
90 if (medium != null)
97 medium.Cancel();
91 medium.Cancel();
98 }
92 }
99 }
93 }
100
94
101 const int UNRESOLVED_SATE = 0;
95 const int UNRESOLVED_SATE = 0;
102 const int TRANSITIONAL_STATE = 1;
96 const int TRANSITIONAL_STATE = 1;
103 const int SUCCEEDED_STATE = 2;
97 const int SUCCEEDED_STATE = 2;
104 const int REJECTED_STATE = 3;
98 const int REJECTED_STATE = 3;
105 const int CANCELLED_STATE = 4;
99 const int CANCELLED_STATE = 4;
106
100
107 readonly bool m_cancellable;
101 int m_childrenCount;
108
109 int m_childrenCount = 0;
110 int m_state;
102 int m_state;
111 T m_result;
103 T m_result;
112 Exception m_error;
104 Exception m_error;
113
105
114 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
106 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
115
107
116 public Promise() {
108 public Promise() {
117 m_cancellable = true;
118 }
109 }
119
110
120 public Promise(IPromise parent, bool cancellable) {
111 public Promise(IPromise parent) {
121 m_cancellable = cancellable;
122 if (parent != null)
112 if (parent != null)
123 AddHandler(
113 AddHandler(
124 null,
114 null,
125 null,
115 null,
126 () => {
116 () => {
127 if (parent.IsExclusive)
117 if (parent.IsExclusive)
128 parent.Cancel();
118 parent.Cancel();
129 },
119 },
130 null
120 null
131 );
121 );
132 }
122 }
133
123
134 bool BeginTransit() {
124 bool BeginTransit() {
135 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
125 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
136 }
126 }
137
127
138 void CompleteTransit(int state) {
128 void CompleteTransit(int state) {
139 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
129 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
140 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
130 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
141 }
131 }
142
132
143 void WaitTransition() {
133 void WaitTransition() {
144 while (m_state == TRANSITIONAL_STATE) {
134 while (m_state == TRANSITIONAL_STATE) {
145 Thread.MemoryBarrier();
135 Thread.MemoryBarrier();
146 }
136 }
147 }
137 }
148
138
149 public bool IsResolved {
139 public bool IsResolved {
150 get {
140 get {
151 Thread.MemoryBarrier();
141 Thread.MemoryBarrier();
152 return m_state > 1;
142 return m_state > 1;
153 }
143 }
154 }
144 }
155
145
156 public bool IsCancelled {
146 public bool IsCancelled {
157 get {
147 get {
158 Thread.MemoryBarrier();
148 Thread.MemoryBarrier();
159 return m_state == CANCELLED_STATE;
149 return m_state == CANCELLED_STATE;
160 }
150 }
161 }
151 }
162
152
163 public Type PromiseType {
153 public Type PromiseType {
164 get { return typeof(T); }
154 get { return typeof(T); }
165 }
155 }
166
156
167 /// <summary>
157 /// <summary>
168 /// Выполняет обещание, сообщая об успешном выполнении.
158 /// Выполняет обещание, сообщая об успешном выполнении.
169 /// </summary>
159 /// </summary>
170 /// <param name="result">Результат выполнения.</param>
160 /// <param name="result">Результат выполнения.</param>
171 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
161 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
172 public void Resolve(T result) {
162 public void Resolve(T result) {
173 if (BeginTransit()) {
163 if (BeginTransit()) {
174 m_result = result;
164 m_result = result;
175 CompleteTransit(SUCCEEDED_STATE);
165 CompleteTransit(SUCCEEDED_STATE);
176 OnStateChanged();
166 OnStateChanged();
177 } else {
167 } else {
178 WaitTransition();
168 WaitTransition();
179 if (m_state != CANCELLED_STATE)
169 if (m_state != CANCELLED_STATE)
180 throw new InvalidOperationException("The promise is already resolved");
170 throw new InvalidOperationException("The promise is already resolved");
181 }
171 }
182 }
172 }
183
173
184 /// <summary>
174 /// <summary>
185 /// Выполняет обещание, сообщая об успешном выполнении. Результатом выполнения будет пустое значения.
175 /// Выполняет обещание, сообщая об успешном выполнении. Результатом выполнения будет пустое значения.
186 /// </summary>
176 /// </summary>
187 /// <remarks>
177 /// <remarks>
188 /// Данный вариант удобен в случаях, когда интересен факт выполнения операции, нежели полученное значение.
178 /// Данный вариант удобен в случаях, когда интересен факт выполнения операции, нежели полученное значение.
189 /// </remarks>
179 /// </remarks>
190 public void Resolve() {
180 public void Resolve() {
191 Resolve(default(T));
181 Resolve(default(T));
192 }
182 }
193
183
194 /// <summary>
184 /// <summary>
195 /// Выполняет обещание, сообщая об ошибке
185 /// Выполняет обещание, сообщая об ошибке
196 /// </summary>
186 /// </summary>
197 /// <remarks>
187 /// <remarks>
198 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
188 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
199 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
189 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
200 /// будут проигнорированы.
190 /// будут проигнорированы.
201 /// </remarks>
191 /// </remarks>
202 /// <param name="error">Исключение возникшее при выполнении операции</param>
192 /// <param name="error">Исключение возникшее при выполнении операции</param>
203 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
193 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
204 public void Reject(Exception error) {
194 public void Reject(Exception error) {
205 if (BeginTransit()) {
195 if (BeginTransit()) {
206 m_error = error is TransientPromiseException ? error.InnerException : error;
196 m_error = error is TransientPromiseException ? error.InnerException : error;
207 CompleteTransit(REJECTED_STATE);
197 CompleteTransit(REJECTED_STATE);
208 OnStateChanged();
198 OnStateChanged();
209 } else {
199 } else {
210 WaitTransition();
200 WaitTransition();
211 if (m_state == SUCCEEDED_STATE)
201 if (m_state == SUCCEEDED_STATE)
212 throw new InvalidOperationException("The promise is already resolved");
202 throw new InvalidOperationException("The promise is already resolved");
213 }
203 }
214 }
204 }
215
205
216 /// <summary>
206 /// <summary>
217 /// Отменяет операцию, если это возможно.
207 /// Отменяет операцию, если это возможно.
218 /// </summary>
208 /// </summary>
219 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
209 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
220 public void Cancel() {
210 public void Cancel() {
221 if (m_cancellable && BeginTransit()) {
211 if (BeginTransit()) {
222 CompleteTransit(CANCELLED_STATE);
212 CompleteTransit(CANCELLED_STATE);
223 OnStateChanged();
213 OnStateChanged();
224 }
214 }
225 }
215 }
226
216
227 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error, Action cancel) {
217 public IPromise<T> Then(Action<T> success, Func<Exception,T> error, Action cancel) {
228 if (success == null && error == null && cancel == null)
218 if (success == null && error == null && cancel == null)
229 return this;
219 return this;
230
220
231 var medium = new Promise<T>(this, true);
221 var medium = new Promise<T>(this);
232
222
233 AddHandler(success, error, cancel, medium);
223 AddHandler(success, error, cancel, medium);
234
224
235 return medium;
225 return medium;
236 }
226 }
237
227
238 /// <summary>
228 /// <summary>
239 /// Adds new handlers to this promise.
229 /// Adds new handlers to this promise.
240 /// </summary>
230 /// </summary>
241 /// <param name="success">The handler of the successfully completed operation.
231 /// <param name="success">The handler of the successfully completed operation.
242 /// This handler will recieve an operation result as a parameter.</param>
232 /// This handler will recieve an operation result as a parameter.</param>
243 /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param>
233 /// <param name="error">Handles an exception that may occur during the operation and returns the value which will be used as the result of the operation.</param>
244 /// <returns>The new promise chained to this one.</returns>
234 /// <returns>The new promise chained to this one.</returns>
245 public IPromise<T> Then(ResultHandler<T> success, ErrorHandler<T> error) {
235 public IPromise<T> Then(Action<T> success, Func<Exception,T> error) {
246 if (success == null && error == null)
236 if (success == null && error == null)
247 return this;
237 return this;
248
238
249 var medium = new Promise<T>(this, true);
239 var medium = new Promise<T>(this);
250
240
251 AddHandler(success, error, null, medium);
241 AddHandler(success, error, null, medium);
252
242
253 return medium;
243 return medium;
254 }
244 }
255
245
256
246
257
247
258
248
259 public IPromise<T> Then(ResultHandler<T> success) {
249 public IPromise<T> Then(Action<T> success) {
260 if (success == null)
250 if (success == null)
261 return this;
251 return this;
262
252
263 var medium = new Promise<T>(this, true);
253 var medium = new Promise<T>(this);
264
254
265 AddHandler(success, null, null, medium);
255 AddHandler(success, null, null, medium);
266
256
267 return medium;
257 return medium;
268 }
258 }
269
259
270 /// <summary>
260 /// <summary>
271 /// Последний обработчик в цепочки обещаний.
261 /// Последний обработчик в цепочки обещаний.
272 /// </summary>
262 /// </summary>
273 /// <param name="success"></param>
263 /// <param name="success"></param>
274 /// <param name="error"></param>
264 /// <param name="error"></param>
275 /// <param name="cancel"></param>
265 /// <param name="cancel"></param>
276 /// <remarks>
266 /// <remarks>
277 /// <para>
267 /// <para>
278 /// Данный метод не создает связанного с текущим обещания и предназначен для окончания
268 /// Данный метод не создает связанного с текущим обещания и предназначен для окончания
279 /// фсинхронной цепочки.
269 /// фсинхронной цепочки.
280 /// </para>
270 /// </para>
281 /// <para>
271 /// <para>
282 /// Если данный метод вызвать несколько раз, либо добавить другие обработчики, то цепочка
272 /// Если данный метод вызвать несколько раз, либо добавить другие обработчики, то цепочка
283 /// не будет одиночной <see cref="IsExclusive"/> и, как следствие, будет невозможна отмена
273 /// не будет одиночной <see cref="IsExclusive"/> и, как следствие, будет невозможна отмена
284 /// всей цепи обещаний снизу (с самого последнего обещания).
274 /// всей цепи обещаний снизу (с самого последнего обещания).
285 /// </para>
275 /// </para>
286 /// </remarks>
276 /// </remarks>
287 public void Last(ResultHandler<T> success, ErrorHandler error, Action cancel) {
277 public void Last(Action<T> success, Action<Exception> error, Action cancel) {
288 if (success == null && error == null && cancel == null)
278 if (success == null && error == null && cancel == null)
289 return;
279 return;
290
280
291 ErrorHandler<T> errorHandler = null;
281 Func<Exception,T> errorHandler = null;
292 if (error != null)
282 if (error != null)
293 errorHandler = err => {
283 errorHandler = err => {
294 error(err);
284 error(err);
295 return default(T);
285 return default(T);
296 };
286 };
297 AddHandler(success, errorHandler, cancel, null);
287 AddHandler(success, errorHandler, cancel, null);
298 }
288 }
299
289
300 public void Last(ResultHandler<T> success, ErrorHandler error) {
290 public void Last(Action<T> success, Action<Exception> error) {
301 Last(success, error, null);
291 Last(success, error, null);
302 }
292 }
303
293
304 public void Last(ResultHandler<T> success) {
294 public void Last(Action<T> success) {
305 Last(success, null, null);
295 Last(success, null, null);
306 }
296 }
307
297
308 public IPromise Error(ErrorHandler error) {
298 public IPromise Error(Action<Exception> error) {
309 if (error == null)
299 if (error == null)
310 return this;
300 return this;
311
301
312 var medium = new Promise<T>(this, true);
302 var medium = new Promise<T>(this);
313
303
314 AddHandler(
304 AddHandler(
315 null,
305 null,
316 e => {
306 e => {
317 error(e);
307 error(e);
318 return default(T);
308 return default(T);
319 },
309 },
320 null,
310 null,
321 medium
311 medium
322 );
312 );
323
313
324 return medium;
314 return medium;
325 }
315 }
326
316
327 /// <summary>
317 /// <summary>
328 /// Handles error and allows to keep the promise.
318 /// Handles error and allows to keep the promise.
329 /// </summary>
319 /// </summary>
330 /// <remarks>
320 /// <remarks>
331 /// If the specified handler throws an exception, this exception will be used to reject the promise.
321 /// If the specified handler throws an exception, this exception will be used to reject the promise.
332 /// </remarks>
322 /// </remarks>
333 /// <param name="handler">The error handler which returns the result of the promise.</param>
323 /// <param name="handler">The error handler which returns the result of the promise.</param>
334 /// <returns>New promise.</returns>
324 /// <returns>New promise.</returns>
335 public IPromise<T> Error(ErrorHandler<T> handler) {
325 public IPromise<T> Error(Func<Exception,T> handler) {
336 if (handler == null)
326 if (handler == null)
337 return this;
327 return this;
338
328
339 var medium = new Promise<T>(this, true);
329 var medium = new Promise<T>(this);
340
330
341 AddHandler(null, handler, null, medium);
331 AddHandler(null, handler, null, medium);
342
332
343 return medium;
333 return medium;
344 }
334 }
345
335
346 /// <summary>
336 /// <summary>
347 /// Позволяет преобразовать результат выполения операции к новому типу.
337 /// Позволяет преобразовать результат выполения операции к новому типу.
348 /// </summary>
338 /// </summary>
349 /// <typeparam name="TNew">Новый тип результата.</typeparam>
339 /// <typeparam name="TNew">Новый тип результата.</typeparam>
350 /// <param name="mapper">Преобразование результата к новому типу.</param>
340 /// <param name="mapper">Преобразование результата к новому типу.</param>
351 /// <param name="error">Обработчик ошибки. Данный обработчик получит
341 /// <param name="error">Обработчик ошибки. Данный обработчик получит
352 /// исключение возникшее при выполнении операции.</param>
342 /// исключение возникшее при выполнении операции.</param>
353 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns>
343 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns>
354 /// <param name = "cancel"></param>
344 /// <param name = "cancel"></param>
355 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error, Action cancel) {
345 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error, Action cancel) {
356 Safe.ArgumentNotNull(mapper, "mapper");
346 Safe.ArgumentNotNull(mapper, "mapper");
357
347
358 // создаем прицепленное обещание
348 // создаем прицепленное обещание
359 var medium = new Promise<TNew>(this, true);
349 var medium = new Promise<TNew>(this);
360
350
361 ResultHandler<T> resultHandler = result => medium.Resolve(mapper(result));
351 Action<T> resultHandler = result => medium.Resolve(mapper(result));
362 ErrorHandler<T> errorHandler;
352 Func<Exception,T> errorHandler;
363 if (error != null)
353 if (error != null)
364 errorHandler = e => {
354 errorHandler = e => {
365 try {
355 try {
366 medium.Resolve(error(e));
356 medium.Resolve(error(e));
367 } catch (Exception e2) {
357 } catch (Exception e2) {
368 // в случае ошибки нужно передать исключение дальше по цепочке
358 // в случае ошибки нужно передать исключение дальше по цепочке
369 medium.Reject(e2);
359 medium.Reject(e2);
370 }
360 }
371 return default(T);
361 return default(T);
372 };
362 };
373 else
363 else
374 errorHandler = e => {
364 errorHandler = e => {
375 medium.Reject(e);
365 medium.Reject(e);
376 return default(T);
366 return default(T);
377 };
367 };
378
368
379 Action cancelHandler;
369 Action cancelHandler;
380 if (cancel != null)
370 if (cancel != null)
381 cancelHandler = () => {
371 cancelHandler = () => {
382 cancel();
372 cancel();
383 medium.Cancel();
373 medium.Cancel();
384 };
374 };
385 else
375 else
386 cancelHandler = medium.Cancel;
376 cancelHandler = medium.Cancel;
387
377
388
378
389 AddHandler(
379 AddHandler(
390 resultHandler,
380 resultHandler,
391 errorHandler,
381 errorHandler,
392 cancelHandler,
382 cancelHandler,
393 null
383 null
394 );
384 );
395
385
396 return medium;
386 return medium;
397 }
387 }
398
388
399 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper, ErrorHandler<TNew> error) {
389 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error) {
400 return Then(mapper, error, null);
390 return Then(mapper, error, null);
401 }
391 }
402
392
403 public IPromise<TNew> Then<TNew>(ResultMapper<T, TNew> mapper) {
393 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper) {
404 return Then(mapper, null, null);
394 return Then(mapper, null, null);
405 }
395 }
406
396
407 /// <summary>
397 /// <summary>
408 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после
398 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после
409 /// выполнения текущей, а результат текущей операции может быть использован для инициализации
399 /// выполнения текущей, а результат текущей операции может быть использован для инициализации
410 /// новой операции.
400 /// новой операции.
411 /// </summary>
401 /// </summary>
412 /// <typeparam name="TNew">Тип результата указанной асинхронной операции.</typeparam>
402 /// <typeparam name="TNew">Тип результата указанной асинхронной операции.</typeparam>
413 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param>
403 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param>
414 /// <param name="error">Обработчик ошибки. Данный обработчик получит
404 /// <param name="error">Обработчик ошибки. Данный обработчик получит
415 /// исключение возникшее при выполнении текуещй операции.</param>
405 /// исключение возникшее при выполнении текуещй операции.</param>
416 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns>
406 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns>
417 /// <param name = "cancel"></param>
407 /// <param name = "cancel"></param>
418 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error, Action cancel) {
408 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error, Action cancel) {
419
409
420 Safe.ArgumentNotNull(chained, "chained");
410 Safe.ArgumentNotNull(chained, "chained");
421
411
422 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно
412 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно
423 // создать посредника, к которому будут подвызяваться следующие обработчики.
413 // создать посредника, к которому будут подвызяваться следующие обработчики.
424 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы
414 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы
425 // передать через него результаты работы.
415 // передать через него результаты работы.
426 var medium = new Promise<TNew>(this, true);
416 var medium = new Promise<TNew>(this);
427
417
428 ResultHandler<T> resultHandler = delegate(T result) {
418 Action<T> resultHandler = delegate(T result) {
429 if (medium.IsCancelled)
419 if (medium.IsCancelled)
430 return;
420 return;
431
421
432 var promise = chained(result);
422 var promise = chained(result);
433
423
434 promise.Last(
424 promise.Last(
435 medium.Resolve,
425 medium.Resolve,
436 medium.Reject,
426 medium.Reject,
437 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
427 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
438 );
428 );
439
429
440 // notify chained operation that it's not needed anymore
430 // notify chained operation that it's not needed anymore
441 // порядок вызова Then, Cancelled важен, поскольку от этого
431 // порядок вызова Then, Cancelled важен, поскольку от этого
442 // зависит IsExclusive
432 // зависит IsExclusive
443 medium.Cancelled(() => {
433 medium.Last(
444 if (promise.IsExclusive)
434 null,
445 promise.Cancel();
435 null,
446 });
436 () => {
437 if (promise.IsExclusive)
438 promise.Cancel();
439 }
440 );
447 };
441 };
448
442
449 ErrorHandler<T> errorHandler;
443 Func<Exception,T> errorHandler;
450
444
451 if (error != null)
445 if (error != null)
452 errorHandler = delegate(Exception e) {
446 errorHandler = delegate(Exception e) {
453 try {
447 try {
454 var promise = error(e);
448 var promise = error(e);
455
449
456 promise.Last(
450 promise.Last(
457 medium.Resolve,
451 medium.Resolve,
458 medium.Reject,
452 medium.Reject,
459 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
453 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
460 );
454 );
461
455
462 // notify chained operation that it's not needed anymore
456 // notify chained operation that it's not needed anymore
463 // порядок вызова Then, Cancelled важен, поскольку от этого
457 // порядок вызова Then, Cancelled важен, поскольку от этого
464 // зависит IsExclusive
458 // зависит IsExclusive
465 medium.Cancelled(() => {
459 medium.Cancelled(() => {
466 if (promise.IsExclusive)
460 if (promise.IsExclusive)
467 promise.Cancel();
461 promise.Cancel();
468 });
462 });
469 } catch (Exception e2) {
463 } catch (Exception e2) {
470 medium.Reject(e2);
464 medium.Reject(e2);
471 }
465 }
472 return default(T);
466 return default(T);
473 };
467 };
474 else
468 else
475 errorHandler = err => {
469 errorHandler = err => {
476 medium.Reject(err);
470 medium.Reject(err);
477 return default(T);
471 return default(T);
478 };
472 };
479
473
480
474
481 Action cancelHandler;
475 Action cancelHandler;
482 if (cancel != null)
476 if (cancel != null)
483 cancelHandler = () => {
477 cancelHandler = () => {
484 if (cancel != null)
478 if (cancel != null)
485 cancel();
479 cancel();
486 medium.Cancel();
480 medium.Cancel();
487 };
481 };
488 else
482 else
489 cancelHandler = medium.Cancel;
483 cancelHandler = medium.Cancel;
490
484
491 AddHandler(
485 AddHandler(
492 resultHandler,
486 resultHandler,
493 errorHandler,
487 errorHandler,
494 cancelHandler,
488 cancelHandler,
495 null
489 null
496 );
490 );
497
491
498 return medium;
492 return medium;
499 }
493 }
500
494
501 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained, ErrorHandler<IPromise<TNew>> error) {
495 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error) {
502 return Chain(chained, error, null);
496 return Chain(chained, error, null);
503 }
497 }
504
498
505 public IPromise<TNew> Chain<TNew>(ResultMapper<T, IPromise<TNew>> chained) {
499 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained) {
506 return Chain(chained, null, null);
500 return Chain(chained, null, null);
507 }
501 }
508
502
509 public IPromise<T> Cancelled(Action handler) {
503 public IPromise<T> Cancelled(Action handler) {
510 var medium = new Promise<T>(this,true);
504 var medium = new Promise<T>(this);
511 AddHandler(null, null, handler, medium);
505 AddHandler(null, null, handler, medium);
512 return medium;
506 return medium;
513 }
507 }
514
508
515 /// <summary>
509 /// <summary>
516 /// Adds the specified handler for all cases (success, error, cancel)
510 /// Adds the specified handler for all cases (success, error, cancel)
517 /// </summary>
511 /// </summary>
518 /// <param name="handler">The handler that will be called anyway</param>
512 /// <param name="handler">The handler that will be called anyway</param>
519 /// <returns>self</returns>
513 /// <returns>self</returns>
520 public IPromise<T> Anyway(Action handler) {
514 public IPromise<T> Anyway(Action handler) {
521 Safe.ArgumentNotNull(handler, "handler");
515 Safe.ArgumentNotNull(handler, "handler");
522
516
523 AddHandler(
517 AddHandler(
524 x => handler(),
518 x => handler(),
525 e => {
519 e => {
526 handler();
520 handler();
527 throw new TransientPromiseException(e);
521 throw new TransientPromiseException(e);
528 },
522 },
529 handler,
523 handler,
530 null
524 null
531 );
525 );
532 return this;
526 return this;
533 }
527 }
534
528
535 /// <summary>
529 /// <summary>
536 /// Преобразует результат обещания к нужному типу
530 /// Преобразует результат обещания к нужному типу
537 /// </summary>
531 /// </summary>
538 /// <typeparam name="T2"></typeparam>
532 /// <typeparam name="T2"></typeparam>
539 /// <returns></returns>
533 /// <returns></returns>
540 public IPromise<T2> Cast<T2>() {
534 public IPromise<T2> Cast<T2>() {
541 return Then(x => (T2)(object)x, null);
535 return Then(x => (T2)(object)x, null);
542 }
536 }
543
537
544 /// <summary>
538 /// <summary>
545 /// Дожидается отложенного обещания и в случае успеха, возвращает
539 /// Дожидается отложенного обещания и в случае успеха, возвращает
546 /// его, результат, в противном случае бросает исключение.
540 /// его, результат, в противном случае бросает исключение.
547 /// </summary>
541 /// </summary>
548 /// <remarks>
542 /// <remarks>
549 /// <para>
543 /// <para>
550 /// Если ожидание обещания было прервано по таймауту, это не значит,
544 /// Если ожидание обещания было прервано по таймауту, это не значит,
551 /// что обещание было отменено или что-то в этом роде, это только
545 /// что обещание было отменено или что-то в этом роде, это только
552 /// означает, что мы его не дождались, однако все зарегистрированные
546 /// означает, что мы его не дождались, однако все зарегистрированные
553 /// обработчики, как были так остались и они будут вызваны, когда
547 /// обработчики, как были так остались и они будут вызваны, когда
554 /// обещание будет выполнено.
548 /// обещание будет выполнено.
555 /// </para>
549 /// </para>
556 /// <para>
550 /// <para>
557 /// Такое поведение вполне оправдано поскольку таймаут может истечь
551 /// Такое поведение вполне оправдано поскольку таймаут может истечь
558 /// в тот момент, когда началась обработка цепочки обработчиков, и
552 /// в тот момент, когда началась обработка цепочки обработчиков, и
559 /// к тому же текущее обещание может стоять в цепочке обещаний и его
553 /// к тому же текущее обещание может стоять в цепочке обещаний и его
560 /// отклонение может привести к непрогнозируемому результату.
554 /// отклонение может привести к непрогнозируемому результату.
561 /// </para>
555 /// </para>
562 /// </remarks>
556 /// </remarks>
563 /// <param name="timeout">Время ожидания</param>
557 /// <param name="timeout">Время ожидания</param>
564 /// <returns>Результат выполнения обещания</returns>
558 /// <returns>Результат выполнения обещания</returns>
565 public T Join(int timeout) {
559 public T Join(int timeout) {
566 var evt = new ManualResetEvent(false);
560 var evt = new ManualResetEvent(false);
567 Anyway(() => evt.Set());
561 Anyway(() => evt.Set());
568
562
569 if (!evt.WaitOne(timeout, true))
563 if (!evt.WaitOne(timeout, true))
570 throw new TimeoutException();
564 throw new TimeoutException();
571
565
572 switch (m_state) {
566 switch (m_state) {
573 case SUCCEEDED_STATE:
567 case SUCCEEDED_STATE:
574 return m_result;
568 return m_result;
575 case CANCELLED_STATE:
569 case CANCELLED_STATE:
576 throw new OperationCanceledException();
570 throw new OperationCanceledException();
577 case REJECTED_STATE:
571 case REJECTED_STATE:
578 throw new TargetInvocationException(m_error);
572 throw new TargetInvocationException(m_error);
579 default:
573 default:
580 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
574 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
581 }
575 }
582 }
576 }
583
577
584 public T Join() {
578 public T Join() {
585 return Join(Timeout.Infinite);
579 return Join(Timeout.Infinite);
586 }
580 }
587
581
588 void AddHandler(ResultHandler<T> success, ErrorHandler<T> error, Action cancel, Promise<T> medium) {
582 void AddHandler(Action<T> success, Func<Exception,T> error, Action cancel, Promise<T> medium) {
589 if (success != null || error != null)
583 if (success != null || error != null)
590 Interlocked.Increment(ref m_childrenCount);
584 Interlocked.Increment(ref m_childrenCount);
591
585
592 var handler = new HandlerDescriptor {
586 var handler = new HandlerDescriptor {
593 resultHandler = success,
587 resultHandler = success,
594 errorHandler = error,
588 errorHandler = error,
595 cancellHandler = cancel,
589 cancellHandler = cancel,
596 medium = medium
590 medium = medium
597 };
591 };
598
592
599 bool queued;
593 bool queued;
600
594
601 if (!IsResolved) {
595 if (!IsResolved) {
602 m_handlers.Enqueue(handler);
596 m_handlers.Enqueue(handler);
603 queued = true;
597 queued = true;
604 } else {
598 } else {
605 // the promise is in resolved state, just invoke the handled with minimum overhead
599 // the promise is in resolved state, just invoke the handled with minimum overhead
606 queued = false;
600 queued = false;
607 InvokeHandler(handler);
601 InvokeHandler(handler);
608 }
602 }
609
603
610 if (queued && IsResolved && m_handlers.TryDequeue(out handler))
604 if (queued && IsResolved && m_handlers.TryDequeue(out handler))
611 // if the promise have been resolved while we was adding handler to the queue
605 // if the promise have been resolved while we was adding handler to the queue
612 // we can't guarantee that someone is still processing it
606 // we can't guarantee that someone is still processing it
613 // therefore we will fetch a handler from the queue and execute it
607 // therefore we will fetch a handler from the queue and execute it
614 // note that fetched handler may be not the one that we have added
608 // note that fetched handler may be not the one that we have added
615 // even we can fetch no handlers at all :)
609 // even we can fetch no handlers at all :)
616 InvokeHandler(handler);
610 InvokeHandler(handler);
617 }
611 }
618
612
619 protected virtual void InvokeHandler(HandlerDescriptor handler) {
613 protected virtual void InvokeHandler(HandlerDescriptor handler) {
620 switch (m_state) {
614 switch (m_state) {
621 case SUCCEEDED_STATE:
615 case SUCCEEDED_STATE:
622 handler.Resolve(m_result);
616 handler.Resolve(m_result);
623 break;
617 break;
624 case REJECTED_STATE:
618 case REJECTED_STATE:
625 handler.Reject(m_error);
619 handler.Reject(m_error);
626 break;
620 break;
627 case CANCELLED_STATE:
621 case CANCELLED_STATE:
628 handler.Cancel();
622 handler.Cancel();
629 break;
623 break;
630 default:
624 default:
631 // do nothing
625 // do nothing
632 return;
626 return;
633 }
627 }
634 }
628 }
635
629
636 void OnStateChanged() {
630 void OnStateChanged() {
637 HandlerDescriptor handler;
631 HandlerDescriptor handler;
638 while (m_handlers.TryDequeue(out handler))
632 while (m_handlers.TryDequeue(out handler))
639 InvokeHandler(handler);
633 InvokeHandler(handler);
640 }
634 }
641
635
642 public bool IsExclusive {
636 public bool IsExclusive {
643 get {
637 get {
644 return m_childrenCount <= 1;
638 return m_childrenCount <= 1;
645 }
639 }
646 }
640 }
647
641
648 /// <summary>
642 /// <summary>
649 /// Объединяет несколько обещаний в одно, результатом которого является массив результатов других обещаний.
643 /// Объединяет несколько обещаний в одно, результатом которого является массив результатов других обещаний.
650 /// Если хотябы одно из переданных обещаний не будет выполнено, то новое обещение тоже не будет выполнено.
644 /// Если хотябы одно из переданных обещаний не будет выполнено, то новое обещение тоже не будет выполнено.
651 /// При отмене нового обещания, переданные обещания также будут отменены, если никто больше на них не подписан.
645 /// При отмене нового обещания, переданные обещания также будут отменены, если никто больше на них не подписан.
652 /// </summary>
646 /// </summary>
653 /// <param name="promises">Список обещаний. Если список пустой, то результирующее обещание возвращается уже выполненным.</param>
647 /// <param name="promises">Список обещаний. Если список пустой, то результирующее обещание возвращается уже выполненным.</param>
654 /// <returns>Обещание объединяющее в себе результат переданных обещаний.</returns>
648 /// <returns>Обещание объединяющее в себе результат переданных обещаний.</returns>
655 /// <exception cref="ArgumentNullException"><paramref name="promises"/> не может быть null</exception>
649 /// <exception cref="ArgumentNullException"><paramref name="promises"/> не может быть null</exception>
656 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) {
650 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) {
657 if (promises == null)
651 if (promises == null)
658 throw new ArgumentNullException();
652 throw new ArgumentNullException();
659
653
660 // создаем аккумулятор для результатов и результирующее обещание
654 // создаем аккумулятор для результатов и результирующее обещание
661 var result = new T[promises.Count];
655 var result = new T[promises.Count];
662 var promise = new Promise<T[]>();
656 var promise = new Promise<T[]>();
663
657
664 // special case
658 // special case
665 if (promises.Count == 0) {
659 if (promises.Count == 0) {
666 promise.Resolve(result);
660 promise.Resolve(result);
667 return promise;
661 return promise;
668 }
662 }
669
663
670 int pending = promises.Count;
664 int pending = promises.Count;
671
665
672 for (int i = 0; i < promises.Count; i++) {
666 for (int i = 0; i < promises.Count; i++) {
673 var dest = i;
667 var dest = i;
674
668
675 if (promises[i] != null) {
669 if (promises[i] != null) {
676 promises[i].Then(
670 promises[i].Then(
677 x => {
671 x => {
678 result[dest] = x;
672 result[dest] = x;
679 if (Interlocked.Decrement(ref pending) == 0)
673 if (Interlocked.Decrement(ref pending) == 0)
680 promise.Resolve(result);
674 promise.Resolve(result);
681 },
675 },
682 e => {
676 e => {
683 promise.Reject(e);
677 promise.Reject(e);
684 return default(T);
678 return default(T);
685 }
679 }
686 );
680 );
687 } else {
681 } else {
688 if (Interlocked.Decrement(ref pending) == 0)
682 if (Interlocked.Decrement(ref pending) == 0)
689 promise.Resolve(result);
683 promise.Resolve(result);
690 }
684 }
691 }
685 }
692
686
693 promise.Cancelled(
687 promise.Cancelled(
694 () => {
688 () => {
695 foreach (var d in promises)
689 foreach (var d in promises)
696 if (d != null && d.IsExclusive)
690 if (d != null && d.IsExclusive)
697 d.Cancel();
691 d.Cancel();
698 }
692 }
699 );
693 );
700
694
701 return promise;
695 return promise;
702 }
696 }
703
697
704 /// <summary>
698 /// <summary>
705 /// Объединяет несколько обещаний в одно. Результирующее обещание будет выполнено при
699 /// Объединяет несколько обещаний в одно. Результирующее обещание будет выполнено при
706 /// выполнении всех указанных обещаний. При этом возвращаемые значения первичных обещаний
700 /// выполнении всех указанных обещаний. При этом возвращаемые значения первичных обещаний
707 /// игнорируются.
701 /// игнорируются.
708 /// </summary>
702 /// </summary>
709 /// <param name="promises">Коллекция первичных обещаний, которые будут объеденены в одно.</param>
703 /// <param name="promises">Коллекция первичных обещаний, которые будут объеденены в одно.</param>
710 /// <returns>Новое обещание, объединяющее в себе переданные.</returns>
704 /// <returns>Новое обещание, объединяющее в себе переданные.</returns>
711 /// <remarks>
705 /// <remarks>
712 /// Если в коллекции встречаюься <c>null</c>, то они воспринимаются как выполненные обещания.
706 /// Если в коллекции встречаюься <c>null</c>, то они воспринимаются как выполненные обещания.
713 /// </remarks>
707 /// </remarks>
714 public static IPromise CreateComposite(ICollection<IPromise> promises) {
708 public static IPromise CreateComposite(ICollection<IPromise> promises) {
715 if (promises == null)
709 if (promises == null)
716 throw new ArgumentNullException();
710 throw new ArgumentNullException();
717 if (promises.Count == 0)
711 if (promises.Count == 0)
718 return Promise<object>.ResultToPromise(null);
712 return Promise<object>.ResultToPromise(null);
719
713
720 int countdown = promises.Count;
714 int countdown = promises.Count;
721
715
722 var result = new Promise<object>();
716 var result = new Promise<object>();
723
717
724 foreach (var d in promises) {
718 foreach (var d in promises) {
725 if (d == null) {
719 if (d == null) {
726 if (Interlocked.Decrement(ref countdown) == 0)
720 if (Interlocked.Decrement(ref countdown) == 0)
727 result.Resolve(null);
721 result.Resolve(null);
728 } else {
722 } else {
729 d.Then(() => {
723 d.Then(() => {
730 if (Interlocked.Decrement(ref countdown) == 0)
724 if (Interlocked.Decrement(ref countdown) == 0)
731 result.Resolve(null);
725 result.Resolve(null);
732 });
726 });
733 }
727 }
734 }
728 }
735
729
736 result.Cancelled(() => {
730 result.Cancelled(() => {
737 foreach (var d in promises)
731 foreach (var d in promises)
738 if (d != null && d.IsExclusive)
732 if (d != null && d.IsExclusive)
739 d.Cancel();
733 d.Cancel();
740 });
734 });
741
735
742 return result;
736 return result;
743 }
737 }
744
738
745 public static Promise<T> ResultToPromise(T result) {
739 public static Promise<T> ResultToPromise(T result) {
746 var p = new Promise<T>();
740 var p = new Promise<T>();
747 p.Resolve(result);
741 p.Resolve(result);
748 return p;
742 return p;
749 }
743 }
750
744
751 public static Promise<T> ExceptionToPromise(Exception error) {
745 public static Promise<T> ExceptionToPromise(Exception error) {
752 if (error == null)
746 if (error == null)
753 throw new ArgumentNullException();
747 throw new ArgumentNullException();
754
748
755 var p = new Promise<T>();
749 var p = new Promise<T>();
756 p.Reject(error);
750 p.Reject(error);
757 return p;
751 return p;
758 }
752 }
759
753
760 #region IPromiseBase explicit implementation
754 #region IPromiseBase explicit implementation
761
755
762 IPromise IPromise.Then(Action success, ErrorHandler error, Action cancel) {
756 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) {
763 return Then(
757 return Then(
764 success != null ? new ResultHandler<T>(x => success()) : null,
758 success != null ? new Action<T>(x => success()) : null,
765 error != null ? new ErrorHandler<T>(e => {
759 error != null ? new Func<Exception,T>(e => {
766 error(e);
760 error(e);
767 return default(T);
761 return default(T);
768 }) : null,
762 }) : null,
769 cancel
763 cancel
770 );
764 );
771 }
765 }
772
766
773 IPromise IPromise.Then(Action success, ErrorHandler error) {
767 IPromise IPromise.Then(Action success, Action<Exception> error) {
774 return Then(
768 return Then(
775 success != null ? new ResultHandler<T>(x => success()) : null,
769 success != null ? new Action<T>(x => success()) : null,
776 error != null ? new ErrorHandler<T>(e => {
770 error != null ? new Func<Exception,T>(e => {
777 error(e);
771 error(e);
778 return default(T);
772 return default(T);
779 }) : null
773 }) : null
780 );
774 );
781 }
775 }
782
776
783 IPromise IPromise.Then(Action success) {
777 IPromise IPromise.Then(Action success) {
784 Safe.ArgumentNotNull(success, "success");
778 Safe.ArgumentNotNull(success, "success");
785 return Then(x => success());
779 return Then(x => success());
786 }
780 }
787
781
788 IPromise IPromise.Chain(Func<IPromise> chained, ErrorHandler<IPromise> error, Action cancel) {
782 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
789 return ChainNoResult(chained, error, cancel);
783 return ChainNoResult(chained, error, cancel);
790 }
784 }
791
785
792 IPromise ChainNoResult(Func<IPromise> chained, ErrorHandler<IPromise> error, Action cancel) {
786 IPromise ChainNoResult(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) {
793 Safe.ArgumentNotNull(chained, "chained");
787 Safe.ArgumentNotNull(chained, "chained");
794
788
795 var medium = new Promise<object>(this, true);
789 var medium = new Promise<object>(this);
796
790
797 ResultHandler<T> resultHandler = delegate(T result) {
791 Action<T> resultHandler = delegate {
798 if (medium.IsCancelled)
792 if (medium.IsCancelled)
799 return;
793 return;
800
794
801 var promise = chained();
795 var promise = chained();
802
796
803 promise.Last(
797 promise.Last(
804 medium.Resolve,
798 medium.Resolve,
805 medium.Reject,
799 medium.Reject,
806 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
800 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
807 );
801 );
808
802
809 // notify chained operation that it's not needed anymore
803 // notify chained operation that it's not needed anymore
810 // порядок вызова Then, Cancelled важен, поскольку от этого
804 // порядок вызова Then, Cancelled важен, поскольку от этого
811 // зависит IsExclusive
805 // зависит IsExclusive
812 medium.Cancelled(() => {
806 medium.Cancelled(() => {
813 if (promise.IsExclusive)
807 if (promise.IsExclusive)
814 promise.Cancel();
808 promise.Cancel();
815 });
809 });
816 };
810 };
817
811
818 ErrorHandler<T> errorHandler;
812 Func<Exception,T> errorHandler;
819
813
820 if (error != null)
814 if (error != null)
821 errorHandler = delegate(Exception e) {
815 errorHandler = delegate(Exception e) {
822 try {
816 try {
823 var promise = error(e);
817 var promise = error(e);
824
818
825 promise.Last(
819 promise.Last(
826 medium.Resolve,
820 medium.Resolve,
827 medium.Reject,
821 medium.Reject,
828 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
822 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка
829 );
823 );
830
824
831 // notify chained operation that it's not needed anymore
825 // notify chained operation that it's not needed anymore
832 // порядок вызова Then, Cancelled важен, поскольку от этого
826 // порядок вызова Then, Cancelled важен, поскольку от этого
833 // зависит IsExclusive
827 // зависит IsExclusive
834 medium.Cancelled(() => {
828 medium.Cancelled(() => {
835 if (promise.IsExclusive)
829 if (promise.IsExclusive)
836 promise.Cancel();
830 promise.Cancel();
837 });
831 });
838 } catch (Exception e2) {
832 } catch (Exception e2) {
839 medium.Reject(e2);
833 medium.Reject(e2);
840 }
834 }
841 return default(T);
835 return default(T);
842 };
836 };
843 else
837 else
844 errorHandler = err => {
838 errorHandler = err => {
845 medium.Reject(err);
839 medium.Reject(err);
846 return default(T);
840 return default(T);
847 };
841 };
848
842
849
843
850 Action cancelHandler;
844 Action cancelHandler;
851 if (cancel != null)
845 if (cancel != null)
852 cancelHandler = () => {
846 cancelHandler = () => {
853 if (cancel != null)
847 if (cancel != null)
854 cancel();
848 cancel();
855 medium.Cancel();
849 medium.Cancel();
856 };
850 };
857 else
851 else
858 cancelHandler = medium.Cancel;
852 cancelHandler = medium.Cancel;
859
853
860 AddHandler(
854 AddHandler(
861 resultHandler,
855 resultHandler,
862 errorHandler,
856 errorHandler,
863 cancelHandler,
857 cancelHandler,
864 null
858 null
865 );
859 );
866
860
867 return medium;
861 return medium;
868 }
862 }
869 IPromise IPromise.Chain(Func<IPromise> chained, ErrorHandler<IPromise> error) {
863 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error) {
870 return ChainNoResult(chained, error, null);
864 return ChainNoResult(chained, error, null);
871 }
865 }
872 IPromise IPromise.Chain(Func<IPromise> chained) {
866 IPromise IPromise.Chain(Func<IPromise> chained) {
873 return ChainNoResult(chained, null, null);
867 return ChainNoResult(chained, null, null);
874 }
868 }
875
869
876
870
877 void IPromise.Last(Action success, ErrorHandler error, Action cancel) {
871 void IPromise.Last(Action success, Action<Exception> error, Action cancel) {
878 Last(x => success(), error, cancel);
872 Last(x => success(), error, cancel);
879 }
873 }
880
874
881 void IPromise.Last(Action success, ErrorHandler error) {
875 void IPromise.Last(Action success, Action<Exception> error) {
882 Last(x => success(), error, null);
876 Last(x => success(), error, null);
883 }
877 }
884
878
885 void IPromise.Last(Action success) {
879 void IPromise.Last(Action success) {
886 Last(x => success(), null, null);
880 Last(x => success(), null, null);
887 }
881 }
888
882
889 IPromise IPromise.Error(ErrorHandler error) {
883 IPromise IPromise.Error(Action<Exception> error) {
890 return Error(error);
884 return Error(error);
891 }
885 }
892
886
893 IPromise IPromise.Anyway(Action handler) {
887 IPromise IPromise.Anyway(Action handler) {
894 return Anyway(handler);
888 return Anyway(handler);
895 }
889 }
896
890
897 IPromise IPromise.Cancelled(Action handler) {
891 IPromise IPromise.Cancelled(Action handler) {
898 return Cancelled(handler);
892 return Cancelled(handler);
899 }
893 }
900
894
901 void IPromise.Join() {
895 void IPromise.Join() {
902 Join();
896 Join();
903 }
897 }
904
898
905 void IPromise.Join(int timeout) {
899 void IPromise.Join(int timeout) {
906 Join(timeout);
900 Join(timeout);
907 }
901 }
908
902
909 #endregion
903 #endregion
910
904
911
905
912
906
913 }
907 }
914 }
908 }
@@ -1,65 +1,83
1 using System.Threading;
1 using System.Threading;
2 using System;
2 using System;
3 #if NET_4_5
3 #if NET_4_5
4 using System.Threading.Tasks;
4 using System.Threading.Tasks;
5 #endif
5 #endif
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) {
9 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
10 Safe.ArgumentNotNull(that, "that");
10 Safe.ArgumentNotNull(that, "that");
11 var context = SynchronizationContext.Current;
11 var context = SynchronizationContext.Current;
12 if (context == null)
12 if (context == null)
13 return that;
13 return that;
14
14
15 var p = new SyncContextPromise<T>(context, that, true);
15 var p = new SyncContextPromise<T>(context, that);
16
16
17 that.Last(
17 that.Last(
18 p.Resolve,
18 p.Resolve,
19 p.Reject,
19 p.Reject,
20 p.Cancel
20 p.Cancel
21 );
21 );
22 return p;
22 return p;
23 }
23 }
24
24
25 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
25 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
26 Safe.ArgumentNotNull(that, "that");
26 Safe.ArgumentNotNull(that, "that");
27 Safe.ArgumentNotNull(context, "context");
27 Safe.ArgumentNotNull(context, "context");
28
28
29 var p = new SyncContextPromise<T>(context, that, true);
29 var p = new SyncContextPromise<T>(context, that);
30
30
31 that.Last(
31 that.Last(
32 p.Resolve,
32 p.Resolve,
33 p.Reject,
33 p.Reject,
34 p.Cancel
34 p.Cancel
35 );
35 );
36 return p;
36 return p;
37 }
37 }
38
38
39 /// <summary>
40 /// Ensures the dispatched.
41 /// </summary>
42 /// <returns>The dispatched.</returns>
43 /// <param name="that">That.</param>
44 /// <param name="head">Head.</param>
45 /// <param name="cleanup">Cleanup.</param>
46 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
47 /// <typeparam name="T">The 2nd type parameter.</typeparam>
48 public static TPromise EnsureDispatched<TPromise,T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise{
49 Safe.ArgumentNotNull(that, "that");
50 Safe.ArgumentNotNull(head, "head");
51
52 that.Last(null,null,() => head.Last(cleanup));
53
54 return that;
55 }
56
39 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
57 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
40 Safe.ArgumentNotNull(that, "that");
58 Safe.ArgumentNotNull(that, "that");
41 Safe.ArgumentNotNull(callback, "callback");
59 Safe.ArgumentNotNull(callback, "callback");
42 return ar => {
60 return ar => {
43 try {
61 try {
44 that.Resolve(callback(ar));
62 that.Resolve(callback(ar));
45 } catch (Exception err) {
63 } catch (Exception err) {
46 that.Reject(err);
64 that.Reject(err);
47 }
65 }
48 };
66 };
49 }
67 }
50
68
51 #if NET_4_5
69 #if NET_4_5
52
70
53 public static Task<T> GetTask<T>(this IPromise<T> that) {
71 public static Task<T> GetTask<T>(this IPromise<T> that) {
54 Safe.ArgumentNotNull(that, "that");
72 Safe.ArgumentNotNull(that, "that");
55 var tcs = new TaskCompletionSource<T>();
73 var tcs = new TaskCompletionSource<T>();
56
74
57 that.Last(tcs.SetResult, tcs.SetException, tcs.SetCanceled);
75 that.Last(tcs.SetResult, tcs.SetException, tcs.SetCanceled);
58
76
59 return tcs.Task;
77 return tcs.Task;
60 }
78 }
61
79
62 #endif
80 #endif
63 }
81 }
64 }
82 }
65
83
@@ -1,22 +1,22
1 using System.Threading;
1 using System.Threading;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class SyncContextPromise<T> : Promise<T> {
4 public class SyncContextPromise<T> : Promise<T> {
5 readonly SynchronizationContext m_context;
5 readonly SynchronizationContext m_context;
6
6
7 public SyncContextPromise(SynchronizationContext context) {
7 public SyncContextPromise(SynchronizationContext context) {
8 Safe.ArgumentNotNull(context, "context");
8 Safe.ArgumentNotNull(context, "context");
9 m_context = context;
9 m_context = context;
10 }
10 }
11
11
12 public SyncContextPromise(SynchronizationContext context, IPromise parent, bool cancellable)
12 public SyncContextPromise(SynchronizationContext context, IPromise parent)
13 : base(parent, cancellable) {
13 : base(parent) {
14 Safe.ArgumentNotNull(context, "context");
14 Safe.ArgumentNotNull(context, "context");
15 m_context = context;
15 m_context = context;
16 }
16 }
17 protected override void InvokeHandler(HandlerDescriptor handler) {
17 protected override void InvokeHandler(HandlerDescriptor handler) {
18 m_context.Post(x => base.InvokeHandler(handler),null);
18 m_context.Post(x => base.InvokeHandler(handler),null);
19 }
19 }
20 }
20 }
21 }
21 }
22
22
General Comments 0
You need to be logged in to leave comments. Login now