annotate win64-msvc/include/kj/async-inl.h @ 47:d93140aac40b

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