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_CORE_LIB_PROMISE_DETAIL_PROMISE_FACTORY_H 16 #define GRPC_CORE_LIB_PROMISE_DETAIL_PROMISE_FACTORY_H 17 18 #include <grpc/support/port_platform.h> 19 20 #include "absl/meta/type_traits.h" 21 22 #include "src/core/lib/promise/detail/promise_like.h" 23 #include "src/core/lib/promise/poll.h" 24 25 // PromiseFactory is an adaptor class. 26 // 27 // Where a Promise is a thing that's polled periodically, a PromiseFactory 28 // creates a Promise. Within this Promise/Activity framework, PromiseFactory's 29 // then provide the edges for computation -- invoked at state transition 30 // boundaries to provide the new steady state. 31 // 32 // A PromiseFactory formally is f(A) -> Promise<T> for some types A & T. 33 // This get a bit awkward and inapproprate to write however, and so the type 34 // contained herein can adapt various kinds of callable into the correct form. 35 // Of course a callable of a single argument returning a Promise will see an 36 // identity translation. One taking no arguments and returning a Promise 37 // similarly. 38 // 39 // A Promise passed to a PromiseFactory will yield a PromiseFactory that 40 // returns just that Promise. 41 // 42 // Generalizing slightly, a callable taking a single argument A and returning a 43 // Poll<T> will yield a PromiseFactory that captures it's argument A and 44 // returns a Poll<T>. 45 // 46 // Since various consumers of PromiseFactory run either repeatedly through an 47 // overarching Promises lifetime, or just once, and we can optimize just once 48 // by moving the contents of the PromiseFactory, two factory methods are 49 // provided: Once, that can be called just once, and Repeated, that can (wait 50 // for it) be called Repeatedly. 51 52 namespace grpc_core { 53 namespace promise_detail { 54 55 // Helper trait: given a T, and T x, is calling x() legal? 56 template <typename T, typename Ignored = void> 57 struct IsVoidCallable { 58 static constexpr bool value = false; 59 }; 60 template <typename F> 61 struct IsVoidCallable<F, absl::void_t<decltype(std::declval<F>()())>> { 62 static constexpr bool value = true; 63 }; 64 65 // Given F(A,B,C,...), what's the return type? 66 template <typename T, typename Ignored = void> 67 struct ResultOfT; 68 template <typename F, typename... Args> 69 struct ResultOfT<F(Args...), 70 absl::void_t<decltype(std::declval<RemoveCVRef<F>>()( 71 std::declval<Args>()...))>> { 72 using T = decltype(std::declval<RemoveCVRef<F>>()(std::declval<Args>()...)); 73 }; 74 75 template <typename T> 76 using ResultOf = typename ResultOfT<T>::T; 77 78 // Captures the promise functor and the argument passed. 79 // Provides the interface of a promise. 80 template <typename F, typename Arg> 81 class Curried { 82 public: 83 Curried(F&& f, Arg&& arg) 84 : f_(std::forward<F>(f)), arg_(std::forward<Arg>(arg)) {} 85 Curried(const F& f, Arg&& arg) : f_(f), arg_(std::forward<Arg>(arg)) {} 86 using Result = decltype(std::declval<F>()(std::declval<Arg>())); 87 Result operator()() { return f_(arg_); } 88 89 private: 90 GPR_NO_UNIQUE_ADDRESS F f_; 91 GPR_NO_UNIQUE_ADDRESS Arg arg_; 92 }; 93 94 // Promote a callable(A) -> T | Poll<T> to a PromiseFactory(A) -> Promise<T> by 95 // capturing A. 96 template <typename A, typename F> 97 absl::enable_if_t<!IsVoidCallable<ResultOf<F(A)>>::value, 98 PromiseLike<Curried<RemoveCVRef<F>, A>>> 99 PromiseFactoryImpl(F&& f, A&& arg) { 100 return Curried<RemoveCVRef<F>, A>(std::forward<F>(f), std::forward<A>(arg)); 101 } 102 103 // Promote a callable() -> T|Poll<T> to a PromiseFactory(A) -> Promise<T> 104 // by dropping the argument passed to the factory. 105 template <typename A, typename F> 106 absl::enable_if_t<!IsVoidCallable<ResultOf<F()>>::value, 107 PromiseLike<RemoveCVRef<F>>> 108 PromiseFactoryImpl(F f, A&&) { 109 return PromiseLike<F>(std::move(f)); 110 } 111 112 // Promote a callable() -> T|Poll<T> to a PromiseFactory() -> Promise<T> 113 template <typename F> 114 absl::enable_if_t<!IsVoidCallable<ResultOf<F()>>::value, 115 PromiseLike<RemoveCVRef<F>>> 116 PromiseFactoryImpl(F f) { 117 return PromiseLike<F>(std::move(f)); 118 } 119 120 // Given a callable(A) -> Promise<T>, name it a PromiseFactory and use it. 121 template <typename A, typename F> 122 absl::enable_if_t<IsVoidCallable<ResultOf<F(A)>>::value, 123 PromiseLike<decltype(std::declval<F>()(std::declval<A>()))>> 124 PromiseFactoryImpl(F&& f, A&& arg) { 125 return f(std::forward<A>(arg)); 126 } 127 128 // Given a callable() -> Promise<T>, promote it to a 129 // PromiseFactory(A) -> Promise<T> by dropping the first argument. 130 template <typename A, typename F> 131 absl::enable_if_t<IsVoidCallable<ResultOf<F()>>::value, 132 PromiseLike<decltype(std::declval<F>()())>> 133 PromiseFactoryImpl(F&& f, A&&) { 134 return f(); 135 } 136 137 // Given a callable() -> Promise<T>, name it a PromiseFactory and use it. 138 template <typename F> 139 absl::enable_if_t<IsVoidCallable<ResultOf<F()>>::value, 140 PromiseLike<decltype(std::declval<F>()())>> 141 PromiseFactoryImpl(F&& f) { 142 return f(); 143 }; 144 145 template <typename A, typename F> 146 class PromiseFactory { 147 private: 148 GPR_NO_UNIQUE_ADDRESS F f_; 149 150 public: 151 using Arg = A; 152 using Promise = 153 decltype(PromiseFactoryImpl(std::move(f_), std::declval<A>())); 154 155 explicit PromiseFactory(F f) : f_(std::move(f)) {} 156 157 Promise Once(Arg&& a) { 158 return PromiseFactoryImpl(std::move(f_), std::forward<Arg>(a)); 159 } 160 161 Promise Repeated(Arg&& a) const { 162 return PromiseFactoryImpl(f_, std::forward<Arg>(a)); 163 } 164 }; 165 166 template <typename F> 167 class PromiseFactory<void, F> { 168 private: 169 GPR_NO_UNIQUE_ADDRESS F f_; 170 171 public: 172 using Arg = void; 173 using Promise = decltype(PromiseFactoryImpl(std::move(f_))); 174 175 explicit PromiseFactory(F f) : f_(std::move(f)) {} 176 177 Promise Once() { return PromiseFactoryImpl(std::move(f_)); } 178 179 Promise Repeated() const { return PromiseFactoryImpl(f_); } 180 }; 181 182 } // namespace promise_detail 183 } // namespace grpc_core 184 185 #endif // GRPC_CORE_LIB_PROMISE_DETAIL_PROMISE_FACTORY_H 186