cannam@147
|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
cannam@147
|
2 // Licensed under the MIT License:
|
cannam@147
|
3 //
|
cannam@147
|
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
cannam@147
|
5 // of this software and associated documentation files (the "Software"), to deal
|
cannam@147
|
6 // in the Software without restriction, including without limitation the rights
|
cannam@147
|
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
cannam@147
|
8 // copies of the Software, and to permit persons to whom the Software is
|
cannam@147
|
9 // furnished to do so, subject to the following conditions:
|
cannam@147
|
10 //
|
cannam@147
|
11 // The above copyright notice and this permission notice shall be included in
|
cannam@147
|
12 // all copies or substantial portions of the Software.
|
cannam@147
|
13 //
|
cannam@147
|
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
cannam@147
|
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
cannam@147
|
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
cannam@147
|
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
cannam@147
|
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
cannam@147
|
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
cannam@147
|
20 // THE SOFTWARE.
|
cannam@147
|
21
|
cannam@147
|
22 // This file contains extended inline implementation details that are required along with async.h.
|
cannam@147
|
23 // We move this all into a separate file to make async.h more readable.
|
cannam@147
|
24 //
|
cannam@147
|
25 // Non-inline declarations here are defined in async.c++.
|
cannam@147
|
26
|
cannam@147
|
27 #ifndef KJ_ASYNC_H_
|
cannam@147
|
28 #error "Do not include this directly; include kj/async.h."
|
cannam@147
|
29 #include "async.h" // help IDE parse this file
|
cannam@147
|
30 #endif
|
cannam@147
|
31
|
cannam@147
|
32 #ifndef KJ_ASYNC_INL_H_
|
cannam@147
|
33 #define KJ_ASYNC_INL_H_
|
cannam@147
|
34
|
cannam@147
|
35 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
cannam@147
|
36 #pragma GCC system_header
|
cannam@147
|
37 #endif
|
cannam@147
|
38
|
cannam@147
|
39 namespace kj {
|
cannam@147
|
40 namespace _ { // private
|
cannam@147
|
41
|
cannam@147
|
42 template <typename T>
|
cannam@147
|
43 class ExceptionOr;
|
cannam@147
|
44
|
cannam@147
|
45 class ExceptionOrValue {
|
cannam@147
|
46 public:
|
cannam@147
|
47 ExceptionOrValue(bool, Exception&& exception): exception(kj::mv(exception)) {}
|
cannam@147
|
48 KJ_DISALLOW_COPY(ExceptionOrValue);
|
cannam@147
|
49
|
cannam@147
|
50 void addException(Exception&& exception) {
|
cannam@147
|
51 if (this->exception == nullptr) {
|
cannam@147
|
52 this->exception = kj::mv(exception);
|
cannam@147
|
53 }
|
cannam@147
|
54 }
|
cannam@147
|
55
|
cannam@147
|
56 template <typename T>
|
cannam@147
|
57 ExceptionOr<T>& as() { return *static_cast<ExceptionOr<T>*>(this); }
|
cannam@147
|
58 template <typename T>
|
cannam@147
|
59 const ExceptionOr<T>& as() const { return *static_cast<const ExceptionOr<T>*>(this); }
|
cannam@147
|
60
|
cannam@147
|
61 Maybe<Exception> exception;
|
cannam@147
|
62
|
cannam@147
|
63 protected:
|
cannam@147
|
64 // Allow subclasses to have move constructor / assignment.
|
cannam@147
|
65 ExceptionOrValue() = default;
|
cannam@147
|
66 ExceptionOrValue(ExceptionOrValue&& other) = default;
|
cannam@147
|
67 ExceptionOrValue& operator=(ExceptionOrValue&& other) = default;
|
cannam@147
|
68 };
|
cannam@147
|
69
|
cannam@147
|
70 template <typename T>
|
cannam@147
|
71 class ExceptionOr: public ExceptionOrValue {
|
cannam@147
|
72 public:
|
cannam@147
|
73 ExceptionOr() = default;
|
cannam@147
|
74 ExceptionOr(T&& value): value(kj::mv(value)) {}
|
cannam@147
|
75 ExceptionOr(bool, Exception&& exception): ExceptionOrValue(false, kj::mv(exception)) {}
|
cannam@147
|
76 ExceptionOr(ExceptionOr&&) = default;
|
cannam@147
|
77 ExceptionOr& operator=(ExceptionOr&&) = default;
|
cannam@147
|
78
|
cannam@147
|
79 Maybe<T> value;
|
cannam@147
|
80 };
|
cannam@147
|
81
|
cannam@147
|
82 class Event {
|
cannam@147
|
83 // An event waiting to be executed. Not for direct use by applications -- promises use this
|
cannam@147
|
84 // internally.
|
cannam@147
|
85
|
cannam@147
|
86 public:
|
cannam@147
|
87 Event();
|
cannam@147
|
88 ~Event() noexcept(false);
|
cannam@147
|
89 KJ_DISALLOW_COPY(Event);
|
cannam@147
|
90
|
cannam@147
|
91 void armDepthFirst();
|
cannam@147
|
92 // Enqueue this event so that `fire()` will be called from the event loop soon.
|
cannam@147
|
93 //
|
cannam@147
|
94 // Events scheduled in this way are executed in depth-first order: if an event callback arms
|
cannam@147
|
95 // more events, those events are placed at the front of the queue (in the order in which they
|
cannam@147
|
96 // were armed), so that they run immediately after the first event's callback returns.
|
cannam@147
|
97 //
|
cannam@147
|
98 // Depth-first event scheduling is appropriate for events that represent simple continuations
|
cannam@147
|
99 // of a previous event that should be globbed together for performance. Depth-first scheduling
|
cannam@147
|
100 // can lead to starvation, so any long-running task must occasionally yield with
|
cannam@147
|
101 // `armBreadthFirst()`. (Promise::then() uses depth-first whereas evalLater() uses
|
cannam@147
|
102 // breadth-first.)
|
cannam@147
|
103 //
|
cannam@147
|
104 // To use breadth-first scheduling instead, use `armBreadthFirst()`.
|
cannam@147
|
105
|
cannam@147
|
106 void armBreadthFirst();
|
cannam@147
|
107 // Like `armDepthFirst()` except that the event is placed at the end of the queue.
|
cannam@147
|
108
|
cannam@147
|
109 kj::String trace();
|
cannam@147
|
110 // Dump debug info about this event.
|
cannam@147
|
111
|
cannam@147
|
112 virtual _::PromiseNode* getInnerForTrace();
|
cannam@147
|
113 // If this event wraps a PromiseNode, get that node. Used for debug tracing.
|
cannam@147
|
114 // Default implementation returns nullptr.
|
cannam@147
|
115
|
cannam@147
|
116 protected:
|
cannam@147
|
117 virtual Maybe<Own<Event>> fire() = 0;
|
cannam@147
|
118 // Fire the event. Possibly returns a pointer to itself, which will be discarded by the
|
cannam@147
|
119 // caller. This is the only way that an event can delete itself as a result of firing, as
|
cannam@147
|
120 // doing so from within fire() will throw an exception.
|
cannam@147
|
121
|
cannam@147
|
122 private:
|
cannam@147
|
123 friend class kj::EventLoop;
|
cannam@147
|
124 EventLoop& loop;
|
cannam@147
|
125 Event* next;
|
cannam@147
|
126 Event** prev;
|
cannam@147
|
127 bool firing = false;
|
cannam@147
|
128 };
|
cannam@147
|
129
|
cannam@147
|
130 class PromiseNode {
|
cannam@147
|
131 // A Promise<T> contains a chain of PromiseNodes tracking the pending transformations.
|
cannam@147
|
132 //
|
cannam@147
|
133 // To reduce generated code bloat, PromiseNode is not a template. Instead, it makes very hacky
|
cannam@147
|
134 // use of pointers to ExceptionOrValue which actually point to ExceptionOr<T>, but are only
|
cannam@147
|
135 // so down-cast in the few places that really need to be templated. Luckily this is all
|
cannam@147
|
136 // internal implementation details.
|
cannam@147
|
137
|
cannam@147
|
138 public:
|
cannam@147
|
139 virtual void onReady(Event& event) noexcept = 0;
|
cannam@147
|
140 // Arms the given event when ready.
|
cannam@147
|
141
|
cannam@147
|
142 virtual void setSelfPointer(Own<PromiseNode>* selfPtr) noexcept;
|
cannam@147
|
143 // Tells the node that `selfPtr` is the pointer that owns this node, and will continue to own
|
cannam@147
|
144 // this node until it is destroyed or setSelfPointer() is called again. ChainPromiseNode uses
|
cannam@147
|
145 // this to shorten redundant chains. The default implementation does nothing; only
|
cannam@147
|
146 // ChainPromiseNode should implement this.
|
cannam@147
|
147
|
cannam@147
|
148 virtual void get(ExceptionOrValue& output) noexcept = 0;
|
cannam@147
|
149 // Get the result. `output` points to an ExceptionOr<T> into which the result will be written.
|
cannam@147
|
150 // Can only be called once, and only after the node is ready. Must be called directly from the
|
cannam@147
|
151 // event loop, with no application code on the stack.
|
cannam@147
|
152
|
cannam@147
|
153 virtual PromiseNode* getInnerForTrace();
|
cannam@147
|
154 // If this node wraps some other PromiseNode, get the wrapped node. Used for debug tracing.
|
cannam@147
|
155 // Default implementation returns nullptr.
|
cannam@147
|
156
|
cannam@147
|
157 protected:
|
cannam@147
|
158 class OnReadyEvent {
|
cannam@147
|
159 // Helper class for implementing onReady().
|
cannam@147
|
160
|
cannam@147
|
161 public:
|
cannam@147
|
162 void init(Event& newEvent);
|
cannam@147
|
163 // Returns true if arm() was already called.
|
cannam@147
|
164
|
cannam@147
|
165 void arm();
|
cannam@147
|
166 // Arms the event if init() has already been called and makes future calls to init() return
|
cannam@147
|
167 // true.
|
cannam@147
|
168
|
cannam@147
|
169 private:
|
cannam@147
|
170 Event* event = nullptr;
|
cannam@147
|
171 };
|
cannam@147
|
172 };
|
cannam@147
|
173
|
cannam@147
|
174 // -------------------------------------------------------------------
|
cannam@147
|
175
|
cannam@147
|
176 class ImmediatePromiseNodeBase: public PromiseNode {
|
cannam@147
|
177 public:
|
cannam@147
|
178 ImmediatePromiseNodeBase();
|
cannam@147
|
179 ~ImmediatePromiseNodeBase() noexcept(false);
|
cannam@147
|
180
|
cannam@147
|
181 void onReady(Event& event) noexcept override;
|
cannam@147
|
182 };
|
cannam@147
|
183
|
cannam@147
|
184 template <typename T>
|
cannam@147
|
185 class ImmediatePromiseNode final: public ImmediatePromiseNodeBase {
|
cannam@147
|
186 // A promise that has already been resolved to an immediate value or exception.
|
cannam@147
|
187
|
cannam@147
|
188 public:
|
cannam@147
|
189 ImmediatePromiseNode(ExceptionOr<T>&& result): result(kj::mv(result)) {}
|
cannam@147
|
190
|
cannam@147
|
191 void get(ExceptionOrValue& output) noexcept override {
|
cannam@147
|
192 output.as<T>() = kj::mv(result);
|
cannam@147
|
193 }
|
cannam@147
|
194
|
cannam@147
|
195 private:
|
cannam@147
|
196 ExceptionOr<T> result;
|
cannam@147
|
197 };
|
cannam@147
|
198
|
cannam@147
|
199 class ImmediateBrokenPromiseNode final: public ImmediatePromiseNodeBase {
|
cannam@147
|
200 public:
|
cannam@147
|
201 ImmediateBrokenPromiseNode(Exception&& exception);
|
cannam@147
|
202
|
cannam@147
|
203 void get(ExceptionOrValue& output) noexcept override;
|
cannam@147
|
204
|
cannam@147
|
205 private:
|
cannam@147
|
206 Exception exception;
|
cannam@147
|
207 };
|
cannam@147
|
208
|
cannam@147
|
209 // -------------------------------------------------------------------
|
cannam@147
|
210
|
cannam@147
|
211 class AttachmentPromiseNodeBase: public PromiseNode {
|
cannam@147
|
212 public:
|
cannam@147
|
213 AttachmentPromiseNodeBase(Own<PromiseNode>&& dependency);
|
cannam@147
|
214
|
cannam@147
|
215 void onReady(Event& event) noexcept override;
|
cannam@147
|
216 void get(ExceptionOrValue& output) noexcept override;
|
cannam@147
|
217 PromiseNode* getInnerForTrace() override;
|
cannam@147
|
218
|
cannam@147
|
219 private:
|
cannam@147
|
220 Own<PromiseNode> dependency;
|
cannam@147
|
221
|
cannam@147
|
222 void dropDependency();
|
cannam@147
|
223
|
cannam@147
|
224 template <typename>
|
cannam@147
|
225 friend class AttachmentPromiseNode;
|
cannam@147
|
226 };
|
cannam@147
|
227
|
cannam@147
|
228 template <typename Attachment>
|
cannam@147
|
229 class AttachmentPromiseNode final: public AttachmentPromiseNodeBase {
|
cannam@147
|
230 // A PromiseNode that holds on to some object (usually, an Own<T>, but could be any movable
|
cannam@147
|
231 // object) until the promise resolves.
|
cannam@147
|
232
|
cannam@147
|
233 public:
|
cannam@147
|
234 AttachmentPromiseNode(Own<PromiseNode>&& dependency, Attachment&& attachment)
|
cannam@147
|
235 : AttachmentPromiseNodeBase(kj::mv(dependency)),
|
cannam@147
|
236 attachment(kj::mv<Attachment>(attachment)) {}
|
cannam@147
|
237
|
cannam@147
|
238 ~AttachmentPromiseNode() noexcept(false) {
|
cannam@147
|
239 // We need to make sure the dependency is deleted before we delete the attachment because the
|
cannam@147
|
240 // dependency may be using the attachment.
|
cannam@147
|
241 dropDependency();
|
cannam@147
|
242 }
|
cannam@147
|
243
|
cannam@147
|
244 private:
|
cannam@147
|
245 Attachment attachment;
|
cannam@147
|
246 };
|
cannam@147
|
247
|
cannam@147
|
248 // -------------------------------------------------------------------
|
cannam@147
|
249
|
cannam@147
|
250 class PtmfHelper {
|
cannam@147
|
251 // This class is a private helper for GetFunctorStartAddress. The class represents the internal
|
cannam@147
|
252 // representation of a pointer-to-member-function.
|
cannam@147
|
253
|
cannam@147
|
254 template <typename... ParamTypes>
|
cannam@147
|
255 friend struct GetFunctorStartAddress;
|
cannam@147
|
256
|
cannam@147
|
257 #if __GNUG__
|
cannam@147
|
258
|
cannam@147
|
259 void* ptr;
|
cannam@147
|
260 ptrdiff_t adj;
|
cannam@147
|
261 // Layout of a pointer-to-member-function used by GCC and compatible compilers.
|
cannam@147
|
262
|
cannam@147
|
263 void* apply(void* obj) {
|
cannam@147
|
264 #if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
|
cannam@147
|
265 if (adj & 1) {
|
cannam@147
|
266 ptrdiff_t voff = (ptrdiff_t)ptr;
|
cannam@147
|
267 #else
|
cannam@147
|
268 ptrdiff_t voff = (ptrdiff_t)ptr;
|
cannam@147
|
269 if (voff & 1) {
|
cannam@147
|
270 voff &= ~1;
|
cannam@147
|
271 #endif
|
cannam@147
|
272 return *(void**)(*(char**)obj + voff);
|
cannam@147
|
273 } else {
|
cannam@147
|
274 return ptr;
|
cannam@147
|
275 }
|
cannam@147
|
276 }
|
cannam@147
|
277
|
cannam@147
|
278 #define BODY \
|
cannam@147
|
279 PtmfHelper result; \
|
cannam@147
|
280 static_assert(sizeof(p) == sizeof(result), "unknown ptmf layout"); \
|
cannam@147
|
281 memcpy(&result, &p, sizeof(result)); \
|
cannam@147
|
282 return result
|
cannam@147
|
283
|
cannam@147
|
284 #else // __GNUG__
|
cannam@147
|
285
|
cannam@147
|
286 void* apply(void* obj) { return nullptr; }
|
cannam@147
|
287 // TODO(port): PTMF instruction address extraction
|
cannam@147
|
288
|
cannam@147
|
289 #define BODY return PtmfHelper{}
|
cannam@147
|
290
|
cannam@147
|
291 #endif // __GNUG__, else
|
cannam@147
|
292
|
cannam@147
|
293 template <typename R, typename C, typename... P, typename F>
|
cannam@147
|
294 static PtmfHelper from(F p) { BODY; }
|
cannam@147
|
295 // Create a PtmfHelper from some arbitrary pointer-to-member-function which is not
|
cannam@147
|
296 // overloaded nor a template. In this case the compiler is able to deduce the full function
|
cannam@147
|
297 // signature directly given the name since there is only one function with that name.
|
cannam@147
|
298
|
cannam@147
|
299 template <typename R, typename C, typename... P>
|
cannam@147
|
300 static PtmfHelper from(R (C::*p)(NoInfer<P>...)) { BODY; }
|
cannam@147
|
301 template <typename R, typename C, typename... P>
|
cannam@147
|
302 static PtmfHelper from(R (C::*p)(NoInfer<P>...) const) { BODY; }
|
cannam@147
|
303 // Create a PtmfHelper from some poniter-to-member-function which is a template. In this case
|
cannam@147
|
304 // the function must match exactly the containing type C, return type R, and parameter types P...
|
cannam@147
|
305 // GetFunctorStartAddress normally specifies exactly the correct C and R, but can only make a
|
cannam@147
|
306 // guess at P. Luckily, if the function parameters are template parameters then it's not
|
cannam@147
|
307 // necessary to be precise about P.
|
cannam@147
|
308 #undef BODY
|
cannam@147
|
309 };
|
cannam@147
|
310
|
cannam@147
|
311 template <typename... ParamTypes>
|
cannam@147
|
312 struct GetFunctorStartAddress {
|
cannam@147
|
313 // Given a functor (any object defining operator()), return the start address of the function,
|
cannam@147
|
314 // suitable for passing to addr2line to obtain a source file/line for debugging purposes.
|
cannam@147
|
315 //
|
cannam@147
|
316 // This turns out to be incredibly hard to implement in the presence of overloaded or templated
|
cannam@147
|
317 // functors. Therefore, we impose these specific restrictions, specific to our use case:
|
cannam@147
|
318 // - Overloading is not allowed, but templating is. (Generally we only intend to support lambdas
|
cannam@147
|
319 // anyway.)
|
cannam@147
|
320 // - The template parameters to GetFunctorStartAddress specify a hint as to the expected
|
cannam@147
|
321 // parameter types. If the functor is templated, its parameters must match exactly these types.
|
cannam@147
|
322 // (If it's not templated, ParamTypes are ignored.)
|
cannam@147
|
323
|
cannam@147
|
324 template <typename Func>
|
cannam@147
|
325 static void* apply(Func&& func) {
|
cannam@147
|
326 typedef decltype(func(instance<ParamTypes>()...)) ReturnType;
|
cannam@147
|
327 return PtmfHelper::from<ReturnType, Decay<Func>, ParamTypes...>(
|
cannam@147
|
328 &Decay<Func>::operator()).apply(&func);
|
cannam@147
|
329 }
|
cannam@147
|
330 };
|
cannam@147
|
331
|
cannam@147
|
332 template <>
|
cannam@147
|
333 struct GetFunctorStartAddress<Void&&>: public GetFunctorStartAddress<> {};
|
cannam@147
|
334 // Hack for TransformPromiseNode use case: an input type of `Void` indicates that the function
|
cannam@147
|
335 // actually has no parameters.
|
cannam@147
|
336
|
cannam@147
|
337 class TransformPromiseNodeBase: public PromiseNode {
|
cannam@147
|
338 public:
|
cannam@147
|
339 TransformPromiseNodeBase(Own<PromiseNode>&& dependency, void* continuationTracePtr);
|
cannam@147
|
340
|
cannam@147
|
341 void onReady(Event& event) noexcept override;
|
cannam@147
|
342 void get(ExceptionOrValue& output) noexcept override;
|
cannam@147
|
343 PromiseNode* getInnerForTrace() override;
|
cannam@147
|
344
|
cannam@147
|
345 private:
|
cannam@147
|
346 Own<PromiseNode> dependency;
|
cannam@147
|
347 void* continuationTracePtr;
|
cannam@147
|
348
|
cannam@147
|
349 void dropDependency();
|
cannam@147
|
350 void getDepResult(ExceptionOrValue& output);
|
cannam@147
|
351
|
cannam@147
|
352 virtual void getImpl(ExceptionOrValue& output) = 0;
|
cannam@147
|
353
|
cannam@147
|
354 template <typename, typename, typename, typename>
|
cannam@147
|
355 friend class TransformPromiseNode;
|
cannam@147
|
356 };
|
cannam@147
|
357
|
cannam@147
|
358 template <typename T, typename DepT, typename Func, typename ErrorFunc>
|
cannam@147
|
359 class TransformPromiseNode final: public TransformPromiseNodeBase {
|
cannam@147
|
360 // A PromiseNode that transforms the result of another PromiseNode through an application-provided
|
cannam@147
|
361 // function (implements `then()`).
|
cannam@147
|
362
|
cannam@147
|
363 public:
|
cannam@147
|
364 TransformPromiseNode(Own<PromiseNode>&& dependency, Func&& func, ErrorFunc&& errorHandler)
|
cannam@147
|
365 : TransformPromiseNodeBase(kj::mv(dependency),
|
cannam@147
|
366 GetFunctorStartAddress<DepT&&>::apply(func)),
|
cannam@147
|
367 func(kj::fwd<Func>(func)), errorHandler(kj::fwd<ErrorFunc>(errorHandler)) {}
|
cannam@147
|
368
|
cannam@147
|
369 ~TransformPromiseNode() noexcept(false) {
|
cannam@147
|
370 // We need to make sure the dependency is deleted before we delete the continuations because it
|
cannam@147
|
371 // is a common pattern for the continuations to hold ownership of objects that might be in-use
|
cannam@147
|
372 // by the dependency.
|
cannam@147
|
373 dropDependency();
|
cannam@147
|
374 }
|
cannam@147
|
375
|
cannam@147
|
376 private:
|
cannam@147
|
377 Func func;
|
cannam@147
|
378 ErrorFunc errorHandler;
|
cannam@147
|
379
|
cannam@147
|
380 void getImpl(ExceptionOrValue& output) override {
|
cannam@147
|
381 ExceptionOr<DepT> depResult;
|
cannam@147
|
382 getDepResult(depResult);
|
cannam@147
|
383 KJ_IF_MAYBE(depException, depResult.exception) {
|
cannam@147
|
384 output.as<T>() = handle(
|
cannam@147
|
385 MaybeVoidCaller<Exception, FixVoid<ReturnType<ErrorFunc, Exception>>>::apply(
|
cannam@147
|
386 errorHandler, kj::mv(*depException)));
|
cannam@147
|
387 } else KJ_IF_MAYBE(depValue, depResult.value) {
|
cannam@147
|
388 output.as<T>() = handle(MaybeVoidCaller<DepT, T>::apply(func, kj::mv(*depValue)));
|
cannam@147
|
389 }
|
cannam@147
|
390 }
|
cannam@147
|
391
|
cannam@147
|
392 ExceptionOr<T> handle(T&& value) {
|
cannam@147
|
393 return kj::mv(value);
|
cannam@147
|
394 }
|
cannam@147
|
395 ExceptionOr<T> handle(PropagateException::Bottom&& value) {
|
cannam@147
|
396 return ExceptionOr<T>(false, value.asException());
|
cannam@147
|
397 }
|
cannam@147
|
398 };
|
cannam@147
|
399
|
cannam@147
|
400 // -------------------------------------------------------------------
|
cannam@147
|
401
|
cannam@147
|
402 class ForkHubBase;
|
cannam@147
|
403
|
cannam@147
|
404 class ForkBranchBase: public PromiseNode {
|
cannam@147
|
405 public:
|
cannam@147
|
406 ForkBranchBase(Own<ForkHubBase>&& hub);
|
cannam@147
|
407 ~ForkBranchBase() noexcept(false);
|
cannam@147
|
408
|
cannam@147
|
409 void hubReady() noexcept;
|
cannam@147
|
410 // Called by the hub to indicate that it is ready.
|
cannam@147
|
411
|
cannam@147
|
412 // implements PromiseNode ------------------------------------------
|
cannam@147
|
413 void onReady(Event& event) noexcept override;
|
cannam@147
|
414 PromiseNode* getInnerForTrace() override;
|
cannam@147
|
415
|
cannam@147
|
416 protected:
|
cannam@147
|
417 inline ExceptionOrValue& getHubResultRef();
|
cannam@147
|
418
|
cannam@147
|
419 void releaseHub(ExceptionOrValue& output);
|
cannam@147
|
420 // Release the hub. If an exception is thrown, add it to `output`.
|
cannam@147
|
421
|
cannam@147
|
422 private:
|
cannam@147
|
423 OnReadyEvent onReadyEvent;
|
cannam@147
|
424
|
cannam@147
|
425 Own<ForkHubBase> hub;
|
cannam@147
|
426 ForkBranchBase* next = nullptr;
|
cannam@147
|
427 ForkBranchBase** prevPtr = nullptr;
|
cannam@147
|
428
|
cannam@147
|
429 friend class ForkHubBase;
|
cannam@147
|
430 };
|
cannam@147
|
431
|
cannam@147
|
432 template <typename T> T copyOrAddRef(T& t) { return t; }
|
cannam@147
|
433 template <typename T> Own<T> copyOrAddRef(Own<T>& t) { return t->addRef(); }
|
cannam@147
|
434
|
cannam@147
|
435 template <typename T>
|
cannam@147
|
436 class ForkBranch final: public ForkBranchBase {
|
cannam@147
|
437 // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives
|
cannam@147
|
438 // a const reference.
|
cannam@147
|
439
|
cannam@147
|
440 public:
|
cannam@147
|
441 ForkBranch(Own<ForkHubBase>&& hub): ForkBranchBase(kj::mv(hub)) {}
|
cannam@147
|
442
|
cannam@147
|
443 void get(ExceptionOrValue& output) noexcept override {
|
cannam@147
|
444 ExceptionOr<T>& hubResult = getHubResultRef().template as<T>();
|
cannam@147
|
445 KJ_IF_MAYBE(value, hubResult.value) {
|
cannam@147
|
446 output.as<T>().value = copyOrAddRef(*value);
|
cannam@147
|
447 } else {
|
cannam@147
|
448 output.as<T>().value = nullptr;
|
cannam@147
|
449 }
|
cannam@147
|
450 output.exception = hubResult.exception;
|
cannam@147
|
451 releaseHub(output);
|
cannam@147
|
452 }
|
cannam@147
|
453 };
|
cannam@147
|
454
|
cannam@147
|
455 template <typename T, size_t index>
|
cannam@147
|
456 class SplitBranch final: public ForkBranchBase {
|
cannam@147
|
457 // A PromiseNode that implements one branch of a fork -- i.e. one of the branches that receives
|
cannam@147
|
458 // a const reference.
|
cannam@147
|
459
|
cannam@147
|
460 public:
|
cannam@147
|
461 SplitBranch(Own<ForkHubBase>&& hub): ForkBranchBase(kj::mv(hub)) {}
|
cannam@147
|
462
|
cannam@147
|
463 typedef kj::Decay<decltype(kj::get<index>(kj::instance<T>()))> Element;
|
cannam@147
|
464
|
cannam@147
|
465 void get(ExceptionOrValue& output) noexcept override {
|
cannam@147
|
466 ExceptionOr<T>& hubResult = getHubResultRef().template as<T>();
|
cannam@147
|
467 KJ_IF_MAYBE(value, hubResult.value) {
|
cannam@147
|
468 output.as<Element>().value = kj::mv(kj::get<index>(*value));
|
cannam@147
|
469 } else {
|
cannam@147
|
470 output.as<Element>().value = nullptr;
|
cannam@147
|
471 }
|
cannam@147
|
472 output.exception = hubResult.exception;
|
cannam@147
|
473 releaseHub(output);
|
cannam@147
|
474 }
|
cannam@147
|
475 };
|
cannam@147
|
476
|
cannam@147
|
477 // -------------------------------------------------------------------
|
cannam@147
|
478
|
cannam@147
|
479 class ForkHubBase: public Refcounted, protected Event {
|
cannam@147
|
480 public:
|
cannam@147
|
481 ForkHubBase(Own<PromiseNode>&& inner, ExceptionOrValue& resultRef);
|
cannam@147
|
482
|
cannam@147
|
483 inline ExceptionOrValue& getResultRef() { return resultRef; }
|
cannam@147
|
484
|
cannam@147
|
485 private:
|
cannam@147
|
486 Own<PromiseNode> inner;
|
cannam@147
|
487 ExceptionOrValue& resultRef;
|
cannam@147
|
488
|
cannam@147
|
489 ForkBranchBase* headBranch = nullptr;
|
cannam@147
|
490 ForkBranchBase** tailBranch = &headBranch;
|
cannam@147
|
491 // Tail becomes null once the inner promise is ready and all branches have been notified.
|
cannam@147
|
492
|
cannam@147
|
493 Maybe<Own<Event>> fire() override;
|
cannam@147
|
494 _::PromiseNode* getInnerForTrace() override;
|
cannam@147
|
495
|
cannam@147
|
496 friend class ForkBranchBase;
|
cannam@147
|
497 };
|
cannam@147
|
498
|
cannam@147
|
499 template <typename T>
|
cannam@147
|
500 class ForkHub final: public ForkHubBase {
|
cannam@147
|
501 // A PromiseNode that implements the hub of a fork. The first call to Promise::fork() replaces
|
cannam@147
|
502 // the promise's outer node with a ForkHub, and subsequent calls add branches to that hub (if
|
cannam@147
|
503 // possible).
|
cannam@147
|
504
|
cannam@147
|
505 public:
|
cannam@147
|
506 ForkHub(Own<PromiseNode>&& inner): ForkHubBase(kj::mv(inner), result) {}
|
cannam@147
|
507
|
cannam@147
|
508 Promise<_::UnfixVoid<T>> addBranch() {
|
cannam@147
|
509 return Promise<_::UnfixVoid<T>>(false, kj::heap<ForkBranch<T>>(addRef(*this)));
|
cannam@147
|
510 }
|
cannam@147
|
511
|
cannam@147
|
512 _::SplitTuplePromise<T> split() {
|
cannam@147
|
513 return splitImpl(MakeIndexes<tupleSize<T>()>());
|
cannam@147
|
514 }
|
cannam@147
|
515
|
cannam@147
|
516 private:
|
cannam@147
|
517 ExceptionOr<T> result;
|
cannam@147
|
518
|
cannam@147
|
519 template <size_t... indexes>
|
cannam@147
|
520 _::SplitTuplePromise<T> splitImpl(Indexes<indexes...>) {
|
cannam@147
|
521 return kj::tuple(addSplit<indexes>()...);
|
cannam@147
|
522 }
|
cannam@147
|
523
|
cannam@147
|
524 template <size_t index>
|
cannam@147
|
525 Promise<JoinPromises<typename SplitBranch<T, index>::Element>> addSplit() {
|
cannam@147
|
526 return Promise<JoinPromises<typename SplitBranch<T, index>::Element>>(
|
cannam@147
|
527 false, maybeChain(kj::heap<SplitBranch<T, index>>(addRef(*this)),
|
cannam@147
|
528 implicitCast<typename SplitBranch<T, index>::Element*>(nullptr)));
|
cannam@147
|
529 }
|
cannam@147
|
530 };
|
cannam@147
|
531
|
cannam@147
|
532 inline ExceptionOrValue& ForkBranchBase::getHubResultRef() {
|
cannam@147
|
533 return hub->getResultRef();
|
cannam@147
|
534 }
|
cannam@147
|
535
|
cannam@147
|
536 // -------------------------------------------------------------------
|
cannam@147
|
537
|
cannam@147
|
538 class ChainPromiseNode final: public PromiseNode, public Event {
|
cannam@147
|
539 // Promise node which reduces Promise<Promise<T>> to Promise<T>.
|
cannam@147
|
540 //
|
cannam@147
|
541 // `Event` is only a public base class because otherwise we can't cast Own<ChainPromiseNode> to
|
cannam@147
|
542 // Own<Event>. Ugh, templates and private...
|
cannam@147
|
543
|
cannam@147
|
544 public:
|
cannam@147
|
545 explicit ChainPromiseNode(Own<PromiseNode> inner);
|
cannam@147
|
546 ~ChainPromiseNode() noexcept(false);
|
cannam@147
|
547
|
cannam@147
|
548 void onReady(Event& event) noexcept override;
|
cannam@147
|
549 void setSelfPointer(Own<PromiseNode>* selfPtr) noexcept override;
|
cannam@147
|
550 void get(ExceptionOrValue& output) noexcept override;
|
cannam@147
|
551 PromiseNode* getInnerForTrace() override;
|
cannam@147
|
552
|
cannam@147
|
553 private:
|
cannam@147
|
554 enum State {
|
cannam@147
|
555 STEP1,
|
cannam@147
|
556 STEP2
|
cannam@147
|
557 };
|
cannam@147
|
558
|
cannam@147
|
559 State state;
|
cannam@147
|
560
|
cannam@147
|
561 Own<PromiseNode> inner;
|
cannam@147
|
562 // In STEP1, a PromiseNode for a Promise<T>.
|
cannam@147
|
563 // In STEP2, a PromiseNode for a T.
|
cannam@147
|
564
|
cannam@147
|
565 Event* onReadyEvent = nullptr;
|
cannam@147
|
566 Own<PromiseNode>* selfPtr = nullptr;
|
cannam@147
|
567
|
cannam@147
|
568 Maybe<Own<Event>> fire() override;
|
cannam@147
|
569 };
|
cannam@147
|
570
|
cannam@147
|
571 template <typename T>
|
cannam@147
|
572 Own<PromiseNode> maybeChain(Own<PromiseNode>&& node, Promise<T>*) {
|
cannam@147
|
573 return heap<ChainPromiseNode>(kj::mv(node));
|
cannam@147
|
574 }
|
cannam@147
|
575
|
cannam@147
|
576 template <typename T>
|
cannam@147
|
577 Own<PromiseNode>&& maybeChain(Own<PromiseNode>&& node, T*) {
|
cannam@147
|
578 return kj::mv(node);
|
cannam@147
|
579 }
|
cannam@147
|
580
|
cannam@147
|
581 // -------------------------------------------------------------------
|
cannam@147
|
582
|
cannam@147
|
583 class ExclusiveJoinPromiseNode final: public PromiseNode {
|
cannam@147
|
584 public:
|
cannam@147
|
585 ExclusiveJoinPromiseNode(Own<PromiseNode> left, Own<PromiseNode> right);
|
cannam@147
|
586 ~ExclusiveJoinPromiseNode() noexcept(false);
|
cannam@147
|
587
|
cannam@147
|
588 void onReady(Event& event) noexcept override;
|
cannam@147
|
589 void get(ExceptionOrValue& output) noexcept override;
|
cannam@147
|
590 PromiseNode* getInnerForTrace() override;
|
cannam@147
|
591
|
cannam@147
|
592 private:
|
cannam@147
|
593 class Branch: public Event {
|
cannam@147
|
594 public:
|
cannam@147
|
595 Branch(ExclusiveJoinPromiseNode& joinNode, Own<PromiseNode> dependency);
|
cannam@147
|
596 ~Branch() noexcept(false);
|
cannam@147
|
597
|
cannam@147
|
598 bool get(ExceptionOrValue& output);
|
cannam@147
|
599 // Returns true if this is the side that finished.
|
cannam@147
|
600
|
cannam@147
|
601 Maybe<Own<Event>> fire() override;
|
cannam@147
|
602 _::PromiseNode* getInnerForTrace() override;
|
cannam@147
|
603
|
cannam@147
|
604 private:
|
cannam@147
|
605 ExclusiveJoinPromiseNode& joinNode;
|
cannam@147
|
606 Own<PromiseNode> dependency;
|
cannam@147
|
607 };
|
cannam@147
|
608
|
cannam@147
|
609 Branch left;
|
cannam@147
|
610 Branch right;
|
cannam@147
|
611 OnReadyEvent onReadyEvent;
|
cannam@147
|
612 };
|
cannam@147
|
613
|
cannam@147
|
614 // -------------------------------------------------------------------
|
cannam@147
|
615
|
cannam@147
|
616 class ArrayJoinPromiseNodeBase: public PromiseNode {
|
cannam@147
|
617 public:
|
cannam@147
|
618 ArrayJoinPromiseNodeBase(Array<Own<PromiseNode>> promises,
|
cannam@147
|
619 ExceptionOrValue* resultParts, size_t partSize);
|
cannam@147
|
620 ~ArrayJoinPromiseNodeBase() noexcept(false);
|
cannam@147
|
621
|
cannam@147
|
622 void onReady(Event& event) noexcept override final;
|
cannam@147
|
623 void get(ExceptionOrValue& output) noexcept override final;
|
cannam@147
|
624 PromiseNode* getInnerForTrace() override final;
|
cannam@147
|
625
|
cannam@147
|
626 protected:
|
cannam@147
|
627 virtual void getNoError(ExceptionOrValue& output) noexcept = 0;
|
cannam@147
|
628 // Called to compile the result only in the case where there were no errors.
|
cannam@147
|
629
|
cannam@147
|
630 private:
|
cannam@147
|
631 uint countLeft;
|
cannam@147
|
632 OnReadyEvent onReadyEvent;
|
cannam@147
|
633
|
cannam@147
|
634 class Branch final: public Event {
|
cannam@147
|
635 public:
|
cannam@147
|
636 Branch(ArrayJoinPromiseNodeBase& joinNode, Own<PromiseNode> dependency,
|
cannam@147
|
637 ExceptionOrValue& output);
|
cannam@147
|
638 ~Branch() noexcept(false);
|
cannam@147
|
639
|
cannam@147
|
640 Maybe<Own<Event>> fire() override;
|
cannam@147
|
641 _::PromiseNode* getInnerForTrace() override;
|
cannam@147
|
642
|
cannam@147
|
643 Maybe<Exception> getPart();
|
cannam@147
|
644 // Calls dependency->get(output). If there was an exception, return it.
|
cannam@147
|
645
|
cannam@147
|
646 private:
|
cannam@147
|
647 ArrayJoinPromiseNodeBase& joinNode;
|
cannam@147
|
648 Own<PromiseNode> dependency;
|
cannam@147
|
649 ExceptionOrValue& output;
|
cannam@147
|
650 };
|
cannam@147
|
651
|
cannam@147
|
652 Array<Branch> branches;
|
cannam@147
|
653 };
|
cannam@147
|
654
|
cannam@147
|
655 template <typename T>
|
cannam@147
|
656 class ArrayJoinPromiseNode final: public ArrayJoinPromiseNodeBase {
|
cannam@147
|
657 public:
|
cannam@147
|
658 ArrayJoinPromiseNode(Array<Own<PromiseNode>> promises,
|
cannam@147
|
659 Array<ExceptionOr<T>> resultParts)
|
cannam@147
|
660 : ArrayJoinPromiseNodeBase(kj::mv(promises), resultParts.begin(), sizeof(ExceptionOr<T>)),
|
cannam@147
|
661 resultParts(kj::mv(resultParts)) {}
|
cannam@147
|
662
|
cannam@147
|
663 protected:
|
cannam@147
|
664 void getNoError(ExceptionOrValue& output) noexcept override {
|
cannam@147
|
665 auto builder = heapArrayBuilder<T>(resultParts.size());
|
cannam@147
|
666 for (auto& part: resultParts) {
|
cannam@147
|
667 KJ_IASSERT(part.value != nullptr,
|
cannam@147
|
668 "Bug in KJ promise framework: Promise result had neither value no exception.");
|
cannam@147
|
669 builder.add(kj::mv(*_::readMaybe(part.value)));
|
cannam@147
|
670 }
|
cannam@147
|
671 output.as<Array<T>>() = builder.finish();
|
cannam@147
|
672 }
|
cannam@147
|
673
|
cannam@147
|
674 private:
|
cannam@147
|
675 Array<ExceptionOr<T>> resultParts;
|
cannam@147
|
676 };
|
cannam@147
|
677
|
cannam@147
|
678 template <>
|
cannam@147
|
679 class ArrayJoinPromiseNode<void> final: public ArrayJoinPromiseNodeBase {
|
cannam@147
|
680 public:
|
cannam@147
|
681 ArrayJoinPromiseNode(Array<Own<PromiseNode>> promises,
|
cannam@147
|
682 Array<ExceptionOr<_::Void>> resultParts);
|
cannam@147
|
683 ~ArrayJoinPromiseNode();
|
cannam@147
|
684
|
cannam@147
|
685 protected:
|
cannam@147
|
686 void getNoError(ExceptionOrValue& output) noexcept override;
|
cannam@147
|
687
|
cannam@147
|
688 private:
|
cannam@147
|
689 Array<ExceptionOr<_::Void>> resultParts;
|
cannam@147
|
690 };
|
cannam@147
|
691
|
cannam@147
|
692 // -------------------------------------------------------------------
|
cannam@147
|
693
|
cannam@147
|
694 class EagerPromiseNodeBase: public PromiseNode, protected Event {
|
cannam@147
|
695 // A PromiseNode that eagerly evaluates its dependency even if its dependent does not eagerly
|
cannam@147
|
696 // evaluate it.
|
cannam@147
|
697
|
cannam@147
|
698 public:
|
cannam@147
|
699 EagerPromiseNodeBase(Own<PromiseNode>&& dependency, ExceptionOrValue& resultRef);
|
cannam@147
|
700
|
cannam@147
|
701 void onReady(Event& event) noexcept override;
|
cannam@147
|
702 PromiseNode* getInnerForTrace() override;
|
cannam@147
|
703
|
cannam@147
|
704 private:
|
cannam@147
|
705 Own<PromiseNode> dependency;
|
cannam@147
|
706 OnReadyEvent onReadyEvent;
|
cannam@147
|
707
|
cannam@147
|
708 ExceptionOrValue& resultRef;
|
cannam@147
|
709
|
cannam@147
|
710 Maybe<Own<Event>> fire() override;
|
cannam@147
|
711 };
|
cannam@147
|
712
|
cannam@147
|
713 template <typename T>
|
cannam@147
|
714 class EagerPromiseNode final: public EagerPromiseNodeBase {
|
cannam@147
|
715 public:
|
cannam@147
|
716 EagerPromiseNode(Own<PromiseNode>&& dependency)
|
cannam@147
|
717 : EagerPromiseNodeBase(kj::mv(dependency), result) {}
|
cannam@147
|
718
|
cannam@147
|
719 void get(ExceptionOrValue& output) noexcept override {
|
cannam@147
|
720 output.as<T>() = kj::mv(result);
|
cannam@147
|
721 }
|
cannam@147
|
722
|
cannam@147
|
723 private:
|
cannam@147
|
724 ExceptionOr<T> result;
|
cannam@147
|
725 };
|
cannam@147
|
726
|
cannam@147
|
727 template <typename T>
|
cannam@147
|
728 Own<PromiseNode> spark(Own<PromiseNode>&& node) {
|
cannam@147
|
729 // Forces evaluation of the given node to begin as soon as possible, even if no one is waiting
|
cannam@147
|
730 // on it.
|
cannam@147
|
731 return heap<EagerPromiseNode<T>>(kj::mv(node));
|
cannam@147
|
732 }
|
cannam@147
|
733
|
cannam@147
|
734 // -------------------------------------------------------------------
|
cannam@147
|
735
|
cannam@147
|
736 class AdapterPromiseNodeBase: public PromiseNode {
|
cannam@147
|
737 public:
|
cannam@147
|
738 void onReady(Event& event) noexcept override;
|
cannam@147
|
739
|
cannam@147
|
740 protected:
|
cannam@147
|
741 inline void setReady() {
|
cannam@147
|
742 onReadyEvent.arm();
|
cannam@147
|
743 }
|
cannam@147
|
744
|
cannam@147
|
745 private:
|
cannam@147
|
746 OnReadyEvent onReadyEvent;
|
cannam@147
|
747 };
|
cannam@147
|
748
|
cannam@147
|
749 template <typename T, typename Adapter>
|
cannam@147
|
750 class AdapterPromiseNode final: public AdapterPromiseNodeBase,
|
cannam@147
|
751 private PromiseFulfiller<UnfixVoid<T>> {
|
cannam@147
|
752 // A PromiseNode that wraps a PromiseAdapter.
|
cannam@147
|
753
|
cannam@147
|
754 public:
|
cannam@147
|
755 template <typename... Params>
|
cannam@147
|
756 AdapterPromiseNode(Params&&... params)
|
cannam@147
|
757 : adapter(static_cast<PromiseFulfiller<UnfixVoid<T>>&>(*this), kj::fwd<Params>(params)...) {}
|
cannam@147
|
758
|
cannam@147
|
759 void get(ExceptionOrValue& output) noexcept override {
|
cannam@147
|
760 KJ_IREQUIRE(!isWaiting());
|
cannam@147
|
761 output.as<T>() = kj::mv(result);
|
cannam@147
|
762 }
|
cannam@147
|
763
|
cannam@147
|
764 private:
|
cannam@147
|
765 ExceptionOr<T> result;
|
cannam@147
|
766 bool waiting = true;
|
cannam@147
|
767 Adapter adapter;
|
cannam@147
|
768
|
cannam@147
|
769 void fulfill(T&& value) override {
|
cannam@147
|
770 if (waiting) {
|
cannam@147
|
771 waiting = false;
|
cannam@147
|
772 result = ExceptionOr<T>(kj::mv(value));
|
cannam@147
|
773 setReady();
|
cannam@147
|
774 }
|
cannam@147
|
775 }
|
cannam@147
|
776
|
cannam@147
|
777 void reject(Exception&& exception) override {
|
cannam@147
|
778 if (waiting) {
|
cannam@147
|
779 waiting = false;
|
cannam@147
|
780 result = ExceptionOr<T>(false, kj::mv(exception));
|
cannam@147
|
781 setReady();
|
cannam@147
|
782 }
|
cannam@147
|
783 }
|
cannam@147
|
784
|
cannam@147
|
785 bool isWaiting() override {
|
cannam@147
|
786 return waiting;
|
cannam@147
|
787 }
|
cannam@147
|
788 };
|
cannam@147
|
789
|
cannam@147
|
790 } // namespace _ (private)
|
cannam@147
|
791
|
cannam@147
|
792 // =======================================================================================
|
cannam@147
|
793
|
cannam@147
|
794 template <typename T>
|
cannam@147
|
795 Promise<T>::Promise(_::FixVoid<T> value)
|
cannam@147
|
796 : PromiseBase(heap<_::ImmediatePromiseNode<_::FixVoid<T>>>(kj::mv(value))) {}
|
cannam@147
|
797
|
cannam@147
|
798 template <typename T>
|
cannam@147
|
799 Promise<T>::Promise(kj::Exception&& exception)
|
cannam@147
|
800 : PromiseBase(heap<_::ImmediateBrokenPromiseNode>(kj::mv(exception))) {}
|
cannam@147
|
801
|
cannam@147
|
802 template <typename T>
|
cannam@147
|
803 template <typename Func, typename ErrorFunc>
|
cannam@147
|
804 PromiseForResult<Func, T> Promise<T>::then(Func&& func, ErrorFunc&& errorHandler) {
|
cannam@147
|
805 typedef _::FixVoid<_::ReturnType<Func, T>> ResultT;
|
cannam@147
|
806
|
cannam@147
|
807 Own<_::PromiseNode> intermediate =
|
cannam@147
|
808 heap<_::TransformPromiseNode<ResultT, _::FixVoid<T>, Func, ErrorFunc>>(
|
cannam@147
|
809 kj::mv(node), kj::fwd<Func>(func), kj::fwd<ErrorFunc>(errorHandler));
|
cannam@147
|
810 return PromiseForResult<Func, T>(false,
|
cannam@147
|
811 _::maybeChain(kj::mv(intermediate), implicitCast<ResultT*>(nullptr)));
|
cannam@147
|
812 }
|
cannam@147
|
813
|
cannam@147
|
814 namespace _ { // private
|
cannam@147
|
815
|
cannam@147
|
816 template <typename T>
|
cannam@147
|
817 struct IdentityFunc {
|
cannam@147
|
818 inline T operator()(T&& value) const {
|
cannam@147
|
819 return kj::mv(value);
|
cannam@147
|
820 }
|
cannam@147
|
821 };
|
cannam@147
|
822 template <typename T>
|
cannam@147
|
823 struct IdentityFunc<Promise<T>> {
|
cannam@147
|
824 inline Promise<T> operator()(T&& value) const {
|
cannam@147
|
825 return kj::mv(value);
|
cannam@147
|
826 }
|
cannam@147
|
827 };
|
cannam@147
|
828 template <>
|
cannam@147
|
829 struct IdentityFunc<void> {
|
cannam@147
|
830 inline void operator()() const {}
|
cannam@147
|
831 };
|
cannam@147
|
832 template <>
|
cannam@147
|
833 struct IdentityFunc<Promise<void>> {
|
cannam@147
|
834 Promise<void> operator()() const;
|
cannam@147
|
835 // This can't be inline because it will make the translation unit depend on kj-async. Awkwardly,
|
cannam@147
|
836 // Cap'n Proto relies on being able to include this header without creating such a link-time
|
cannam@147
|
837 // dependency.
|
cannam@147
|
838 };
|
cannam@147
|
839
|
cannam@147
|
840 } // namespace _ (private)
|
cannam@147
|
841
|
cannam@147
|
842 template <typename T>
|
cannam@147
|
843 template <typename ErrorFunc>
|
cannam@147
|
844 Promise<T> Promise<T>::catch_(ErrorFunc&& errorHandler) {
|
cannam@147
|
845 // then()'s ErrorFunc can only return a Promise if Func also returns a Promise. In this case,
|
cannam@147
|
846 // Func is being filled in automatically. We want to make sure ErrorFunc can return a Promise,
|
cannam@147
|
847 // but we don't want the extra overhead of promise chaining if ErrorFunc doesn't actually
|
cannam@147
|
848 // return a promise. So we make our Func return match ErrorFunc.
|
cannam@147
|
849 return then(_::IdentityFunc<decltype(errorHandler(instance<Exception&&>()))>(),
|
cannam@147
|
850 kj::fwd<ErrorFunc>(errorHandler));
|
cannam@147
|
851 }
|
cannam@147
|
852
|
cannam@147
|
853 template <typename T>
|
cannam@147
|
854 T Promise<T>::wait(WaitScope& waitScope) {
|
cannam@147
|
855 _::ExceptionOr<_::FixVoid<T>> result;
|
cannam@147
|
856
|
cannam@147
|
857 waitImpl(kj::mv(node), result, waitScope);
|
cannam@147
|
858
|
cannam@147
|
859 KJ_IF_MAYBE(value, result.value) {
|
cannam@147
|
860 KJ_IF_MAYBE(exception, result.exception) {
|
cannam@147
|
861 throwRecoverableException(kj::mv(*exception));
|
cannam@147
|
862 }
|
cannam@147
|
863 return _::returnMaybeVoid(kj::mv(*value));
|
cannam@147
|
864 } else KJ_IF_MAYBE(exception, result.exception) {
|
cannam@147
|
865 throwFatalException(kj::mv(*exception));
|
cannam@147
|
866 } else {
|
cannam@147
|
867 // Result contained neither a value nor an exception?
|
cannam@147
|
868 KJ_UNREACHABLE;
|
cannam@147
|
869 }
|
cannam@147
|
870 }
|
cannam@147
|
871
|
cannam@147
|
872 template <>
|
cannam@147
|
873 inline void Promise<void>::wait(WaitScope& waitScope) {
|
cannam@147
|
874 // Override <void> case to use throwRecoverableException().
|
cannam@147
|
875
|
cannam@147
|
876 _::ExceptionOr<_::Void> result;
|
cannam@147
|
877
|
cannam@147
|
878 waitImpl(kj::mv(node), result, waitScope);
|
cannam@147
|
879
|
cannam@147
|
880 if (result.value != nullptr) {
|
cannam@147
|
881 KJ_IF_MAYBE(exception, result.exception) {
|
cannam@147
|
882 throwRecoverableException(kj::mv(*exception));
|
cannam@147
|
883 }
|
cannam@147
|
884 } else KJ_IF_MAYBE(exception, result.exception) {
|
cannam@147
|
885 throwRecoverableException(kj::mv(*exception));
|
cannam@147
|
886 } else {
|
cannam@147
|
887 // Result contained neither a value nor an exception?
|
cannam@147
|
888 KJ_UNREACHABLE;
|
cannam@147
|
889 }
|
cannam@147
|
890 }
|
cannam@147
|
891
|
cannam@147
|
892 template <typename T>
|
cannam@147
|
893 ForkedPromise<T> Promise<T>::fork() {
|
cannam@147
|
894 return ForkedPromise<T>(false, refcounted<_::ForkHub<_::FixVoid<T>>>(kj::mv(node)));
|
cannam@147
|
895 }
|
cannam@147
|
896
|
cannam@147
|
897 template <typename T>
|
cannam@147
|
898 Promise<T> ForkedPromise<T>::addBranch() {
|
cannam@147
|
899 return hub->addBranch();
|
cannam@147
|
900 }
|
cannam@147
|
901
|
cannam@147
|
902 template <typename T>
|
cannam@147
|
903 _::SplitTuplePromise<T> Promise<T>::split() {
|
cannam@147
|
904 return refcounted<_::ForkHub<_::FixVoid<T>>>(kj::mv(node))->split();
|
cannam@147
|
905 }
|
cannam@147
|
906
|
cannam@147
|
907 template <typename T>
|
cannam@147
|
908 Promise<T> Promise<T>::exclusiveJoin(Promise<T>&& other) {
|
cannam@147
|
909 return Promise(false, heap<_::ExclusiveJoinPromiseNode>(kj::mv(node), kj::mv(other.node)));
|
cannam@147
|
910 }
|
cannam@147
|
911
|
cannam@147
|
912 template <typename T>
|
cannam@147
|
913 template <typename... Attachments>
|
cannam@147
|
914 Promise<T> Promise<T>::attach(Attachments&&... attachments) {
|
cannam@147
|
915 return Promise(false, kj::heap<_::AttachmentPromiseNode<Tuple<Attachments...>>>(
|
cannam@147
|
916 kj::mv(node), kj::tuple(kj::fwd<Attachments>(attachments)...)));
|
cannam@147
|
917 }
|
cannam@147
|
918
|
cannam@147
|
919 template <typename T>
|
cannam@147
|
920 template <typename ErrorFunc>
|
cannam@147
|
921 Promise<T> Promise<T>::eagerlyEvaluate(ErrorFunc&& errorHandler) {
|
cannam@147
|
922 // See catch_() for commentary.
|
cannam@147
|
923 return Promise(false, _::spark<_::FixVoid<T>>(then(
|
cannam@147
|
924 _::IdentityFunc<decltype(errorHandler(instance<Exception&&>()))>(),
|
cannam@147
|
925 kj::fwd<ErrorFunc>(errorHandler)).node));
|
cannam@147
|
926 }
|
cannam@147
|
927
|
cannam@147
|
928 template <typename T>
|
cannam@147
|
929 Promise<T> Promise<T>::eagerlyEvaluate(decltype(nullptr)) {
|
cannam@147
|
930 return Promise(false, _::spark<_::FixVoid<T>>(kj::mv(node)));
|
cannam@147
|
931 }
|
cannam@147
|
932
|
cannam@147
|
933 template <typename T>
|
cannam@147
|
934 kj::String Promise<T>::trace() {
|
cannam@147
|
935 return PromiseBase::trace();
|
cannam@147
|
936 }
|
cannam@147
|
937
|
cannam@147
|
938 template <typename Func>
|
cannam@147
|
939 inline PromiseForResult<Func, void> evalLater(Func&& func) {
|
cannam@147
|
940 return _::yield().then(kj::fwd<Func>(func), _::PropagateException());
|
cannam@147
|
941 }
|
cannam@147
|
942
|
cannam@147
|
943 template <typename Func>
|
cannam@147
|
944 inline PromiseForResult<Func, void> evalNow(Func&& func) {
|
cannam@147
|
945 PromiseForResult<Func, void> result = nullptr;
|
cannam@147
|
946 KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
|
cannam@147
|
947 result = func();
|
cannam@147
|
948 })) {
|
cannam@147
|
949 result = kj::mv(*e);
|
cannam@147
|
950 }
|
cannam@147
|
951 return result;
|
cannam@147
|
952 }
|
cannam@147
|
953
|
cannam@147
|
954 template <typename T>
|
cannam@147
|
955 template <typename ErrorFunc>
|
cannam@147
|
956 void Promise<T>::detach(ErrorFunc&& errorHandler) {
|
cannam@147
|
957 return _::detach(then([](T&&) {}, kj::fwd<ErrorFunc>(errorHandler)));
|
cannam@147
|
958 }
|
cannam@147
|
959
|
cannam@147
|
960 template <>
|
cannam@147
|
961 template <typename ErrorFunc>
|
cannam@147
|
962 void Promise<void>::detach(ErrorFunc&& errorHandler) {
|
cannam@147
|
963 return _::detach(then([]() {}, kj::fwd<ErrorFunc>(errorHandler)));
|
cannam@147
|
964 }
|
cannam@147
|
965
|
cannam@147
|
966 template <typename T>
|
cannam@147
|
967 Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises) {
|
cannam@147
|
968 return Promise<Array<T>>(false, kj::heap<_::ArrayJoinPromiseNode<T>>(
|
cannam@147
|
969 KJ_MAP(p, promises) { return kj::mv(p.node); },
|
cannam@147
|
970 heapArray<_::ExceptionOr<T>>(promises.size())));
|
cannam@147
|
971 }
|
cannam@147
|
972
|
cannam@147
|
973 // =======================================================================================
|
cannam@147
|
974
|
cannam@147
|
975 namespace _ { // private
|
cannam@147
|
976
|
cannam@147
|
977 template <typename T>
|
cannam@147
|
978 class WeakFulfiller final: public PromiseFulfiller<T>, private kj::Disposer {
|
cannam@147
|
979 // A wrapper around PromiseFulfiller which can be detached.
|
cannam@147
|
980 //
|
cannam@147
|
981 // There are a couple non-trivialities here:
|
cannam@147
|
982 // - If the WeakFulfiller is discarded, we want the promise it fulfills to be implicitly
|
cannam@147
|
983 // rejected.
|
cannam@147
|
984 // - We cannot destroy the WeakFulfiller until the application has discarded it *and* it has been
|
cannam@147
|
985 // detached from the underlying fulfiller, because otherwise the later detach() call will go
|
cannam@147
|
986 // to a dangling pointer. Essentially, WeakFulfiller is reference counted, although the
|
cannam@147
|
987 // refcount never goes over 2 and we manually implement the refcounting because we need to do
|
cannam@147
|
988 // other special things when each side detaches anyway. To this end, WeakFulfiller is its own
|
cannam@147
|
989 // Disposer -- dispose() is called when the application discards its owned pointer to the
|
cannam@147
|
990 // fulfiller and detach() is called when the promise is destroyed.
|
cannam@147
|
991
|
cannam@147
|
992 public:
|
cannam@147
|
993 KJ_DISALLOW_COPY(WeakFulfiller);
|
cannam@147
|
994
|
cannam@147
|
995 static kj::Own<WeakFulfiller> make() {
|
cannam@147
|
996 WeakFulfiller* ptr = new WeakFulfiller;
|
cannam@147
|
997 return Own<WeakFulfiller>(ptr, *ptr);
|
cannam@147
|
998 }
|
cannam@147
|
999
|
cannam@147
|
1000 void fulfill(FixVoid<T>&& value) override {
|
cannam@147
|
1001 if (inner != nullptr) {
|
cannam@147
|
1002 inner->fulfill(kj::mv(value));
|
cannam@147
|
1003 }
|
cannam@147
|
1004 }
|
cannam@147
|
1005
|
cannam@147
|
1006 void reject(Exception&& exception) override {
|
cannam@147
|
1007 if (inner != nullptr) {
|
cannam@147
|
1008 inner->reject(kj::mv(exception));
|
cannam@147
|
1009 }
|
cannam@147
|
1010 }
|
cannam@147
|
1011
|
cannam@147
|
1012 bool isWaiting() override {
|
cannam@147
|
1013 return inner != nullptr && inner->isWaiting();
|
cannam@147
|
1014 }
|
cannam@147
|
1015
|
cannam@147
|
1016 void attach(PromiseFulfiller<T>& newInner) {
|
cannam@147
|
1017 inner = &newInner;
|
cannam@147
|
1018 }
|
cannam@147
|
1019
|
cannam@147
|
1020 void detach(PromiseFulfiller<T>& from) {
|
cannam@147
|
1021 if (inner == nullptr) {
|
cannam@147
|
1022 // Already disposed.
|
cannam@147
|
1023 delete this;
|
cannam@147
|
1024 } else {
|
cannam@147
|
1025 KJ_IREQUIRE(inner == &from);
|
cannam@147
|
1026 inner = nullptr;
|
cannam@147
|
1027 }
|
cannam@147
|
1028 }
|
cannam@147
|
1029
|
cannam@147
|
1030 private:
|
cannam@147
|
1031 mutable PromiseFulfiller<T>* inner;
|
cannam@147
|
1032
|
cannam@147
|
1033 WeakFulfiller(): inner(nullptr) {}
|
cannam@147
|
1034
|
cannam@147
|
1035 void disposeImpl(void* pointer) const override {
|
cannam@147
|
1036 // TODO(perf): Factor some of this out so it isn't regenerated for every fulfiller type?
|
cannam@147
|
1037
|
cannam@147
|
1038 if (inner == nullptr) {
|
cannam@147
|
1039 // Already detached.
|
cannam@147
|
1040 delete this;
|
cannam@147
|
1041 } else {
|
cannam@147
|
1042 if (inner->isWaiting()) {
|
cannam@147
|
1043 inner->reject(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__,
|
cannam@147
|
1044 kj::heapString("PromiseFulfiller was destroyed without fulfilling the promise.")));
|
cannam@147
|
1045 }
|
cannam@147
|
1046 inner = nullptr;
|
cannam@147
|
1047 }
|
cannam@147
|
1048 }
|
cannam@147
|
1049 };
|
cannam@147
|
1050
|
cannam@147
|
1051 template <typename T>
|
cannam@147
|
1052 class PromiseAndFulfillerAdapter {
|
cannam@147
|
1053 public:
|
cannam@147
|
1054 PromiseAndFulfillerAdapter(PromiseFulfiller<T>& fulfiller,
|
cannam@147
|
1055 WeakFulfiller<T>& wrapper)
|
cannam@147
|
1056 : fulfiller(fulfiller), wrapper(wrapper) {
|
cannam@147
|
1057 wrapper.attach(fulfiller);
|
cannam@147
|
1058 }
|
cannam@147
|
1059
|
cannam@147
|
1060 ~PromiseAndFulfillerAdapter() noexcept(false) {
|
cannam@147
|
1061 wrapper.detach(fulfiller);
|
cannam@147
|
1062 }
|
cannam@147
|
1063
|
cannam@147
|
1064 private:
|
cannam@147
|
1065 PromiseFulfiller<T>& fulfiller;
|
cannam@147
|
1066 WeakFulfiller<T>& wrapper;
|
cannam@147
|
1067 };
|
cannam@147
|
1068
|
cannam@147
|
1069 } // namespace _ (private)
|
cannam@147
|
1070
|
cannam@147
|
1071 template <typename T>
|
cannam@147
|
1072 template <typename Func>
|
cannam@147
|
1073 bool PromiseFulfiller<T>::rejectIfThrows(Func&& func) {
|
cannam@147
|
1074 KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) {
|
cannam@147
|
1075 reject(kj::mv(*exception));
|
cannam@147
|
1076 return false;
|
cannam@147
|
1077 } else {
|
cannam@147
|
1078 return true;
|
cannam@147
|
1079 }
|
cannam@147
|
1080 }
|
cannam@147
|
1081
|
cannam@147
|
1082 template <typename Func>
|
cannam@147
|
1083 bool PromiseFulfiller<void>::rejectIfThrows(Func&& func) {
|
cannam@147
|
1084 KJ_IF_MAYBE(exception, kj::runCatchingExceptions(kj::mv(func))) {
|
cannam@147
|
1085 reject(kj::mv(*exception));
|
cannam@147
|
1086 return false;
|
cannam@147
|
1087 } else {
|
cannam@147
|
1088 return true;
|
cannam@147
|
1089 }
|
cannam@147
|
1090 }
|
cannam@147
|
1091
|
cannam@147
|
1092 template <typename T, typename Adapter, typename... Params>
|
cannam@147
|
1093 Promise<T> newAdaptedPromise(Params&&... adapterConstructorParams) {
|
cannam@147
|
1094 return Promise<T>(false, heap<_::AdapterPromiseNode<_::FixVoid<T>, Adapter>>(
|
cannam@147
|
1095 kj::fwd<Params>(adapterConstructorParams)...));
|
cannam@147
|
1096 }
|
cannam@147
|
1097
|
cannam@147
|
1098 template <typename T>
|
cannam@147
|
1099 PromiseFulfillerPair<T> newPromiseAndFulfiller() {
|
cannam@147
|
1100 auto wrapper = _::WeakFulfiller<T>::make();
|
cannam@147
|
1101
|
cannam@147
|
1102 Own<_::PromiseNode> intermediate(
|
cannam@147
|
1103 heap<_::AdapterPromiseNode<_::FixVoid<T>, _::PromiseAndFulfillerAdapter<T>>>(*wrapper));
|
cannam@147
|
1104 Promise<_::JoinPromises<T>> promise(false,
|
cannam@147
|
1105 _::maybeChain(kj::mv(intermediate), implicitCast<T*>(nullptr)));
|
cannam@147
|
1106
|
cannam@147
|
1107 return PromiseFulfillerPair<T> { kj::mv(promise), kj::mv(wrapper) };
|
cannam@147
|
1108 }
|
cannam@147
|
1109
|
cannam@147
|
1110 } // namespace kj
|
cannam@147
|
1111
|
cannam@147
|
1112 #endif // KJ_ASYNC_INL_H_
|