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_LIKE_H 16 #define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_PROMISE_LIKE_H 17 18 #include <grpc/support/port_platform.h> 19 20 #include <utility> 21 22 #include "absl/functional/any_invocable.h" 23 #include "absl/meta/type_traits.h" 24 #include "src/core/lib/promise/poll.h" 25 26 // A Promise is a callable object that returns Poll<T> for some T. 27 // Often when we're writing code that uses promises, we end up wanting to also 28 // deal with code that completes instantaneously - that is, it returns some T 29 // where T is not Poll. 30 // PromiseLike wraps any callable that takes no parameters and implements the 31 // Promise interface. For things that already return Poll, this wrapping does 32 // nothing. For things that do not return Poll, we wrap the return type in Poll. 33 // This allows us to write things like: 34 // Seq( 35 // [] { return 42; }, 36 // ...) 37 // in preference to things like: 38 // Seq( 39 // [] { return Poll<int>(42); }, 40 // ...) 41 // or: 42 // Seq( 43 // [] -> Poll<int> { return 42; }, 44 // ...) 45 // leading to slightly more concise code and eliminating some rules that in 46 // practice people find hard to deal with. 47 48 namespace grpc_core { 49 namespace promise_detail { 50 51 template <typename T> 52 struct PollWrapper { WrapPollWrapper53 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static Poll<T> Wrap(T&& x) { 54 return Poll<T>(std::forward<T>(x)); 55 } 56 }; 57 58 template <typename T> 59 struct PollWrapper<Poll<T>> { 60 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static Poll<T> Wrap(Poll<T>&& x) { 61 return std::forward<Poll<T>>(x); 62 } 63 }; 64 65 template <typename T> 66 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline auto WrapInPoll(T&& x) 67 -> decltype(PollWrapper<T>::Wrap(std::forward<T>(x))) { 68 return PollWrapper<T>::Wrap(std::forward<T>(x)); 69 } 70 71 // T -> T, const T& -> T 72 template <typename T> 73 using RemoveCVRef = absl::remove_cv_t<absl::remove_reference_t<T>>; 74 75 template <typename F, typename SfinaeVoid = void> 76 class PromiseLike; 77 78 template <> 79 class PromiseLike<void>; 80 81 template <typename F> 82 class PromiseLike<F, absl::enable_if_t<!std::is_void< 83 #if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \ 84 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) 85 std::invoke_result_t<F> 86 #else 87 typename std::result_of<F()>::type 88 #endif 89 >::value>> { 90 private: 91 GPR_NO_UNIQUE_ADDRESS RemoveCVRef<F> f_; 92 93 public: 94 // NOLINTNEXTLINE - internal detail that drastically simplifies calling code. 95 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION PromiseLike(F&& f) 96 : f_(std::forward<F>(f)) {} 97 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION auto operator()() 98 -> decltype(WrapInPoll(f_())) { 99 return WrapInPoll(f_()); 100 } 101 using Result = typename PollTraits<decltype(WrapInPoll(f_()))>::Type; 102 }; 103 104 template <typename F> 105 class PromiseLike<F, absl::enable_if_t<std::is_void< 106 #if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \ 107 (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) 108 std::invoke_result_t<F> 109 #else 110 typename std::result_of<F()>::type 111 #endif 112 >::value>> { 113 private: 114 GPR_NO_UNIQUE_ADDRESS RemoveCVRef<F> f_; 115 116 public: 117 // NOLINTNEXTLINE - internal detail that drastically simplifies calling code. 118 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION PromiseLike(F&& f) 119 : f_(std::forward<F>(f)) {} 120 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION Poll<Empty> operator()() { 121 f_(); 122 return Empty{}; 123 } 124 using Result = Empty; 125 }; 126 127 } // namespace promise_detail 128 } // namespace grpc_core 129 130 #endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_PROMISE_LIKE_H 131