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

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