jpayne@69: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors jpayne@69: // Licensed under the MIT License: jpayne@69: // jpayne@69: // Permission is hereby granted, free of charge, to any person obtaining a copy jpayne@69: // of this software and associated documentation files (the "Software"), to deal jpayne@69: // in the Software without restriction, including without limitation the rights jpayne@69: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell jpayne@69: // copies of the Software, and to permit persons to whom the Software is jpayne@69: // furnished to do so, subject to the following conditions: jpayne@69: // jpayne@69: // The above copyright notice and this permission notice shall be included in jpayne@69: // all copies or substantial portions of the Software. jpayne@69: // jpayne@69: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR jpayne@69: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, jpayne@69: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE jpayne@69: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER jpayne@69: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, jpayne@69: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN jpayne@69: // THE SOFTWARE. jpayne@69: jpayne@69: // This file contains a bunch of internal declarations that must appear before async.h can start. jpayne@69: // We don't define these directly in async.h because it makes the file hard to read. jpayne@69: jpayne@69: #pragma once jpayne@69: jpayne@69: #include jpayne@69: #include jpayne@69: #include jpayne@69: jpayne@69: // Detect whether or not we should enable kj::Promise coroutine integration. jpayne@69: // jpayne@69: // TODO(someday): Support coroutines with -fno-exceptions. jpayne@69: #if !KJ_NO_EXCEPTIONS jpayne@69: #ifdef __has_include jpayne@69: #if (__cpp_impl_coroutine >= 201902L) && __has_include() jpayne@69: // C++20 Coroutines detected. jpayne@69: #include jpayne@69: #define KJ_HAS_COROUTINE 1 jpayne@69: #define KJ_COROUTINE_STD_NAMESPACE std jpayne@69: #elif (__cpp_coroutines >= 201703L) && __has_include() jpayne@69: // Coroutines TS detected. jpayne@69: #include jpayne@69: #define KJ_HAS_COROUTINE 1 jpayne@69: #define KJ_COROUTINE_STD_NAMESPACE std::experimental jpayne@69: #endif jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: KJ_BEGIN_HEADER jpayne@69: jpayne@69: namespace kj { jpayne@69: jpayne@69: class EventLoop; jpayne@69: template jpayne@69: class Promise; jpayne@69: class WaitScope; jpayne@69: class TaskSet; jpayne@69: jpayne@69: Promise joinPromises(Array>&& promises, SourceLocation location = {}); jpayne@69: Promise joinPromisesFailFast(Array>&& promises, SourceLocation location = {}); jpayne@69: // Out-of-line specialization of template function defined in async.h. jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: Promise chainPromiseType(T*); jpayne@69: template jpayne@69: Promise chainPromiseType(Promise*); jpayne@69: jpayne@69: template jpayne@69: using ChainPromises = decltype(chainPromiseType((T*)nullptr)); jpayne@69: // Constructs a promise for T, reducing double-promises. That is, if T is Promise, resolves to jpayne@69: // Promise, otherwise resolves to Promise. jpayne@69: jpayne@69: template jpayne@69: Promise reducePromiseType(T*, ...); jpayne@69: template jpayne@69: Promise reducePromiseType(Promise*, ...); jpayne@69: template >()))> jpayne@69: Reduced reducePromiseType(T*, bool); jpayne@69: jpayne@69: template jpayne@69: using ReducePromises = decltype(reducePromiseType((T*)nullptr, false)); jpayne@69: // Like ChainPromises, but also takes into account whether T has a method `reducePromise` that jpayne@69: // reduces Promise to something else. In particular this allows Promise> jpayne@69: // to reduce to capnp::RemotePromise. jpayne@69: jpayne@69: template struct UnwrapPromise_; jpayne@69: template struct UnwrapPromise_> { typedef T Type; }; jpayne@69: jpayne@69: template jpayne@69: using UnwrapPromise = typename UnwrapPromise_::Type; jpayne@69: jpayne@69: class PropagateException { jpayne@69: // A functor which accepts a kj::Exception as a parameter and returns a broken promise of jpayne@69: // arbitrary type which simply propagates the exception. jpayne@69: public: jpayne@69: class Bottom { jpayne@69: public: jpayne@69: Bottom(Exception&& exception): exception(kj::mv(exception)) {} jpayne@69: jpayne@69: Exception asException() { return kj::mv(exception); } jpayne@69: jpayne@69: private: jpayne@69: Exception exception; jpayne@69: }; jpayne@69: jpayne@69: Bottom operator()(Exception&& e) { jpayne@69: return Bottom(kj::mv(e)); jpayne@69: } jpayne@69: Bottom operator()(const Exception& e) { jpayne@69: return Bottom(kj::cp(e)); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: struct ReturnType_ { typedef decltype(instance()(instance())) Type; }; jpayne@69: template jpayne@69: struct ReturnType_ { typedef decltype(instance()()) Type; }; jpayne@69: jpayne@69: template jpayne@69: using ReturnType = typename ReturnType_::Type; jpayne@69: // The return type of functor Func given a parameter of type T, with the special exception that if jpayne@69: // T is void, this is the return type of Func called with no arguments. jpayne@69: jpayne@69: template struct SplitTuplePromise_ { typedef Promise Type; }; jpayne@69: template jpayne@69: struct SplitTuplePromise_> { jpayne@69: typedef kj::Tuple...> Type; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: using SplitTuplePromise = typename SplitTuplePromise_::Type; jpayne@69: // T -> Promise jpayne@69: // Tuple -> Tuple> jpayne@69: jpayne@69: struct Void {}; jpayne@69: // Application code should NOT refer to this! See `kj::READY_NOW` instead. jpayne@69: jpayne@69: template struct FixVoid_ { typedef T Type; }; jpayne@69: template <> struct FixVoid_ { typedef Void Type; }; jpayne@69: template using FixVoid = typename FixVoid_::Type; jpayne@69: // FixVoid is just T unless T is void in which case it is _::Void (an empty struct). jpayne@69: jpayne@69: template struct UnfixVoid_ { typedef T Type; }; jpayne@69: template <> struct UnfixVoid_ { typedef void Type; }; jpayne@69: template using UnfixVoid = typename UnfixVoid_::Type; jpayne@69: // UnfixVoid is the opposite of FixVoid. jpayne@69: jpayne@69: template jpayne@69: struct MaybeVoidCaller { jpayne@69: // Calls the function converting a Void input to an empty parameter list and a void return jpayne@69: // value to a Void output. jpayne@69: jpayne@69: template jpayne@69: static inline Out apply(Func& func, In&& in) { jpayne@69: return func(kj::mv(in)); jpayne@69: } jpayne@69: }; jpayne@69: template jpayne@69: struct MaybeVoidCaller { jpayne@69: template jpayne@69: static inline Out apply(Func& func, In& in) { jpayne@69: return func(in); jpayne@69: } jpayne@69: }; jpayne@69: template jpayne@69: struct MaybeVoidCaller { jpayne@69: template jpayne@69: static inline Out apply(Func& func, Void&& in) { jpayne@69: return func(); jpayne@69: } jpayne@69: }; jpayne@69: template jpayne@69: struct MaybeVoidCaller { jpayne@69: template jpayne@69: static inline Void apply(Func& func, In&& in) { jpayne@69: func(kj::mv(in)); jpayne@69: return Void(); jpayne@69: } jpayne@69: }; jpayne@69: template jpayne@69: struct MaybeVoidCaller { jpayne@69: template jpayne@69: static inline Void apply(Func& func, In& in) { jpayne@69: func(in); jpayne@69: return Void(); jpayne@69: } jpayne@69: }; jpayne@69: template <> jpayne@69: struct MaybeVoidCaller { jpayne@69: template jpayne@69: static inline Void apply(Func& func, Void&& in) { jpayne@69: func(); jpayne@69: return Void(); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: inline T&& returnMaybeVoid(T&& t) { jpayne@69: return kj::fwd(t); jpayne@69: } jpayne@69: inline void returnMaybeVoid(Void&& v) {} jpayne@69: jpayne@69: class ExceptionOrValue; jpayne@69: class PromiseNode; jpayne@69: class ChainPromiseNode; jpayne@69: template jpayne@69: class ForkHub; jpayne@69: class FiberStack; jpayne@69: class FiberBase; jpayne@69: jpayne@69: class Event; jpayne@69: class XThreadEvent; jpayne@69: class XThreadPaf; jpayne@69: jpayne@69: class PromiseDisposer; jpayne@69: using OwnPromiseNode = Own; jpayne@69: // PromiseNode uses a static disposer. jpayne@69: jpayne@69: class PromiseBase { jpayne@69: public: jpayne@69: kj::String trace(); jpayne@69: // Dump debug info about this promise. jpayne@69: jpayne@69: private: jpayne@69: OwnPromiseNode node; jpayne@69: jpayne@69: PromiseBase() = default; jpayne@69: PromiseBase(OwnPromiseNode&& node): node(kj::mv(node)) {} jpayne@69: jpayne@69: template jpayne@69: friend class kj::Promise; jpayne@69: friend class PromiseNode; jpayne@69: }; jpayne@69: jpayne@69: void detach(kj::Promise&& promise); jpayne@69: void waitImpl(_::OwnPromiseNode&& node, _::ExceptionOrValue& result, WaitScope& waitScope, jpayne@69: SourceLocation location); jpayne@69: bool pollImpl(_::PromiseNode& node, WaitScope& waitScope, SourceLocation location); jpayne@69: Promise yield(); jpayne@69: Promise yieldHarder(); jpayne@69: OwnPromiseNode readyNow(); jpayne@69: OwnPromiseNode neverDone(); jpayne@69: jpayne@69: class ReadyNow { jpayne@69: public: jpayne@69: operator Promise() const; jpayne@69: }; jpayne@69: jpayne@69: class NeverDone { jpayne@69: public: jpayne@69: template jpayne@69: operator Promise() const; jpayne@69: jpayne@69: KJ_NORETURN(void wait(WaitScope& waitScope, SourceLocation location = {}) const); jpayne@69: }; jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: } // namespace kj jpayne@69: jpayne@69: KJ_END_HEADER