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