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#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
28#pragma GCC system_header
29#endif
30
31#include "exception.h"
32#include "tuple.h"
33
34namespace kj {
35
36class EventLoop;
37template <typename T>
38class Promise;
39class WaitScope;
40class TaskSet;
41
42template <typename T>
43Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises);
44Promise<void> joinPromises(Array<Promise<void>>&& promises);
45
46namespace _ { // private
47
48template <typename T>
49Promise<T> chainPromiseType(T*);
50template <typename T>
51Promise<T> chainPromiseType(Promise<T>*);
52
53template <typename T>
54using ChainPromises = decltype(chainPromiseType((T*)nullptr));
55// Constructs a promise for T, reducing double-promises. That is, if T is Promise<U>, resolves to
56// Promise<U>, otherwise resolves to Promise<T>.
57
58template <typename T>
59Promise<T> reducePromiseType(T*, ...);
60template <typename T>
61Promise<T> reducePromiseType(Promise<T>*, ...);
62template <typename T, typename Reduced = decltype(T::reducePromise(kj::instance<Promise<T>>()))>
63Reduced reducePromiseType(T*, bool);
64
65template <typename T>
66using ReducePromises = decltype(reducePromiseType((T*)nullptr, false));
67// Like ChainPromises, but also takes into account whether T has a method `reducePromise` that
68// reduces Promise<T> to something else. In particular this allows Promise<capnp::RemotePromise<U>>
69// to reduce to capnp::RemotePromise<U>.
70
71class PropagateException {
72 // A functor which accepts a kj::Exception as a parameter and returns a broken promise of
73 // arbitrary type which simply propagates the exception.
74public:
75 class Bottom {
76 public:
77 Bottom(Exception&& exception): exception(kj::mv(exception)) {}
78
79 Exception asException() { return kj::mv(exception); }
80
81 private:
82 Exception exception;
83 };
84
85 Bottom operator()(Exception&& e) {
86 return Bottom(kj::mv(e));
87 }
88 Bottom operator()(const Exception& e) {
89 return Bottom(kj::cp(e));
90 }
91};
92
93template <typename Func, typename T>
94struct ReturnType_ { typedef decltype(instance<Func>()(instance<T>())) Type; };
95template <typename Func>
96struct ReturnType_<Func, void> { typedef decltype(instance<Func>()()) Type; };
97
98template <typename Func, typename T>
99using ReturnType = typename ReturnType_<Func, T>::Type;
100// The return type of functor Func given a parameter of type T, with the special exception that if
101// T is void, this is the return type of Func called with no arguments.
102
103template <typename T> struct SplitTuplePromise_ { typedef Promise<T> Type; };
104template <typename... T>
105struct SplitTuplePromise_<kj::_::Tuple<T...>> {
106 typedef kj::Tuple<ReducePromises<T>...> Type;
107};
108
109template <typename T>
110using SplitTuplePromise = typename SplitTuplePromise_<T>::Type;
111// T -> Promise<T>
112// Tuple<T> -> Tuple<Promise<T>>
113
114struct Void {};
115// Application code should NOT refer to this! See `kj::READY_NOW` instead.
116
117template <typename T> struct FixVoid_ { typedef T Type; };
118template <> struct FixVoid_<void> { typedef Void Type; };
119template <typename T> using FixVoid = typename FixVoid_<T>::Type;
120// FixVoid<T> is just T unless T is void in which case it is _::Void (an empty struct).
121
122template <typename T> struct UnfixVoid_ { typedef T Type; };
123template <> struct UnfixVoid_<Void> { typedef void Type; };
124template <typename T> using UnfixVoid = typename UnfixVoid_<T>::Type;
125// UnfixVoid is the opposite of FixVoid.
126
127template <typename In, typename Out>
128struct MaybeVoidCaller {
129 // Calls the function converting a Void input to an empty parameter list and a void return
130 // value to a Void output.
131
132 template <typename Func>
133 static inline Out apply(Func& func, In&& in) {
134 return func(kj::mv(in));
135 }
136};
137template <typename In, typename Out>
138struct MaybeVoidCaller<In&, Out> {
139 template <typename Func>
140 static inline Out apply(Func& func, In& in) {
141 return func(in);
142 }
143};
144template <typename Out>
145struct MaybeVoidCaller<Void, Out> {
146 template <typename Func>
147 static inline Out apply(Func& func, Void&& in) {
148 return func();
149 }
150};
151template <typename In>
152struct MaybeVoidCaller<In, Void> {
153 template <typename Func>
154 static inline Void apply(Func& func, In&& in) {
155 func(kj::mv(in));
156 return Void();
157 }
158};
159template <typename In>
160struct MaybeVoidCaller<In&, Void> {
161 template <typename Func>
162 static inline Void apply(Func& func, In& in) {
163 func(in);
164 return Void();
165 }
166};
167template <>
168struct MaybeVoidCaller<Void, Void> {
169 template <typename Func>
170 static inline Void apply(Func& func, Void&& in) {
171 func();
172 return Void();
173 }
174};
175
176template <typename T>
177inline T&& returnMaybeVoid(T&& t) {
178 return kj::fwd<T>(t);
179}
180inline void returnMaybeVoid(Void&& v) {}
181
182class ExceptionOrValue;
183class PromiseNode;
184class ChainPromiseNode;
185template <typename T>
186class ForkHub;
187
188class Event;
189
190class PromiseBase {
191public:
192 kj::String trace();
193 // Dump debug info about this promise.
194
195private:
196 Own<PromiseNode> node;
197
198 PromiseBase() = default;
199 PromiseBase(Own<PromiseNode>&& node): node(kj::mv(node)) {}
200
201 friend class kj::EventLoop;
202 friend class ChainPromiseNode;
203 template <typename>
204 friend class kj::Promise;
205 friend class kj::TaskSet;
206 template <typename U>
207 friend Promise<Array<U>> kj::joinPromises(Array<Promise<U>>&& promises);
208 friend Promise<void> kj::joinPromises(Array<Promise<void>>&& promises);
209};
210
211void detach(kj::Promise<void>&& promise);
212void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope);
213bool pollImpl(_::PromiseNode& node, WaitScope& waitScope);
214Promise<void> yield();
215Own<PromiseNode> neverDone();
216
217class NeverDone {
218public:
219 template <typename T>
220 operator Promise<T>() const {
221 return Promise<T>(false, neverDone());
222 }
223
224 KJ_NORETURN(void wait(WaitScope& waitScope) const);
225};
226
227} // namespace _ (private)
228} // namespace kj
229