1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_SRC_CORE_LIB_PROMISE_DETAIL_PROMISE_FACTORY_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_PROMISE_FACTORY_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <memory>
21 #include <type_traits>
22 #include <utility>
23 
24 #include "absl/meta/type_traits.h"
25 
26 #include "src/core/lib/promise/detail/promise_like.h"
27 
28 // PromiseFactory is an adaptor class.
29 //
30 // Where a Promise is a thing that's polled periodically, a PromiseFactory
31 // creates a Promise. Within this Promise/Activity framework, PromiseFactory's
32 // then provide the edges for computation -- invoked at state transition
33 // boundaries to provide the new steady state.
34 //
35 // A PromiseFactory formally is f(A) -> Promise<T> for some types A & T.
36 // This get a bit awkward and inapproprate to write however, and so the type
37 // contained herein can adapt various kinds of callable into the correct form.
38 // Of course a callable of a single argument returning a Promise will see an
39 // identity translation. One taking no arguments and returning a Promise
40 // similarly.
41 //
42 // A Promise passed to a PromiseFactory will yield a PromiseFactory that
43 // returns just that Promise.
44 //
45 // Generalizing slightly, a callable taking a single argument A and returning a
46 // Poll<T> will yield a PromiseFactory that captures it's argument A and
47 // returns a Poll<T>.
48 //
49 // Since various consumers of PromiseFactory run either repeatedly through an
50 // overarching Promises lifetime, or just once, and we can optimize just once
51 // by moving the contents of the PromiseFactory, two factory methods are
52 // provided: Once, that can be called just once, and Repeated, that can (wait
53 // for it) be called Repeatedly.
54 
55 namespace grpc_core {
56 namespace promise_detail {
57 
58 // Helper trait: given a T, and T x, is calling x() legal?
59 template <typename T, typename Ignored = void>
60 struct IsVoidCallable {
61   static constexpr bool value = false;
62 };
63 template <typename F>
64 struct IsVoidCallable<F, absl::void_t<decltype(std::declval<F>()())>> {
65   static constexpr bool value = true;
66 };
67 
68 // Given F(A,B,C,...), what's the return type?
69 template <typename T, typename Ignored = void>
70 struct ResultOfT;
71 
72 template <typename F, typename... Args>
73 struct ResultOfT<F(Args...),
74                  absl::void_t<decltype(std::declval<RemoveCVRef<F>>()(
75                      std::declval<Args>()...))>> {
76   using T = decltype(std::declval<RemoveCVRef<F>>()(std::declval<Args>()...));
77 };
78 
79 template <typename F, typename... Args>
80 struct ResultOfT<F(Args...)&,
81                  absl::void_t<decltype(std::declval<RemoveCVRef<F>>()(
82                      std::declval<Args>()...))>> {
83   using T = decltype(std::declval<RemoveCVRef<F>>()(std::declval<Args>()...));
84 };
85 
86 template <typename F, typename... Args>
87 struct ResultOfT<const F(Args...)&,
88                  absl::void_t<decltype(std::declval<RemoveCVRef<F>>()(
89                      std::declval<Args>()...))>> {
90   using T = decltype(std::declval<RemoveCVRef<F>>()(std::declval<Args>()...));
91 };
92 
93 template <typename T>
94 using ResultOf = typename ResultOfT<T>::T;
95 
96 // Captures the promise functor and the argument passed.
97 // Provides the interface of a promise.
98 template <typename F, typename Arg>
99 class Curried {
100  public:
101   Curried(F&& f, Arg&& arg)
102       : f_(std::forward<F>(f)), arg_(std::forward<Arg>(arg)) {}
103   Curried(const F& f, Arg&& arg) : f_(f), arg_(std::forward<Arg>(arg)) {}
104   using Result = decltype(std::declval<F>()(std::declval<Arg>()));
105   Result operator()() { return f_(std::move(arg_)); }
106 
107  private:
108   GPR_NO_UNIQUE_ADDRESS F f_;
109   GPR_NO_UNIQUE_ADDRESS Arg arg_;
110 #ifndef NDEBUG
111   std::unique_ptr<int> asan_canary_ = std::make_unique<int>(0);
112 #endif
113 };
114 
115 // Promote a callable(A) -> T | Poll<T> to a PromiseFactory(A) -> Promise<T> by
116 // capturing A.
117 template <typename A, typename F>
118 absl::enable_if_t<!IsVoidCallable<ResultOf<F(A)>>::value,
119                   PromiseLike<Curried<RemoveCVRef<F>, A>>>
120 PromiseFactoryImpl(F&& f, A&& arg) {
121   return Curried<RemoveCVRef<F>, A>(std::forward<F>(f), std::forward<A>(arg));
122 }
123 
124 // Promote a callable() -> T|Poll<T> to a PromiseFactory(A) -> Promise<T>
125 // by dropping the argument passed to the factory.
126 template <typename A, typename F>
127 absl::enable_if_t<!IsVoidCallable<ResultOf<F()>>::value,
128                   PromiseLike<RemoveCVRef<F>>>
129 PromiseFactoryImpl(F f, A&&) {
130   return PromiseLike<F>(std::move(f));
131 }
132 
133 // Promote a callable() -> T|Poll<T> to a PromiseFactory() -> Promise<T>
134 template <typename F>
135 absl::enable_if_t<!IsVoidCallable<ResultOf<F()>>::value,
136                   PromiseLike<RemoveCVRef<F>>>
137 PromiseFactoryImpl(F f) {
138   return PromiseLike<F>(std::move(f));
139 }
140 
141 // Given a callable(A) -> Promise<T>, name it a PromiseFactory and use it.
142 template <typename A, typename F>
143 absl::enable_if_t<IsVoidCallable<ResultOf<F(A)>>::value,
144                   PromiseLike<decltype(std::declval<F>()(std::declval<A>()))>>
145 PromiseFactoryImpl(F&& f, A&& arg) {
146   return f(std::forward<A>(arg));
147 }
148 
149 // Given a callable(A) -> Promise<T>, name it a PromiseFactory and use it.
150 template <typename A, typename F>
151 absl::enable_if_t<IsVoidCallable<ResultOf<F(A)>>::value,
152                   PromiseLike<decltype(std::declval<F>()(std::declval<A>()))>>
153 PromiseFactoryImpl(F& f, A&& arg) {
154   return f(std::forward<A>(arg));
155 }
156 
157 // Given a callable() -> Promise<T>, promote it to a
158 // PromiseFactory(A) -> Promise<T> by dropping the first argument.
159 template <typename A, typename F>
160 absl::enable_if_t<IsVoidCallable<ResultOf<F()>>::value,
161                   PromiseLike<decltype(std::declval<F>()())>>
162 PromiseFactoryImpl(F&& f, A&&) {
163   return f();
164 }
165 
166 // Given a callable() -> Promise<T>, name it a PromiseFactory and use it.
167 template <typename F>
168 absl::enable_if_t<IsVoidCallable<ResultOf<F()>>::value,
169                   PromiseLike<decltype(std::declval<F>()())>>
170 PromiseFactoryImpl(F&& f) {
171   return f();
172 }
173 
174 template <typename A, typename F>
175 class OncePromiseFactory {
176  private:
177   GPR_NO_UNIQUE_ADDRESS F f_;
178 
179  public:
180   using Arg = A;
181   using Promise =
182       decltype(PromiseFactoryImpl(std::move(f_), std::declval<A>()));
183 
184   explicit OncePromiseFactory(F f) : f_(std::move(f)) {}
185 
186   Promise Make(Arg&& a) {
187     return PromiseFactoryImpl(std::move(f_), std::forward<Arg>(a));
188   }
189 };
190 
191 template <typename F>
192 class OncePromiseFactory<void, F> {
193  private:
194   GPR_NO_UNIQUE_ADDRESS F f_;
195 
196  public:
197   using Arg = void;
198   using Promise = decltype(PromiseFactoryImpl(std::move(f_)));
199 
200   explicit OncePromiseFactory(F f) : f_(std::move(f)) {}
201 
202   Promise Make() { return PromiseFactoryImpl(std::move(f_)); }
203 };
204 
205 template <typename A, typename F>
206 class RepeatedPromiseFactory {
207  private:
208   GPR_NO_UNIQUE_ADDRESS F f_;
209 
210  public:
211   using Arg = A;
212   using Promise = decltype(PromiseFactoryImpl(f_, std::declval<A>()));
213 
214   explicit RepeatedPromiseFactory(F f) : f_(std::move(f)) {}
215 
216   Promise Make(Arg&& a) const {
217     return PromiseFactoryImpl(f_, std::forward<Arg>(a));
218   }
219   Promise Make(Arg&& a) { return PromiseFactoryImpl(f_, std::forward<Arg>(a)); }
220 };
221 
222 template <typename F>
223 class RepeatedPromiseFactory<void, F> {
224  private:
225   GPR_NO_UNIQUE_ADDRESS F f_;
226 
227  public:
228   using Arg = void;
229   using Promise = decltype(PromiseFactoryImpl(f_));
230 
231   explicit RepeatedPromiseFactory(F f) : f_(std::move(f)) {}
232 
233   Promise Make() const { return PromiseFactoryImpl(f_); }
234   Promise Make() { return PromiseFactoryImpl(f_); }
235 };
236 
237 }  // namespace promise_detail
238 }  // namespace grpc_core
239 
240 #endif  // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_PROMISE_FACTORY_H
241