1 // Copyright 2024 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_MATCH_PROMISE_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_MATCH_PROMISE_H
17
18 #include "absl/types/variant.h"
19 #include "src/core/lib/promise/detail/promise_factory.h"
20 #include "src/core/lib/promise/detail/promise_like.h"
21 #include "src/core/lib/promise/detail/promise_variant.h"
22 #include "src/core/util/overload.h"
23
24 namespace grpc_core {
25
26 namespace promise_detail {
27
28 // This types job is to visit a supplied variant, and apply a mapping
29 // Constructor from input types to promises, returning a variant full of
30 // promises.
31 template <typename Constructor, typename... Ts>
32 struct ConstructPromiseVariantVisitor {
33 // Factory functions supplied to the top level `Match` object, wrapped by
34 // OverloadType to become overloaded members.
35 Constructor constructor;
36
37 // Helper function... only callable once.
38 // Given a value, construct a Promise Factory that accepts that value type,
39 // and uses the constructor type above to map from that type to a promise
40 // returned by the factory.
41 // We use the Promise Factory infrastructure to deal with all the common
42 // variants of factory signatures that we've found to be convenient.
43 template <typename T>
CallConstructorThenFactoryConstructPromiseVariantVisitor44 auto CallConstructorThenFactory(T x) {
45 OncePromiseFactory<T, Constructor> factory(std::move(constructor));
46 return factory.Make(std::move(x));
47 }
48
49 // Polling operator.
50 // Given a visited type T, construct a Promise Factory, use it, and then cast
51 // the result into a variant type that covers ALL of the possible return types
52 // given the input types listed in Ts...
53 template <typename T>
54 auto operator()(T x) -> absl::variant<promise_detail::PromiseLike<
55 decltype(CallConstructorThenFactory(std::declval<Ts>()))>...> {
56 return CallConstructorThenFactory(std::move(x));
57 }
58 };
59
60 } // namespace promise_detail
61
62 // Match for promises
63 // Like the Match function takes a variant of some set of types,
64 // and a set of functions - one per variant type.
65 // We use these functions as Promise Factories, and return a Promise that can be
66 // polled selected by the type that was in the variant.
67 template <typename... Fs, typename... Ts>
MatchPromise(absl::variant<Ts...> value,Fs...fs)68 auto MatchPromise(absl::variant<Ts...> value, Fs... fs) {
69 // Construct a variant of promises using the factory functions fs, selected by
70 // the type held by value.
71 auto body = absl::visit(
72 promise_detail::ConstructPromiseVariantVisitor<OverloadType<Fs...>,
73 Ts...>{
74 OverloadType<Fs...>(std::move(fs)...)},
75 std::move(value));
76 // Wrap that in a PromiseVariant that provides the promise API on the wrapped
77 // variant.
78 return promise_detail::PromiseVariant<decltype(body)>(std::move(body));
79 }
80
81 } // namespace grpc_core
82
83 #endif // GRPC_SRC_CORE_LIB_PROMISE_MATCH_PROMISE_H
84