annotate win64-msvc/include/kj/async-inl.h @ 148:b4bfdf10c4b3

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