Mercurial > pub > ImplabNet
comparison Implab/Promise.cs @ 248:5cb4826c2c2a v3
Added awaiters to promises
Added static methods to Promise Resolve, Reject, All.
Updated promise helpers
author | cin |
---|---|
date | Tue, 30 Jan 2018 01:37:17 +0300 |
parents | |
children | d82909310094 |
comparison
equal
deleted
inserted
replaced
247:fb70574741a1 | 248:5cb4826c2c2a |
---|---|
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 |