annotate win64-msvc/include/kj/async-inl.h @ 64:eccd51b72864

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