annotate win32-mingw/include/kj/async-inl.h @ 83:ae30d91d2ffe

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