From db3584dc9ecc498508d14f38be28edf478d3cd36 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 2 Jan 2024 09:36:25 -0800 Subject: [PATCH 01/53] [call-v3] Convert RBAC to new api (#35421) Closes #35421 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35421 from ctiller:rrrrrback 8ff26a1dd44adedb03a02deb4ec4a8284d13f934 PiperOrigin-RevId: 595138895 --- src/core/ext/filters/rbac/rbac_filter.cc | 26 ++++++---- src/core/ext/filters/rbac/rbac_filter.h | 15 ++++-- src/core/lib/channel/promise_based_filter.h | 56 +++++++++++++++++++++ 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/core/ext/filters/rbac/rbac_filter.cc b/src/core/ext/filters/rbac/rbac_filter.cc index 77b6dd46ad7..3481b434bb8 100644 --- a/src/core/ext/filters/rbac/rbac_filter.cc +++ b/src/core/ext/filters/rbac/rbac_filter.cc @@ -43,8 +43,14 @@ namespace grpc_core { -ArenaPromise RbacFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { +const NoInterceptor RbacFilter::Call::OnServerInitialMetadata; +const NoInterceptor RbacFilter::Call::OnServerTrailingMetadata; +const NoInterceptor RbacFilter::Call::OnClientToServerMessage; +const NoInterceptor RbacFilter::Call::OnServerToClientMessage; +const NoInterceptor RbacFilter::Call::OnFinalize; + +absl::Status RbacFilter::Call::OnClientInitialMetadata(ClientMetadata& md, + RbacFilter* filter) { // Fetch and apply the rbac policy from the service config. auto* service_config_call_data = static_cast( GetContext< @@ -52,21 +58,19 @@ ArenaPromise RbacFilter::MakeCallPromise( .value); auto* method_params = static_cast( service_config_call_data->GetMethodParsedConfig( - service_config_parser_index_)); + filter->service_config_parser_index_)); if (method_params == nullptr) { - return Immediate(ServerMetadataFromStatus( - absl::PermissionDeniedError("No RBAC policy found."))); + return absl::PermissionDeniedError("No RBAC policy found."); } else { - auto* authorization_engine = method_params->authorization_engine(index_); + auto* authorization_engine = + method_params->authorization_engine(filter->index_); if (authorization_engine - ->Evaluate(EvaluateArgs(call_args.client_initial_metadata.get(), - &per_channel_evaluate_args_)) + ->Evaluate(EvaluateArgs(&md, &filter->per_channel_evaluate_args_)) .type == AuthorizationEngine::Decision::Type::kDeny) { - return Immediate(ServerMetadataFromStatus( - absl::PermissionDeniedError("Unauthorized RPC rejected"))); + return absl::PermissionDeniedError("Unauthorized RPC rejected"); } } - return next_promise_factory(std::move(call_args)); + return absl::OkStatus(); } const grpc_channel_filter RbacFilter::kFilterVtable = diff --git a/src/core/ext/filters/rbac/rbac_filter.h b/src/core/ext/filters/rbac/rbac_filter.h index 1bc923c4e22..f2208753b6b 100644 --- a/src/core/ext/filters/rbac/rbac_filter.h +++ b/src/core/ext/filters/rbac/rbac_filter.h @@ -34,7 +34,7 @@ namespace grpc_core { // Filter used when xDS server config fetcher provides a configuration with an // HTTP RBAC filter. Also serves as the type for channel data for the filter. -class RbacFilter : public ChannelFilter { +class RbacFilter : public ImplementChannelFilter { public: // This channel filter is intended to be used by connections on xDS enabled // servers configured with RBAC. The RBAC filter fetches the RBAC policy from @@ -45,9 +45,16 @@ class RbacFilter : public ChannelFilter { static absl::StatusOr Create(const ChannelArgs& args, ChannelFilter::Args filter_args); - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + absl::Status OnClientInitialMetadata(ClientMetadata& md, + RbacFilter* filter); + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; + }; private: RbacFilter(size_t index, diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h index 5c3b7ddb55a..898970d1f48 100644 --- a/src/core/lib/channel/promise_based_filter.h +++ b/src/core/lib/channel/promise_based_filter.h @@ -378,6 +378,33 @@ struct RunCallImpl +struct RunCallImpl { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) + -> ArenaPromise { + auto status = call_data->call.OnClientInitialMetadata( + *call_args.client_initial_metadata); + if (status.ok()) return next_promise_factory(std::move(call_args)); + return Immediate(ServerMetadataFromStatus(status)); + } +}; + +template +struct RunCallImpl { + static auto Run(CallArgs call_args, NextPromiseFactory next_promise_factory, + FilterCallData* call_data) + -> ArenaPromise { + auto status = call_data->call.OnClientInitialMetadata( + *call_args.client_initial_metadata, call_data->channel); + if (status.ok()) return next_promise_factory(std::move(call_args)); + return Immediate(ServerMetadataFromStatus(status)); + } +}; + template struct RunCallImpl< void (Derived::Call::*)(ClientMetadata& md, Derived* channel), Derived> { @@ -593,6 +620,35 @@ inline void InterceptClientInitialMetadata( }); } +template +inline void InterceptClientInitialMetadata( + absl::Status (Derived::Call::*fn)(ClientMetadata& md), + typename Derived::Call* call, Derived*, CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call_spine, + call](ClientMetadataHandle md) -> absl::optional { + auto status = call->OnClientInitialMetadata(*md); + if (status.ok()) return std::move(md); + return call_spine->Cancel(ServerMetadataFromStatus(status)); + }); +} + +template +inline void InterceptClientInitialMetadata( + absl::Status (Derived::Call::*fn)(ClientMetadata& md, Derived* channel), + typename Derived::Call* call, Derived* channel, + CallSpineInterface* call_spine) { + GPR_DEBUG_ASSERT(fn == &Derived::Call::OnClientInitialMetadata); + call_spine->client_initial_metadata().receiver.InterceptAndMap( + [call_spine, call, channel]( + ClientMetadataHandle md) -> absl::optional { + auto status = call->OnClientInitialMetadata(*md, channel); + if (status.ok()) return std::move(md); + return call_spine->Cancel(ServerMetadataFromStatus(status)); + }); +} + // Returning a promise that resolves to something that can be cast to // ServerMetadataHandle also counts template From 9a6744b6bffab4b216c29a4ac8f77109c9c1dba9 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 2 Jan 2024 09:43:53 -0800 Subject: [PATCH 02/53] [call-v3] Convert ServiceConfigChannelArgFilter to new API (#35418) Omitting experiments in this case because the conversion is trivial Closes #35418 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35418 from ctiller:scca ae131d81645d2256ae1943c5c55d2592cb134c9e PiperOrigin-RevId: 595140546 --- .../service_config_channel_arg_filter.cc | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc b/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc index 9de7fe2e374..54169fcab06 100644 --- a/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc +++ b/src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc @@ -54,7 +54,8 @@ namespace grpc_core { namespace { -class ServiceConfigChannelArgFilter : public ChannelFilter { +class ServiceConfigChannelArgFilter + : public ImplementChannelFilter { public: static absl::StatusOr Create( const ChannelArgs& args, ChannelFilter::Args) { @@ -74,28 +75,43 @@ class ServiceConfigChannelArgFilter : public ChannelFilter { } } - // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + void OnClientInitialMetadata(ClientMetadata& md, + ServiceConfigChannelArgFilter* filter); + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; + }; private: RefCountedPtr service_config_; }; -ArenaPromise -ServiceConfigChannelArgFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { +const NoInterceptor + ServiceConfigChannelArgFilter::Call::OnServerInitialMetadata; +const NoInterceptor + ServiceConfigChannelArgFilter::Call::OnServerTrailingMetadata; +const NoInterceptor + ServiceConfigChannelArgFilter::Call::OnClientToServerMessage; +const NoInterceptor + ServiceConfigChannelArgFilter::Call::OnServerToClientMessage; +const NoInterceptor ServiceConfigChannelArgFilter::Call::OnFinalize; + +void ServiceConfigChannelArgFilter::Call::OnClientInitialMetadata( + ClientMetadata& md, ServiceConfigChannelArgFilter* filter) { const ServiceConfigParser::ParsedConfigVector* method_configs = nullptr; - if (service_config_ != nullptr) { - method_configs = service_config_->GetMethodParsedConfigVector( - call_args.client_initial_metadata->get_pointer(HttpPathMetadata()) - ->c_slice()); + if (filter->service_config_ != nullptr) { + method_configs = filter->service_config_->GetMethodParsedConfigVector( + md.get_pointer(HttpPathMetadata())->c_slice()); } auto* arena = GetContext(); auto* service_config_call_data = arena->New( arena, GetContext()); - service_config_call_data->SetServiceConfig(service_config_, method_configs); - return next_promise_factory(std::move(call_args)); + service_config_call_data->SetServiceConfig(filter->service_config_, + method_configs); } const grpc_channel_filter kServiceConfigChannelArgFilter = From 1383c4629bcc9c74da5133286734ab28e88eabd3 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 2 Jan 2024 09:44:49 -0800 Subject: [PATCH 03/53] [call-v3] Move `FaultInjectionFilter` to v3 api (#35420) Closes #35420 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35420 from ctiller:plead-the-fif 1a7cb7aef3216426a338400f2aa3bf1f8677bd20 PiperOrigin-RevId: 595140790 --- .../fault_injection/fault_injection_filter.cc | 30 +++++++++++-------- .../fault_injection/fault_injection_filter.h | 17 ++++++++--- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/core/ext/filters/fault_injection/fault_injection_filter.cc b/src/core/ext/filters/fault_injection/fault_injection_filter.cc index 843de69bbc1..6ddc4c26230 100644 --- a/src/core/ext/filters/fault_injection/fault_injection_filter.cc +++ b/src/core/ext/filters/fault_injection/fault_injection_filter.cc @@ -54,6 +54,11 @@ namespace grpc_core { TraceFlag grpc_fault_injection_filter_trace(false, "fault_injection_filter"); +const NoInterceptor FaultInjectionFilter::Call::OnServerInitialMetadata; +const NoInterceptor FaultInjectionFilter::Call::OnServerTrailingMetadata; +const NoInterceptor FaultInjectionFilter::Call::OnClientToServerMessage; +const NoInterceptor FaultInjectionFilter::Call::OnServerToClientMessage; +const NoInterceptor FaultInjectionFilter::Call::OnFinalize; namespace { @@ -144,23 +149,22 @@ FaultInjectionFilter::FaultInjectionFilter(ChannelFilter::Args filter_args) mu_(new Mutex) {} // Construct a promise for one call. -ArenaPromise FaultInjectionFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { - auto decision = MakeInjectionDecision(call_args.client_initial_metadata); +ArenaPromise FaultInjectionFilter::Call::OnClientInitialMetadata( + ClientMetadata& md, FaultInjectionFilter* filter) { + auto decision = filter->MakeInjectionDecision(md); if (GRPC_TRACE_FLAG_ENABLED(grpc_fault_injection_filter_trace)) { gpr_log(GPR_INFO, "chand=%p: Fault injection triggered %s", this, decision.ToString().c_str()); } auto delay = decision.DelayUntil(); - return TrySeq( - Sleep(delay), - [decision = std::move(decision)]() { return decision.MaybeAbort(); }, - next_promise_factory(std::move(call_args))); + return TrySeq(Sleep(delay), [decision = std::move(decision)]() { + return decision.MaybeAbort(); + }); } FaultInjectionFilter::InjectionDecision FaultInjectionFilter::MakeInjectionDecision( - const ClientMetadataHandle& initial_metadata) { + const ClientMetadata& initial_metadata) { // Fetch the fault injection policy from the service config, based on the // relative index for which policy should this CallData use. auto* service_config_call_data = static_cast( @@ -188,15 +192,15 @@ FaultInjectionFilter::MakeInjectionDecision( !fi_policy->delay_percentage_header.empty()) { std::string buffer; if (!fi_policy->abort_code_header.empty() && abort_code == GRPC_STATUS_OK) { - auto value = initial_metadata->GetStringValue( - fi_policy->abort_code_header, &buffer); + auto value = initial_metadata.GetStringValue(fi_policy->abort_code_header, + &buffer); if (value.has_value()) { grpc_status_code_from_int( AsInt(*value).value_or(GRPC_STATUS_UNKNOWN), &abort_code); } } if (!fi_policy->abort_percentage_header.empty()) { - auto value = initial_metadata->GetStringValue( + auto value = initial_metadata.GetStringValue( fi_policy->abort_percentage_header, &buffer); if (value.has_value()) { abort_percentage_numerator = std::min( @@ -205,14 +209,14 @@ FaultInjectionFilter::MakeInjectionDecision( } if (!fi_policy->delay_header.empty() && delay == Duration::Zero()) { auto value = - initial_metadata->GetStringValue(fi_policy->delay_header, &buffer); + initial_metadata.GetStringValue(fi_policy->delay_header, &buffer); if (value.has_value()) { delay = Duration::Milliseconds( std::max(AsInt(*value).value_or(0), int64_t{0})); } } if (!fi_policy->delay_percentage_header.empty()) { - auto value = initial_metadata->GetStringValue( + auto value = initial_metadata.GetStringValue( fi_policy->delay_percentage_header, &buffer); if (value.has_value()) { delay_percentage_numerator = std::min( diff --git a/src/core/ext/filters/fault_injection/fault_injection_filter.h b/src/core/ext/filters/fault_injection/fault_injection_filter.h index ed1006f4e66..e2918e854f5 100644 --- a/src/core/ext/filters/fault_injection/fault_injection_filter.h +++ b/src/core/ext/filters/fault_injection/fault_injection_filter.h @@ -40,7 +40,8 @@ namespace grpc_core { // of the ordinary channel stack. The fault injection filter fetches fault // injection policy from the method config of service config returned by the // resolver, and enforces the fault injection policy. -class FaultInjectionFilter : public ChannelFilter { +class FaultInjectionFilter + : public ImplementChannelFilter { public: static const grpc_channel_filter kFilter; @@ -48,15 +49,23 @@ class FaultInjectionFilter : public ChannelFilter { const ChannelArgs& args, ChannelFilter::Args filter_args); // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + ArenaPromise OnClientInitialMetadata( + ClientMetadata& md, FaultInjectionFilter* filter); + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; + }; private: explicit FaultInjectionFilter(ChannelFilter::Args filter_args); class InjectionDecision; InjectionDecision MakeInjectionDecision( - const ClientMetadataHandle& initial_metadata); + const ClientMetadata& initial_metadata); // The relative index of instances of the same filter. size_t index_; From 75e5ebcb14a7a16e1cb5994853e2a6215dbf97e8 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 2 Jan 2024 09:45:45 -0800 Subject: [PATCH 04/53] [promises] Add a switch primitive (#35424) Remove the old `switch` library - this used to be an implementation detail of `Seq`, `TrySeq` - but has become unused. Add a new user facing primitive `Switch` that fills a similar role to `switch` in C++ - selecting a promise to execute based on a primitive discriminator - much like `If` allows selection based on a boolean discriminator now. A future change will optimize this to actually lower the `Switch` into an actual `switch` statement, but for right now I want to get the functionality in. Closes #35424 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35424 from ctiller:switchy 5308a914c689b79e5e83f218ae0cd7e88bc0034e PiperOrigin-RevId: 595140965 --- CMakeLists.txt | 36 + build_autogenerated.yaml | 18 + src/core/BUILD | 20 +- src/core/lib/promise/detail/switch.h | 1455 -------------------------- src/core/lib/promise/switch.h | 72 ++ test/core/promise/BUILD | 11 + test/core/promise/switch_test.cc | 69 ++ tools/codegen/core/gen_switch.py | 78 -- tools/run_tests/generated/tests.json | 24 + 9 files changed, 241 insertions(+), 1542 deletions(-) delete mode 100644 src/core/lib/promise/detail/switch.h create mode 100644 src/core/lib/promise/switch.h create mode 100644 test/core/promise/switch_test.cc delete mode 100755 tools/codegen/core/gen_switch.py diff --git a/CMakeLists.txt b/CMakeLists.txt index d15ae57b0f8..939249812d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1372,6 +1372,7 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx streams_not_seen_test) add_dependencies(buildtests_cxx string_ref_test) add_dependencies(buildtests_cxx string_test) + add_dependencies(buildtests_cxx switch_test) add_dependencies(buildtests_cxx sync_test) add_dependencies(buildtests_cxx system_roots_test) add_dependencies(buildtests_cxx table_test) @@ -23771,6 +23772,41 @@ target_link_libraries(string_test ) +endif() +if(gRPC_BUILD_TESTS) + +add_executable(switch_test + test/core/promise/switch_test.cc +) +target_compile_features(switch_test PUBLIC cxx_std_14) +target_include_directories(switch_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(switch_test + ${_gRPC_ALLTARGETS_LIBRARIES} + gtest + absl::type_traits + absl::statusor + gpr +) + + endif() if(gRPC_BUILD_TESTS) diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 462631306ab..1849ce804a2 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -16282,6 +16282,24 @@ targets: - gtest - grpc_test_util uses_polling: false +- name: switch_test + gtest: true + build: test + language: c++ + headers: + - src/core/lib/promise/detail/promise_factory.h + - src/core/lib/promise/detail/promise_like.h + - src/core/lib/promise/if.h + - src/core/lib/promise/poll.h + - src/core/lib/promise/switch.h + src: + - test/core/promise/switch_test.cc + deps: + - gtest + - absl/meta:type_traits + - absl/status:statusor + - gpr + uses_polling: false - name: sync_test gtest: true build: test diff --git a/src/core/BUILD b/src/core/BUILD index fccb572aa67..57b476033c4 100644 --- a/src/core/BUILD +++ b/src/core/BUILD @@ -619,6 +619,17 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "switch", + language = "c++", + public_hdrs = ["lib/promise/switch.h"], + deps = [ + "if", + "promise_factory", + "//:gpr_platform", + ], +) + grpc_cc_library( name = "promise_status", external_deps = [ @@ -736,15 +747,6 @@ grpc_cc_library( ], ) -grpc_cc_library( - name = "switch", - language = "c++", - public_hdrs = [ - "lib/promise/detail/switch.h", - ], - deps = ["//:gpr_platform"], -) - grpc_cc_library( name = "basic_seq", language = "c++", diff --git a/src/core/lib/promise/detail/switch.h b/src/core/lib/promise/detail/switch.h deleted file mode 100644 index a823b260609..00000000000 --- a/src/core/lib/promise/detail/switch.h +++ /dev/null @@ -1,1455 +0,0 @@ -// -// Copyright 2021 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// -// Automatically generated by tools/codegen/core/gen_switch.py -// - -#ifndef GRPC_SRC_CORE_LIB_PROMISE_DETAIL_SWITCH_H -#define GRPC_SRC_CORE_LIB_PROMISE_DETAIL_SWITCH_H - -#include - -#include - -namespace grpc_core { - -template -R Switch(char idx, F0 f0) { - switch (idx) { - case 0: - return f0(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, - F23 f23) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25, F26 f26) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - case 26: - return f26(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25, F26 f26, F27 f27) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - case 26: - return f26(); - case 27: - return f27(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25, F26 f26, F27 f27, F28 f28) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - case 26: - return f26(); - case 27: - return f27(); - case 28: - return f28(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25, F26 f26, F27 f27, F28 f28, F29 f29) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - case 26: - return f26(); - case 27: - return f27(); - case 28: - return f28(); - case 29: - return f29(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25, F26 f26, F27 f27, F28 f28, F29 f29, F30 f30) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - case 26: - return f26(); - case 27: - return f27(); - case 28: - return f28(); - case 29: - return f29(); - case 30: - return f30(); - } - abort(); -} - -template -R Switch(char idx, F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, - F8 f8, F9 f9, F10 f10, F11 f11, F12 f12, F13 f13, F14 f14, F15 f15, - F16 f16, F17 f17, F18 f18, F19 f19, F20 f20, F21 f21, F22 f22, F23 f23, - F24 f24, F25 f25, F26 f26, F27 f27, F28 f28, F29 f29, F30 f30, - F31 f31) { - switch (idx) { - case 0: - return f0(); - case 1: - return f1(); - case 2: - return f2(); - case 3: - return f3(); - case 4: - return f4(); - case 5: - return f5(); - case 6: - return f6(); - case 7: - return f7(); - case 8: - return f8(); - case 9: - return f9(); - case 10: - return f10(); - case 11: - return f11(); - case 12: - return f12(); - case 13: - return f13(); - case 14: - return f14(); - case 15: - return f15(); - case 16: - return f16(); - case 17: - return f17(); - case 18: - return f18(); - case 19: - return f19(); - case 20: - return f20(); - case 21: - return f21(); - case 22: - return f22(); - case 23: - return f23(); - case 24: - return f24(); - case 25: - return f25(); - case 26: - return f26(); - case 27: - return f27(); - case 28: - return f28(); - case 29: - return f29(); - case 30: - return f30(); - case 31: - return f31(); - } - abort(); -} - -} // namespace grpc_core - -#endif // GRPC_SRC_CORE_LIB_PROMISE_DETAIL_SWITCH_H diff --git a/src/core/lib/promise/switch.h b/src/core/lib/promise/switch.h new file mode 100644 index 00000000000..1bb05507ef2 --- /dev/null +++ b/src/core/lib/promise/switch.h @@ -0,0 +1,72 @@ +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GRPC_SRC_CORE_LIB_PROMISE_SWITCH_H +#define GRPC_SRC_CORE_LIB_PROMISE_SWITCH_H + +#include + +#include +#include + +#include "src/core/lib/promise/detail/promise_factory.h" +#include "src/core/lib/promise/if.h" + +namespace grpc_core { + +namespace promise_detail { +template +struct Case { + D discriminator; + F factory; +}; + +template +struct Default { + F factory; +}; +} // namespace promise_detail + +template +auto Case(D discriminator, PromiseFactory f) { + return promise_detail::Case{discriminator, std::move(f)}; +} + +template +auto Default(PromiseFactory f) { + return promise_detail::Default{std::move(f)}; +} + +// Given a list of cases that result in promise factories, return a single +// promise chosen by the discriminator (the first argument of this function). +// e.g.: +// Switch(1, Case<1>([] { return 43; }), Case<2>([] { return 44; })) +// resolves to 43. +// TODO(ctiller): consider writing a code-generator like we do for seq/join +// so that this lowers into a C switch statement. +template +auto Switch(D, promise_detail::Default def) { + return promise_detail::OncePromiseFactory(std::move(def.factory)) + .Make(); +} + +template +auto Switch(D discriminator, promise_detail::Case c, Others... others) { + return If(discriminator == c.discriminator, std::move(c.factory), + Switch(discriminator, std::move(others)...)); +} + +} // namespace grpc_core + +#endif // GRPC_SRC_CORE_LIB_PROMISE_SWITCH_H diff --git a/test/core/promise/BUILD b/test/core/promise/BUILD index b4c4ce855c6..a035820d5a8 100644 --- a/test/core/promise/BUILD +++ b/test/core/promise/BUILD @@ -197,6 +197,17 @@ grpc_cc_test( deps = ["//src/core:if"], ) +grpc_cc_test( + name = "switch_test", + srcs = ["switch_test.cc"], + external_deps = ["gtest"], + language = "c++", + tags = ["promise_test"], + uses_event_engine = False, + uses_polling = False, + deps = ["//src/core:switch"], +) + grpc_cc_test( name = "loop_test", srcs = ["loop_test.cc"], diff --git a/test/core/promise/switch_test.cc b/test/core/promise/switch_test.cc new file mode 100644 index 00000000000..ed18c1113ed --- /dev/null +++ b/test/core/promise/switch_test.cc @@ -0,0 +1,69 @@ +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/core/lib/promise/switch.h" + +#include "gtest/gtest.h" + +namespace grpc_core { + +TEST(SwitchTest, JustDefault) { + EXPECT_EQ(Switch(42, Default([] { return 1; }))(), Poll(1)); +} + +TEST(SwitchTest, ThreeCases) { + auto test_switch = [](int d) { + return Switch(d, Case(1, [] { return 25; }), Case(2, [] { return 95; }), + Case(3, [] { return 68; }), Default([] { return 52; })); + }; + EXPECT_EQ(test_switch(0)(), Poll(52)); + EXPECT_EQ(test_switch(1)(), Poll(25)); + EXPECT_EQ(test_switch(2)(), Poll(95)); + EXPECT_EQ(test_switch(3)(), Poll(68)); + EXPECT_EQ(test_switch(4)(), Poll(52)); +} + +TEST(SwitchTest, Pending) { + auto test_switch = [](int d) { + return Switch(d, Case(42, []() -> Poll { return Pending{}; }), + Case(1, [] { return 25; }), Case(2, [] { return 95; }), + Case(3, [] { return 68; }), Default([] { return 52; })); + }; + EXPECT_EQ(test_switch(0)(), Poll(52)); + EXPECT_EQ(test_switch(1)(), Poll(25)); + EXPECT_EQ(test_switch(2)(), Poll(95)); + EXPECT_EQ(test_switch(3)(), Poll(68)); + EXPECT_EQ(test_switch(4)(), Poll(52)); + EXPECT_EQ(test_switch(42)(), Poll(Pending{})); +} + +TEST(SwitchTest, ThreeCasesFromEnum) { + enum class X : uint8_t { A, B, C }; + + auto test_switch = [](X d) { + return Switch(d, Case(X::A, [] { return 25; }), + Case(X::B, [] { return 95; }), Case(X::C, [] { return 68; }), + Default([] { return 52; })); + }; + EXPECT_EQ(test_switch(X::A)(), Poll(25)); + EXPECT_EQ(test_switch(X::B)(), Poll(95)); + EXPECT_EQ(test_switch(X::C)(), Poll(68)); +} + +} // namespace grpc_core + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tools/codegen/core/gen_switch.py b/tools/codegen/core/gen_switch.py deleted file mode 100755 index 80e53c6416d..00000000000 --- a/tools/codegen/core/gen_switch.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2021 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys - - -# utility: print a big comment block into a set of files -def put_banner(files, banner): - for f in files: - print("/*", file=f) - for line in banner: - print(" * %s" % line, file=f) - print(" */", file=f) - print("", file=f) - - -with open("src/core/lib/promise/detail/switch.h", "w") as H: - # copy-paste copyright notice from this file - with open(sys.argv[0]) as my_source: - copyright = [] - for line in my_source: - if line[0] != "#": - break - for line in my_source: - if line[0] == "#": - copyright.append(line) - break - for line in my_source: - if line[0] != "#": - break - copyright.append(line) - put_banner([H], [line[2:].rstrip() for line in copyright]) - - put_banner([H], ["Automatically generated by %s" % sys.argv[0]]) - - print("#ifndef GRPC_CORE_LIB_PROMISE_DETAIL_SWITCH_H", file=H) - print("#define GRPC_CORE_LIB_PROMISE_DETAIL_SWITCH_H", file=H) - print("", file=H) - print("#include ", file=H) - print("", file=H) - print("#include ", file=H) - print("", file=H) - print("namespace grpc_core {", file=H) - - for n in range(1, 33): - print("", file=H) - print( - "template R Switch(char idx, %s) {" - % ( - ", ".join("typename F%d" % i for i in range(0, n)), - ", ".join("F%d f%d" % (i, i) for i in range(0, n)), - ), - file=H, - ) - print(" switch (idx) {", file=H) - for i in range(0, n): - print(" case %d: return f%d();" % (i, i), file=H) - print(" }", file=H) - print(" abort();", file=H) - print("}", file=H) - - print("", file=H) - print("}", file=H) - print("", file=H) - print("#endif // GRPC_CORE_LIB_PROMISE_DETAIL_SWITCH_H", file=H) diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 97e35cd758b..665d030a6fb 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -9925,6 +9925,30 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "switch_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [], "benchmark": false, From ecc2bbac3bfd81950d4ea6fce4b7b7003abfd3c1 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 2 Jan 2024 10:02:03 -0800 Subject: [PATCH 05/53] [call-v3] Move `XdsResolver::ClusterSelectionFilter` to v3 api (#35419) Omit experiments due to trivial refactor Closes #35419 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35419 from ctiller:xds1 4c639752a03d75d31262ab05ae630afc07cb1cbc PiperOrigin-RevId: 595144625 --- .../resolver/xds/xds_resolver.cc | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc index 732f07169bc..9cc094f0499 100644 --- a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc @@ -312,7 +312,8 @@ class XdsResolver : public Resolver { RouteConfigData::RouteEntry* route_; }; - class ClusterSelectionFilter : public ChannelFilter { + class ClusterSelectionFilter + : public ImplementChannelFilter { public: const static grpc_channel_filter kFilter; @@ -322,8 +323,15 @@ class XdsResolver : public Resolver { } // Construct a promise for one call. - ArenaPromise MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) override; + class Call { + public: + void OnClientInitialMetadata(ClientMetadata& md); + static const NoInterceptor OnServerInitialMetadata; + static const NoInterceptor OnServerTrailingMetadata; + static const NoInterceptor OnClientToServerMessage; + static const NoInterceptor OnServerToClientMessage; + static const NoInterceptor OnFinalize; + }; private: explicit ClusterSelectionFilter(ChannelFilter::Args filter_args) @@ -374,6 +382,16 @@ class XdsResolver : public Resolver { std::map> cluster_ref_map_; }; +const NoInterceptor + XdsResolver::ClusterSelectionFilter::Call::OnServerInitialMetadata; +const NoInterceptor + XdsResolver::ClusterSelectionFilter::Call::OnServerTrailingMetadata; +const NoInterceptor + XdsResolver::ClusterSelectionFilter::Call::OnClientToServerMessage; +const NoInterceptor + XdsResolver::ClusterSelectionFilter::Call::OnServerToClientMessage; +const NoInterceptor XdsResolver::ClusterSelectionFilter::Call::OnFinalize; + // // XdsResolver::RouteConfigData::RouteListIterator // @@ -835,9 +853,8 @@ const grpc_channel_filter XdsResolver::ClusterSelectionFilter::kFilter = kFilterExaminesServerInitialMetadata>( "cluster_selection_filter"); -ArenaPromise -XdsResolver::ClusterSelectionFilter::MakeCallPromise( - CallArgs call_args, NextPromiseFactory next_promise_factory) { +void XdsResolver::ClusterSelectionFilter::Call::OnClientInitialMetadata( + ClientMetadata&) { auto* service_config_call_data = static_cast( GetContext() @@ -856,7 +873,6 @@ XdsResolver::ClusterSelectionFilter::MakeCallPromise( [cluster = std::move(cluster)]() mutable { cluster.reset(); }); } } - return next_promise_factory(std::move(call_args)); } // From 99cafa32d9d63eb612e9956494e89075fe023cf7 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 2 Jan 2024 10:13:20 -0800 Subject: [PATCH 06/53] [promises] Expand maximum `Seq` length (#35423) Closes #35423 COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35423 from ctiller:seqqy fea10949d35881a33511fbe7a2f0311edde106f5 PiperOrigin-RevId: 595147939 --- src/core/lib/promise/detail/seq_state.h | 3041 +++++++++++++++++++++++ src/core/lib/promise/seq.h | 45 + tools/codegen/core/gen_seq.py | 2 +- 3 files changed, 3087 insertions(+), 1 deletion(-) diff --git a/src/core/lib/promise/detail/seq_state.h b/src/core/lib/promise/detail/seq_state.h index 97547465fcc..147ff10e6f1 100644 --- a/src/core/lib/promise/detail/seq_state.h +++ b/src/core/lib/promise/detail/seq_state.h @@ -2754,6 +2754,3047 @@ struct SeqState { } }; +template