annotate win64-msvc/include/kj/async-inl.h @ 136:ce0478b62770

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