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