async-prelude.h (7744B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 // This file contains a bunch of internal declarations that must appear before async.h can start. 23 // We don't define these directly in async.h because it makes the file hard to read. 24 25 #pragma once 26 27 #include "exception.h" 28 #include "tuple.h" 29 30 // Detect whether or not we should enable kj::Promise<T> coroutine integration. 31 // 32 // TODO(someday): Support coroutines with -fno-exceptions. 33 #if !KJ_NO_EXCEPTIONS 34 #ifdef __has_include 35 // For now, we only support the Coroutines TS. 36 // 37 // TODO(someday): Also support standardized C++20 Coroutines. The latest VS2019 and GCC 10 both have 38 // support, though MSVC hides it behind /std:c++latest, which brings an ICE with it. 39 #if __cpp_coroutines && __has_include(<experimental/coroutine>) 40 // Coroutines TS detected. 41 #include <experimental/coroutine> 42 #define KJ_HAS_COROUTINE 1 43 #define KJ_COROUTINE_STD_NAMESPACE std::experimental 44 #endif 45 #endif 46 #endif 47 48 KJ_BEGIN_HEADER 49 50 namespace kj { 51 52 class EventLoop; 53 template <typename T> 54 class Promise; 55 class WaitScope; 56 class TaskSet; 57 58 template <typename T> 59 Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises); 60 Promise<void> joinPromises(Array<Promise<void>>&& promises); 61 62 namespace _ { // private 63 64 template <typename T> 65 Promise<T> chainPromiseType(T*); 66 template <typename T> 67 Promise<T> chainPromiseType(Promise<T>*); 68 69 template <typename T> 70 using ChainPromises = decltype(chainPromiseType((T*)nullptr)); 71 // Constructs a promise for T, reducing double-promises. That is, if T is Promise<U>, resolves to 72 // Promise<U>, otherwise resolves to Promise<T>. 73 74 template <typename T> 75 Promise<T> reducePromiseType(T*, ...); 76 template <typename T> 77 Promise<T> reducePromiseType(Promise<T>*, ...); 78 template <typename T, typename Reduced = decltype(T::reducePromise(kj::instance<Promise<T>>()))> 79 Reduced reducePromiseType(T*, bool); 80 81 template <typename T> 82 using ReducePromises = decltype(reducePromiseType((T*)nullptr, false)); 83 // Like ChainPromises, but also takes into account whether T has a method `reducePromise` that 84 // reduces Promise<T> to something else. In particular this allows Promise<capnp::RemotePromise<U>> 85 // to reduce to capnp::RemotePromise<U>. 86 87 template <typename T> struct UnwrapPromise_; 88 template <typename T> struct UnwrapPromise_<Promise<T>> { typedef T Type; }; 89 90 template <typename T> 91 using UnwrapPromise = typename UnwrapPromise_<T>::Type; 92 93 class PropagateException { 94 // A functor which accepts a kj::Exception as a parameter and returns a broken promise of 95 // arbitrary type which simply propagates the exception. 96 public: 97 class Bottom { 98 public: 99 Bottom(Exception&& exception): exception(kj::mv(exception)) {} 100 101 Exception asException() { return kj::mv(exception); } 102 103 private: 104 Exception exception; 105 }; 106 107 Bottom operator()(Exception&& e) { 108 return Bottom(kj::mv(e)); 109 } 110 Bottom operator()(const Exception& e) { 111 return Bottom(kj::cp(e)); 112 } 113 }; 114 115 template <typename Func, typename T> 116 struct ReturnType_ { typedef decltype(instance<Func>()(instance<T>())) Type; }; 117 template <typename Func> 118 struct ReturnType_<Func, void> { typedef decltype(instance<Func>()()) Type; }; 119 120 template <typename Func, typename T> 121 using ReturnType = typename ReturnType_<Func, T>::Type; 122 // The return type of functor Func given a parameter of type T, with the special exception that if 123 // T is void, this is the return type of Func called with no arguments. 124 125 template <typename T> struct SplitTuplePromise_ { typedef Promise<T> Type; }; 126 template <typename... T> 127 struct SplitTuplePromise_<kj::_::Tuple<T...>> { 128 typedef kj::Tuple<ReducePromises<T>...> Type; 129 }; 130 131 template <typename T> 132 using SplitTuplePromise = typename SplitTuplePromise_<T>::Type; 133 // T -> Promise<T> 134 // Tuple<T> -> Tuple<Promise<T>> 135 136 struct Void {}; 137 // Application code should NOT refer to this! See `kj::READY_NOW` instead. 138 139 template <typename T> struct FixVoid_ { typedef T Type; }; 140 template <> struct FixVoid_<void> { typedef Void Type; }; 141 template <typename T> using FixVoid = typename FixVoid_<T>::Type; 142 // FixVoid<T> is just T unless T is void in which case it is _::Void (an empty struct). 143 144 template <typename T> struct UnfixVoid_ { typedef T Type; }; 145 template <> struct UnfixVoid_<Void> { typedef void Type; }; 146 template <typename T> using UnfixVoid = typename UnfixVoid_<T>::Type; 147 // UnfixVoid is the opposite of FixVoid. 148 149 template <typename In, typename Out> 150 struct MaybeVoidCaller { 151 // Calls the function converting a Void input to an empty parameter list and a void return 152 // value to a Void output. 153 154 template <typename Func> 155 static inline Out apply(Func& func, In&& in) { 156 return func(kj::mv(in)); 157 } 158 }; 159 template <typename In, typename Out> 160 struct MaybeVoidCaller<In&, Out> { 161 template <typename Func> 162 static inline Out apply(Func& func, In& in) { 163 return func(in); 164 } 165 }; 166 template <typename Out> 167 struct MaybeVoidCaller<Void, Out> { 168 template <typename Func> 169 static inline Out apply(Func& func, Void&& in) { 170 return func(); 171 } 172 }; 173 template <typename In> 174 struct MaybeVoidCaller<In, Void> { 175 template <typename Func> 176 static inline Void apply(Func& func, In&& in) { 177 func(kj::mv(in)); 178 return Void(); 179 } 180 }; 181 template <typename In> 182 struct MaybeVoidCaller<In&, Void> { 183 template <typename Func> 184 static inline Void apply(Func& func, In& in) { 185 func(in); 186 return Void(); 187 } 188 }; 189 template <> 190 struct MaybeVoidCaller<Void, Void> { 191 template <typename Func> 192 static inline Void apply(Func& func, Void&& in) { 193 func(); 194 return Void(); 195 } 196 }; 197 198 template <typename T> 199 inline T&& returnMaybeVoid(T&& t) { 200 return kj::fwd<T>(t); 201 } 202 inline void returnMaybeVoid(Void&& v) {} 203 204 class ExceptionOrValue; 205 class PromiseNode; 206 class ChainPromiseNode; 207 template <typename T> 208 class ForkHub; 209 class FiberStack; 210 class FiberBase; 211 212 class Event; 213 class XThreadEvent; 214 class XThreadPaf; 215 216 class PromiseBase { 217 public: 218 kj::String trace(); 219 // Dump debug info about this promise. 220 221 private: 222 Own<PromiseNode> node; 223 224 PromiseBase() = default; 225 PromiseBase(Own<PromiseNode>&& node): node(kj::mv(node)) {} 226 227 template <typename> 228 friend class kj::Promise; 229 friend class PromiseNode; 230 }; 231 232 void detach(kj::Promise<void>&& promise); 233 void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope); 234 bool pollImpl(_::PromiseNode& node, WaitScope& waitScope); 235 Promise<void> yield(); 236 Promise<void> yieldHarder(); 237 Own<PromiseNode> neverDone(); 238 239 class NeverDone { 240 public: 241 template <typename T> 242 operator Promise<T>() const; 243 244 KJ_NORETURN(void wait(WaitScope& waitScope) const); 245 }; 246 247 } // namespace _ (private) 248 } // namespace kj 249 250 KJ_END_HEADER