[call-v3] initial surface call integration (#35312)

Adds temporary `call.cc` and `connected_channel.cc` scaffolding to run `CallInterceptor`/`CallHandler` style calls.
This will get ripped out as soon as the v3 transition is completed.

Closes #35312

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35312 from ctiller:v3-accept ae0bf81f8b
PiperOrigin-RevId: 594128029
pull/34728/merge
Craig Tiller 11 months ago committed by Copybara-Service
parent b25a382b60
commit f703530b6d
  1. 3
      BUILD
  2. 2
      CMakeLists.txt
  3. 4
      Package.swift
  4. 27
      build_autogenerated.yaml
  5. 8
      gRPC-C++.podspec
  6. 8
      gRPC-Core.podspec
  7. 4
      grpc.gemspec
  8. 4
      package.xml
  9. 3
      src/core/BUILD
  10. 4
      src/core/ext/transport/chaotic_good/client_transport.cc
  11. 2
      src/core/ext/transport/chaotic_good/client_transport.h
  12. 10
      src/core/lib/channel/channel_stack.cc
  13. 81
      src/core/lib/channel/connected_channel.cc
  14. 1
      src/core/lib/promise/detail/promise_factory.h
  15. 2
      src/core/lib/promise/latch.h
  16. 49
      src/core/lib/promise/status_flag.h
  17. 45
      src/core/lib/promise/try_join.h
  18. 4
      src/core/lib/promise/try_seq.h
  19. 862
      src/core/lib/surface/call.cc
  20. 38
      src/core/lib/surface/call.h
  21. 305
      src/core/lib/surface/server.cc
  22. 1
      src/core/lib/surface/server.h
  23. 94
      src/core/lib/surface/wait_for_cq_end_op.h
  24. 12
      src/core/lib/transport/transport.h
  25. 5
      test/core/promise/status_flag_test.cc
  26. 150
      test/core/promise/try_join_test.cc
  27. 138
      test/core/promise/try_seq_test.cc
  28. 4
      tools/doxygen/Doxyfile.c++.internal
  29. 4
      tools/doxygen/Doxyfile.core.internal

@ -1464,6 +1464,7 @@ grpc_cc_library(
"//src/core:lib/surface/lame_client.h",
"//src/core:lib/surface/server.h",
"//src/core:lib/surface/validate_metadata.h",
"//src/core:lib/surface/wait_for_cq_end_op.h",
"//src/core:lib/transport/batch_builder.h",
"//src/core:lib/transport/connectivity_state.h",
"//src/core:lib/transport/custom_metadata.h",
@ -1540,6 +1541,7 @@ grpc_cc_library(
"work_serializer",
"//src/core:1999",
"//src/core:activity",
"//src/core:all_ok",
"//src/core:arena",
"//src/core:arena_promise",
"//src/core:atomic_utils",
@ -1612,6 +1614,7 @@ grpc_cc_library(
"//src/core:thread_quota",
"//src/core:time",
"//src/core:transport_fwd",
"//src/core:try_join",
"//src/core:try_seq",
"//src/core:type_list",
"//src/core:useful",

2
CMakeLists.txt generated

@ -23456,8 +23456,8 @@ target_include_directories(status_flag_test
target_link_libraries(status_flag_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::status
absl::statusor
gpr
)

4
Package.swift generated

@ -1634,10 +1634,12 @@ let package = Package(
"src/core/lib/matchers/matchers.h",
"src/core/lib/promise/activity.cc",
"src/core/lib/promise/activity.h",
"src/core/lib/promise/all_ok.h",
"src/core/lib/promise/arena_promise.h",
"src/core/lib/promise/cancel_callback.h",
"src/core/lib/promise/context.h",
"src/core/lib/promise/detail/basic_seq.h",
"src/core/lib/promise/detail/join_state.h",
"src/core/lib/promise/detail/promise_factory.h",
"src/core/lib/promise/detail/promise_like.h",
"src/core/lib/promise/detail/seq_state.h",
@ -1662,6 +1664,7 @@ let package = Package(
"src/core/lib/promise/status_flag.h",
"src/core/lib/promise/trace.cc",
"src/core/lib/promise/trace.h",
"src/core/lib/promise/try_join.h",
"src/core/lib/promise/try_seq.h",
"src/core/lib/resolver/endpoint_addresses.cc",
"src/core/lib/resolver/endpoint_addresses.h",
@ -1869,6 +1872,7 @@ let package = Package(
"src/core/lib/surface/validate_metadata.cc",
"src/core/lib/surface/validate_metadata.h",
"src/core/lib/surface/version.cc",
"src/core/lib/surface/wait_for_cq_end_op.h",
"src/core/lib/transport/batch_builder.cc",
"src/core/lib/transport/batch_builder.h",
"src/core/lib/transport/bdp_estimator.cc",

@ -1033,10 +1033,12 @@ libs:
- src/core/lib/load_balancing/subchannel_interface.h
- src/core/lib/matchers/matchers.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/all_ok.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/cancel_callback.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/seq_state.h
@ -1058,6 +1060,7 @@ libs:
- src/core/lib/promise/sleep.h
- src/core/lib/promise/status_flag.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/endpoint_addresses.h
- src/core/lib/resolver/resolver.h
@ -1156,6 +1159,7 @@ libs:
- src/core/lib/surface/lame_client.h
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/surface/wait_for_cq_end_op.h
- src/core/lib/transport/batch_builder.h
- src/core/lib/transport/bdp_estimator.h
- src/core/lib/transport/connectivity_state.h
@ -2490,10 +2494,12 @@ libs:
- src/core/lib/load_balancing/lb_policy_registry.h
- src/core/lib/load_balancing/subchannel_interface.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/all_ok.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/cancel_callback.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/seq_state.h
@ -2515,6 +2521,7 @@ libs:
- src/core/lib/promise/sleep.h
- src/core/lib/promise/status_flag.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/endpoint_addresses.h
- src/core/lib/resolver/resolver.h
@ -2582,6 +2589,7 @@ libs:
- src/core/lib/surface/lame_client.h
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/surface/wait_for_cq_end_op.h
- src/core/lib/transport/batch_builder.h
- src/core/lib/transport/bdp_estimator.h
- src/core/lib/transport/connectivity_state.h
@ -4624,10 +4632,12 @@ libs:
- src/core/lib/load_balancing/subchannel_interface.h
- src/core/lib/matchers/matchers.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/all_ok.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/cancel_callback.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/seq_state.h
@ -4647,6 +4657,7 @@ libs:
- src/core/lib/promise/seq.h
- src/core/lib/promise/status_flag.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/endpoint_addresses.h
- src/core/lib/resolver/resolver.h
@ -4716,6 +4727,7 @@ libs:
- src/core/lib/surface/lame_client.h
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/surface/wait_for_cq_end_op.h
- src/core/lib/transport/batch_builder.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/custom_metadata.h
@ -7638,12 +7650,10 @@ targets:
- src/core/ext/transport/chaotic_good/client_transport.h
- src/core/ext/transport/chaotic_good/frame.h
- src/core/ext/transport/chaotic_good/frame_header.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/event_engine_wakeup_scheduler.h
- src/core/lib/promise/inter_activity_pipe.h
- src/core/lib/promise/join.h
- src/core/lib/promise/mpsc.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/wait_set.h
- src/core/lib/transport/promise_endpoint.h
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h
@ -7668,12 +7678,10 @@ targets:
- src/core/ext/transport/chaotic_good/client_transport.h
- src/core/ext/transport/chaotic_good/frame.h
- src/core/ext/transport/chaotic_good/frame_header.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/event_engine_wakeup_scheduler.h
- src/core/lib/promise/inter_activity_pipe.h
- src/core/lib/promise/join.h
- src/core/lib/promise/mpsc.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/wait_set.h
- src/core/lib/transport/promise_endpoint.h
- test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h
@ -12921,7 +12929,6 @@ targets:
build: test
language: c++
headers:
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/join.h
- test/core/promise/test_wakeup_schedulers.h
src:
@ -13122,7 +13129,6 @@ targets:
build: test
language: c++
headers:
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/join.h
- src/core/lib/transport/promise_endpoint.h
- test/core/promise/test_wakeup_schedulers.h
@ -16126,8 +16132,8 @@ targets:
- test/core/promise/status_flag_test.cc
deps:
- gtest
- absl/status:status
- absl/status:statusor
- gpr
uses_polling: false
- name: status_helper_test
gtest: true
@ -17004,10 +17010,12 @@ targets:
- src/core/lib/load_balancing/lb_policy_registry.h
- src/core/lib/load_balancing/subchannel_interface.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/all_ok.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/cancel_callback.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/seq_state.h
@ -17027,6 +17035,7 @@ targets:
- src/core/lib/promise/seq.h
- src/core/lib/promise/status_flag.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/endpoint_addresses.h
- src/core/lib/resolver/resolver.h
@ -17071,6 +17080,7 @@ targets:
- src/core/lib/surface/lame_client.h
- src/core/lib/surface/server.h
- src/core/lib/surface/validate_metadata.h
- src/core/lib/surface/wait_for_cq_end_op.h
- src/core/lib/transport/batch_builder.h
- src/core/lib/transport/connectivity_state.h
- src/core/lib/transport/custom_metadata.h
@ -18003,8 +18013,10 @@ targets:
- src/core/lib/gprpp/bitset.h
- src/core/lib/promise/detail/join_state.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/map.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/status_flag.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
src:
@ -18041,6 +18053,7 @@ targets:
- src/core/lib/promise/detail/seq_state.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/status_flag.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_seq.h
src:

8
gRPC-C++.podspec generated

@ -1128,10 +1128,12 @@ Pod::Spec.new do |s|
'src/core/lib/load_balancing/subchannel_interface.h',
'src/core/lib/matchers/matchers.h',
'src/core/lib/promise/activity.h',
'src/core/lib/promise/all_ok.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/cancel_callback.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/join_state.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/seq_state.h',
@ -1153,6 +1155,7 @@ Pod::Spec.new do |s|
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/status_flag.h',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/endpoint_addresses.h',
'src/core/lib/resolver/resolver.h',
@ -1251,6 +1254,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/lame_client.h',
'src/core/lib/surface/server.h',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/surface/wait_for_cq_end_op.h',
'src/core/lib/transport/batch_builder.h',
'src/core/lib/transport/bdp_estimator.h',
'src/core/lib/transport/connectivity_state.h',
@ -2364,10 +2368,12 @@ Pod::Spec.new do |s|
'src/core/lib/load_balancing/subchannel_interface.h',
'src/core/lib/matchers/matchers.h',
'src/core/lib/promise/activity.h',
'src/core/lib/promise/all_ok.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/cancel_callback.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/join_state.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/seq_state.h',
@ -2389,6 +2395,7 @@ Pod::Spec.new do |s|
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/status_flag.h',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/endpoint_addresses.h',
'src/core/lib/resolver/resolver.h',
@ -2487,6 +2494,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/lame_client.h',
'src/core/lib/surface/server.h',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/surface/wait_for_cq_end_op.h',
'src/core/lib/transport/batch_builder.h',
'src/core/lib/transport/bdp_estimator.h',
'src/core/lib/transport/connectivity_state.h',

8
gRPC-Core.podspec generated

@ -1737,10 +1737,12 @@ Pod::Spec.new do |s|
'src/core/lib/matchers/matchers.h',
'src/core/lib/promise/activity.cc',
'src/core/lib/promise/activity.h',
'src/core/lib/promise/all_ok.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/cancel_callback.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/join_state.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/seq_state.h',
@ -1765,6 +1767,7 @@ Pod::Spec.new do |s|
'src/core/lib/promise/status_flag.h',
'src/core/lib/promise/trace.cc',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/endpoint_addresses.cc',
'src/core/lib/resolver/endpoint_addresses.h',
@ -1968,6 +1971,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/validate_metadata.cc',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/surface/version.cc',
'src/core/lib/surface/wait_for_cq_end_op.h',
'src/core/lib/transport/batch_builder.cc',
'src/core/lib/transport/batch_builder.h',
'src/core/lib/transport/bdp_estimator.cc',
@ -3130,10 +3134,12 @@ Pod::Spec.new do |s|
'src/core/lib/load_balancing/subchannel_interface.h',
'src/core/lib/matchers/matchers.h',
'src/core/lib/promise/activity.h',
'src/core/lib/promise/all_ok.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/cancel_callback.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/join_state.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/seq_state.h',
@ -3155,6 +3161,7 @@ Pod::Spec.new do |s|
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/status_flag.h',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/endpoint_addresses.h',
'src/core/lib/resolver/resolver.h',
@ -3253,6 +3260,7 @@ Pod::Spec.new do |s|
'src/core/lib/surface/lame_client.h',
'src/core/lib/surface/server.h',
'src/core/lib/surface/validate_metadata.h',
'src/core/lib/surface/wait_for_cq_end_op.h',
'src/core/lib/transport/batch_builder.h',
'src/core/lib/transport/bdp_estimator.h',
'src/core/lib/transport/connectivity_state.h',

4
grpc.gemspec generated

@ -1640,10 +1640,12 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/matchers/matchers.h )
s.files += %w( src/core/lib/promise/activity.cc )
s.files += %w( src/core/lib/promise/activity.h )
s.files += %w( src/core/lib/promise/all_ok.h )
s.files += %w( src/core/lib/promise/arena_promise.h )
s.files += %w( src/core/lib/promise/cancel_callback.h )
s.files += %w( src/core/lib/promise/context.h )
s.files += %w( src/core/lib/promise/detail/basic_seq.h )
s.files += %w( src/core/lib/promise/detail/join_state.h )
s.files += %w( src/core/lib/promise/detail/promise_factory.h )
s.files += %w( src/core/lib/promise/detail/promise_like.h )
s.files += %w( src/core/lib/promise/detail/seq_state.h )
@ -1668,6 +1670,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/promise/status_flag.h )
s.files += %w( src/core/lib/promise/trace.cc )
s.files += %w( src/core/lib/promise/trace.h )
s.files += %w( src/core/lib/promise/try_join.h )
s.files += %w( src/core/lib/promise/try_seq.h )
s.files += %w( src/core/lib/resolver/endpoint_addresses.cc )
s.files += %w( src/core/lib/resolver/endpoint_addresses.h )
@ -1871,6 +1874,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/surface/validate_metadata.cc )
s.files += %w( src/core/lib/surface/validate_metadata.h )
s.files += %w( src/core/lib/surface/version.cc )
s.files += %w( src/core/lib/surface/wait_for_cq_end_op.h )
s.files += %w( src/core/lib/transport/batch_builder.cc )
s.files += %w( src/core/lib/transport/batch_builder.h )
s.files += %w( src/core/lib/transport/bdp_estimator.cc )

4
package.xml generated

@ -1622,10 +1622,12 @@
<file baseinstalldir="/" name="src/core/lib/matchers/matchers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/activity.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/activity.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/all_ok.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/arena_promise.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/cancel_callback.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/basic_seq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/join_state.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/promise_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/promise_like.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/seq_state.h" role="src" />
@ -1650,6 +1652,7 @@
<file baseinstalldir="/" name="src/core/lib/promise/status_flag.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/try_join.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/try_seq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/resolver/endpoint_addresses.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/resolver/endpoint_addresses.h" role="src" />
@ -1853,6 +1856,7 @@
<file baseinstalldir="/" name="src/core/lib/surface/validate_metadata.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/validate_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/version.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/wait_for_cq_end_op.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/batch_builder.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/batch_builder.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/bdp_estimator.cc" role="src" />

@ -439,6 +439,7 @@ grpc_cc_library(
],
deps = [
"promise_status",
"//:gpr",
"//:gpr_platform",
],
)
@ -710,6 +711,7 @@ grpc_cc_library(
"join_state",
"map",
"poll",
"status_flag",
"//:gpr_platform",
],
)
@ -810,6 +812,7 @@ grpc_cc_library(
"promise_like",
"promise_status",
"seq_state",
"status_flag",
"//:debug_location",
"//:gpr_platform",
],

@ -96,7 +96,7 @@ ClientTransport::ClientTransport(
},
// Write buffers to corresponding endpoints concurrently.
[this]() {
return TryJoin(
return TryJoin<absl::StatusOr>(
control_endpoint_->Write(
std::move(control_endpoint_write_buffer_)),
data_endpoint_->Write(std::move(data_endpoint_write_buffer_)));
@ -134,7 +134,7 @@ ClientTransport::ClientTransport(
.value());
// Read header and trailers from control endpoint.
// Read message padding and message from data endpoint.
return TryJoin(
return TryJoin<absl::StatusOr>(
control_endpoint_->Read(frame_header_->GetFrameLength()),
data_endpoint_->Read(frame_header_->message_padding +
frame_header_->message_length));

@ -105,7 +105,7 @@ class ClientTransport {
std::move(pipe_server_frames.sender))));
}
return TrySeq(
TryJoin(
TryJoin<absl::StatusOr>(
// Continuously send client frame with client to server messages.
ForEach(std::move(*call_args.client_to_server_messages),
[stream_id, initial_frame = true,

@ -326,6 +326,11 @@ void grpc_channel_stack::InitClientCallSpine(
grpc_core::CallSpineInterface* call) {
for (size_t i = 0; i < count; i++) {
auto* elem = grpc_channel_stack_element(this, i);
if (elem->filter->init_call == nullptr) {
grpc_core::Crash(
absl::StrCat("Filter '", elem->filter->name,
"' does not support the call-v3 interface"));
}
elem->filter->init_call(elem, call);
}
}
@ -334,6 +339,11 @@ void grpc_channel_stack::InitServerCallSpine(
grpc_core::CallSpineInterface* call) {
for (size_t i = 0; i < count; i++) {
auto* elem = grpc_channel_stack_element(this, count - 1 - i);
if (elem->filter->init_call == nullptr) {
grpc_core::Crash(
absl::StrCat("Filter '", elem->filter->name,
"' does not support the call-v3 interface"));
}
elem->filter->init_call(elem, call);
}
}

@ -873,10 +873,12 @@ grpc_channel_filter MakeConnectedFilter() {
// do this, and I'm not sure what that is yet. This is only "safe"
// because call stacks place no additional data after the last call
// element, and the last call element MUST be the connected channel.
channel_stack->call_stack_size +=
static_cast<channel_data*>(elem->channel_data)
->transport->filter_stack_transport()
->SizeOfStream();
auto* transport =
static_cast<channel_data*>(elem->channel_data)->transport;
if (transport->filter_stack_transport() != nullptr) {
channel_stack->call_stack_size +=
transport->filter_stack_transport()->SizeOfStream();
}
},
connected_channel_destroy_channel_elem,
connected_channel_get_channel_info,
@ -884,13 +886,27 @@ grpc_channel_filter MakeConnectedFilter() {
};
}
ArenaPromise<ServerMetadataHandle> MakeTransportCallPromise(
Transport*, CallArgs, NextPromiseFactory) {
Crash("unimplemented");
ArenaPromise<ServerMetadataHandle> MakeClientTransportCallPromise(
Transport* transport, CallArgs call_args, NextPromiseFactory) {
auto spine = GetContext<CallContext>()->MakeCallSpine(std::move(call_args));
transport->client_transport()->StartCall(CallHandler{spine});
return Map(spine->server_trailing_metadata().receiver.Next(),
[](NextResult<ServerMetadataHandle> r) {
if (r.has_value()) {
auto md = std::move(r.value());
md->Set(GrpcStatusFromWire(), true);
return md;
}
auto m = GetContext<Arena>()->MakePooled<ServerMetadata>(
GetContext<Arena>());
m->Set(GrpcStatusMetadata(), GRPC_STATUS_CANCELLED);
m->Set(GrpcCallWasCancelled(), true);
return m;
});
}
const grpc_channel_filter kPromiseBasedTransportFilter =
MakeConnectedFilter<MakeTransportCallPromise>();
const grpc_channel_filter kClientPromiseBasedTransportFilter =
MakeConnectedFilter<MakeClientTransportCallPromise>();
#ifdef GRPC_EXPERIMENT_IS_INCLUDED_PROMISE_BASED_CLIENT_CALL
const grpc_channel_filter kClientEmulatedFilter =
@ -908,11 +924,37 @@ const grpc_channel_filter kServerEmulatedFilter =
MakeConnectedFilter<nullptr>();
#endif
bool TransportSupportsPromiseBasedCalls(const ChannelArgs& args) {
// noop filter for the v3 stack: placeholder for now because other code requires
// we have a terminator.
// TODO(ctiller): delete when v3 transition is complete.
const grpc_channel_filter kServerPromiseBasedTransportFilter = {
nullptr,
[](grpc_channel_element*, CallArgs, NextPromiseFactory)
-> ArenaPromise<ServerMetadataHandle> { Crash("not implemented"); },
/* init_call: */ [](grpc_channel_element*, CallSpineInterface*) {},
connected_channel_start_transport_op,
0,
nullptr,
set_pollset_or_pollset_set,
nullptr,
sizeof(channel_data),
connected_channel_init_channel_elem,
+[](grpc_channel_stack*, grpc_channel_element*) {},
connected_channel_destroy_channel_elem,
connected_channel_get_channel_info,
"connected",
};
bool TransportSupportsClientPromiseBasedCalls(const ChannelArgs& args) {
auto* transport = args.GetObject<Transport>();
return transport->client_transport() != nullptr;
}
bool TransportSupportsServerPromiseBasedCalls(const ChannelArgs& args) {
auto* transport = args.GetObject<Transport>();
return transport->server_transport() != nullptr;
}
} // namespace
void RegisterConnectedChannel(CoreConfiguration::Builder* builder) {
@ -925,32 +967,33 @@ void RegisterConnectedChannel(CoreConfiguration::Builder* builder) {
// Option 1, and our ideal: the transport supports promise based calls,
// and so we simply use the transport directly.
builder->channel_init()
->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, &kPromiseBasedTransportFilter)
->RegisterFilter(GRPC_CLIENT_SUBCHANNEL,
&kClientPromiseBasedTransportFilter)
.Terminal()
.If(TransportSupportsPromiseBasedCalls);
.If(TransportSupportsClientPromiseBasedCalls);
builder->channel_init()
->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL,
&kPromiseBasedTransportFilter)
&kClientPromiseBasedTransportFilter)
.Terminal()
.If(TransportSupportsPromiseBasedCalls);
.If(TransportSupportsClientPromiseBasedCalls);
builder->channel_init()
->RegisterFilter(GRPC_SERVER_CHANNEL, &kPromiseBasedTransportFilter)
->RegisterFilter(GRPC_SERVER_CHANNEL, &kServerPromiseBasedTransportFilter)
.Terminal()
.If(TransportSupportsPromiseBasedCalls);
.If(TransportSupportsServerPromiseBasedCalls);
// Option 2: the transport does not support promise based calls.
builder->channel_init()
->RegisterFilter(GRPC_CLIENT_SUBCHANNEL, &kClientEmulatedFilter)
.Terminal()
.IfNot(TransportSupportsPromiseBasedCalls);
.IfNot(TransportSupportsClientPromiseBasedCalls);
builder->channel_init()
->RegisterFilter(GRPC_CLIENT_DIRECT_CHANNEL, &kClientEmulatedFilter)
.Terminal()
.IfNot(TransportSupportsPromiseBasedCalls);
.IfNot(TransportSupportsClientPromiseBasedCalls);
builder->channel_init()
->RegisterFilter(GRPC_SERVER_CHANNEL, &kServerEmulatedFilter)
.Terminal()
.IfNot(TransportSupportsPromiseBasedCalls);
.IfNot(TransportSupportsServerPromiseBasedCalls);
}
} // namespace grpc_core

@ -18,6 +18,7 @@
#include <grpc/support/port_platform.h>
#include <memory>
#include <type_traits>
#include <utility>
#include "absl/meta/type_traits.h"

@ -185,6 +185,8 @@ class Latch<void> {
waiter_.Wake();
}
bool is_set() const { return is_set_; }
private:
std::string DebugTag() {
return absl::StrCat(Activity::current()->DebugTag(), " LATCH(void)[0x",

@ -21,6 +21,8 @@
#include "absl/status/statusor.h"
#include "absl/types/optional.h"
#include <grpc/support/log.h>
#include "src/core/lib/promise/detail/status.h"
namespace grpc_core {
@ -41,6 +43,16 @@ struct StatusCastImpl<absl::Status, const Success&> {
static absl::Status Cast(Success) { return absl::OkStatus(); }
};
template <>
struct StatusCastImpl<absl::Status, Failure> {
static absl::Status Cast(Failure) { return absl::CancelledError(); }
};
template <typename T>
struct StatusCastImpl<absl::StatusOr<T>, Failure> {
static absl::StatusOr<T> Cast(Failure) { return absl::CancelledError(); }
};
// A boolean representing whether an operation succeeded (true) or failed
// (false).
class StatusFlag {
@ -91,18 +103,25 @@ class ValueOrFailure {
ValueOrFailure(T value) : value_(std::move(value)) {}
// NOLINTNEXTLINE(google-explicit-constructor)
ValueOrFailure(Failure) {}
// NOLINTNEXTLINE(google-explicit-constructor)
ValueOrFailure(StatusFlag status) { GPR_ASSERT(!status.ok()); }
static ValueOrFailure FromOptional(absl::optional<T> value) {
return ValueOrFailure{std::move(value)};
}
bool ok() const { return value_.has_value(); }
StatusFlag status() const { return StatusFlag(ok()); }
const T& value() const { return value_.value(); }
T& value() { return value_.value(); }
const T& operator*() const { return *value_; }
T& operator*() { return *value_; }
bool operator==(const ValueOrFailure& other) const {
return value_ == other.value_;
}
private:
absl::optional<T> value_;
};
@ -117,13 +136,6 @@ inline T TakeValue(ValueOrFailure<T>&& value) {
return std::move(value.value());
}
template <typename T>
struct StatusCastImpl<absl::Status, ValueOrFailure<T>> {
static absl::Status Cast(const ValueOrFailure<T> flag) {
return flag.ok() ? absl::OkStatus() : absl::CancelledError();
}
};
template <typename T>
struct StatusCastImpl<absl::StatusOr<T>, ValueOrFailure<T>> {
static absl::StatusOr<T> Cast(ValueOrFailure<T> value) {
@ -132,6 +144,29 @@ struct StatusCastImpl<absl::StatusOr<T>, ValueOrFailure<T>> {
}
};
template <typename T>
struct StatusCastImpl<ValueOrFailure<T>, Failure> {
static ValueOrFailure<T> Cast(Failure) {
return ValueOrFailure<T>(Failure{});
}
};
template <typename T>
struct StatusCastImpl<ValueOrFailure<T>, StatusFlag&> {
static ValueOrFailure<T> Cast(StatusFlag f) {
GPR_ASSERT(!f.ok());
return ValueOrFailure<T>(Failure{});
}
};
template <typename T>
struct StatusCastImpl<ValueOrFailure<T>, StatusFlag> {
static ValueOrFailure<T> Cast(StatusFlag f) {
GPR_ASSERT(!f.ok());
return ValueOrFailure<T>(Failure{});
}
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H

@ -27,6 +27,7 @@
#include "src/core/lib/promise/detail/join_state.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/status_flag.h"
namespace grpc_core {
@ -44,48 +45,68 @@ T IntoResult(absl::StatusOr<T>* status) {
inline Empty IntoResult(absl::Status*) { return Empty{}; }
// Traits object to pass to BasicJoin
template <template <typename> class Result>
struct TryJoinTraits {
template <typename T>
using ResultType = absl::StatusOr<absl::remove_reference_t<T>>;
using ResultType = Result<absl::remove_reference_t<T>>;
template <typename T>
static bool IsOk(const absl::StatusOr<T>& x) {
return x.ok();
}
static bool IsOk(const absl::Status& x) { return x.ok(); }
static bool IsOk(StatusFlag x) { return x.ok(); }
template <typename T>
static bool IsOk(const ValueOrFailure<T>& x) {
return x.ok();
}
template <typename T>
static T Unwrapped(absl::StatusOr<T> x) {
return std::move(*x);
}
template <typename T>
static T Unwrapped(ValueOrFailure<T> x) {
return std::move(*x);
}
static Empty Unwrapped(absl::Status) { return Empty{}; }
static Empty Unwrapped(StatusFlag) { return Empty{}; }
template <typename R, typename T>
static R EarlyReturn(absl::StatusOr<T> x) {
return x.status();
}
template <typename R>
static R EarlyReturn(absl::Status x) {
return x;
return StatusCast<R>(std::move(x));
}
template <typename R>
static R EarlyReturn(StatusFlag x) {
return StatusCast<R>(x);
}
template <typename R, typename T>
static R EarlyReturn(const ValueOrFailure<T>& x) {
GPR_ASSERT(!x.ok());
return StatusCast<R>(Failure{});
}
template <typename... A>
static auto FinalReturn(A&&... a) {
return absl::StatusOr<std::tuple<A...>>(
std::make_tuple(std::forward<A>(a)...));
return Result<std::tuple<A...>>(std::make_tuple(std::forward<A>(a)...));
}
};
// Implementation of TryJoin combinator.
template <typename... Promises>
template <template <typename> class R, typename... Promises>
class TryJoin {
public:
explicit TryJoin(Promises... promises) : state_(std::move(promises)...) {}
auto operator()() { return state_.PollOnce(); }
private:
JoinState<TryJoinTraits, Promises...> state_;
JoinState<TryJoinTraits<R>, Promises...> state_;
};
template <template <typename> class R>
struct WrapInStatusOrTuple {
template <typename T>
absl::StatusOr<std::tuple<T>> operator()(absl::StatusOr<T> x) {
R<std::tuple<T>> operator()(R<T> x) {
if (!x.ok()) return x.status();
return std::make_tuple(std::move(*x));
}
@ -96,14 +117,14 @@ struct WrapInStatusOrTuple {
// Run all promises.
// If any fail, cancel the rest and return the failure.
// If all succeed, return Ok(tuple-of-results).
template <typename... Promises>
promise_detail::TryJoin<Promises...> TryJoin(Promises... promises) {
return promise_detail::TryJoin<Promises...>(std::move(promises)...);
template <template <typename> class R, typename... Promises>
promise_detail::TryJoin<R, Promises...> TryJoin(Promises... promises) {
return promise_detail::TryJoin<R, Promises...>(std::move(promises)...);
}
template <typename F>
template <template <typename> class R, typename F>
auto TryJoin(F promise) {
return Map(promise, promise_detail::WrapInStatusOrTuple{});
return Map(promise, promise_detail::WrapInStatusOrTuple<R>{});
}
} // namespace grpc_core

@ -31,6 +31,7 @@
#include "src/core/lib/promise/detail/seq_state.h"
#include "src/core/lib/promise/detail/status.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/status_flag.h"
namespace grpc_core {
@ -89,6 +90,7 @@ struct TrySeqTraitsWithSfinae<absl::StatusOr<T>> {
return run_next(std::move(prior));
}
};
template <typename T, typename AnyType = void>
struct TakeValueExists {
static constexpr bool value = false;
@ -146,7 +148,7 @@ struct TrySeqTraitsWithSfinae<
template <typename R>
static R ReturnValue(T&& status) {
GPR_DEBUG_ASSERT(!IsStatusOk(status));
return StatusCast<R>(std::move(status));
return StatusCast<R>(status.status());
}
template <typename Result, typename RunNext>
static Poll<Result> CheckResultAndRunNext(T prior, RunNext run_next) {

File diff suppressed because it is too large Load Diff

@ -77,34 +77,35 @@ typedef struct grpc_call_create_args {
} grpc_call_create_args;
namespace grpc_core {
class PromiseBasedCall;
class BasicPromiseBasedCall;
class ServerPromiseBasedCall;
class ServerCallContext {
public:
ServerCallContext(ServerPromiseBasedCall* call,
const void* server_stream_data)
: call_(call), server_stream_data_(server_stream_data) {}
ArenaPromise<ServerMetadataHandle> MakeTopOfServerCallPromise(
virtual void PublishInitialMetadata(
ClientMetadataHandle metadata,
grpc_metadata_array* publish_initial_metadata) = 0;
// Construct the top of the server call promise for the v2 filter stack.
// TODO(ctiller): delete when v3 is available.
virtual ArenaPromise<ServerMetadataHandle> MakeTopOfServerCallPromise(
CallArgs call_args, grpc_completion_queue* cq,
grpc_metadata_array* publish_initial_metadata,
absl::FunctionRef<void(grpc_call* call)> publish);
absl::FunctionRef<void(grpc_call* call)> publish) = 0;
// Server stream data as supplied by the transport (so we can link the
// transport stream up with the call again).
// TODO(ctiller): legacy API - once we move transports to promises we'll
// create the promise directly and not need to pass around this token.
const void* server_stream_data() { return server_stream_data_; }
virtual const void* server_stream_data() = 0;
private:
ServerPromiseBasedCall* const call_;
const void* const server_stream_data_;
protected:
~ServerCallContext() = default;
};
// TODO(ctiller): move more call things into this type
class CallContext {
public:
explicit CallContext(PromiseBasedCall* call) : call_(call) {}
explicit CallContext(BasicPromiseBasedCall* call) : call_(call) {}
// Update the deadline (if deadline < the current deadline).
void UpdateDeadline(Timestamp deadline);
@ -135,13 +136,21 @@ class CallContext {
void set_traced(bool traced) { traced_ = traced; }
bool traced() const { return traced_; }
// TEMPORARY HACK
// Create a call spine object for this call.
// Said object should only be created once.
// Allows interop between the v2 call stack and the v3 (which is required by
// transports).
RefCountedPtr<CallSpineInterface> MakeCallSpine(CallArgs call_args);
grpc_call* c_call();
private:
friend class PromiseBasedCall;
// Call final info.
grpc_call_stats call_stats_;
// TODO(ctiller): remove this once transport APIs are promise based and we
// don't need refcounting here.
PromiseBasedCall* const call_;
BasicPromiseBasedCall* const call_;
gpr_cycle_counter start_time_ = gpr_get_cycle_counter();
// Is this call traced?
bool traced_ = false;
@ -150,6 +159,9 @@ class CallContext {
template <>
struct ContextType<CallContext> {};
RefCountedPtr<CallSpineInterface> MakeServerCall(Server* server,
Channel* channel);
} // namespace grpc_core
// Create a new call based on \a args.

@ -67,6 +67,7 @@
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/try_join.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/slice/slice_internal.h"
@ -75,6 +76,7 @@
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/wait_for_cq_end_op.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/error_utils.h"
@ -82,57 +84,6 @@ namespace grpc_core {
TraceFlag grpc_server_channel_trace(false, "server_channel");
//
// Server::RequestedCall
//
struct Server::RequestedCall {
enum class Type { BATCH_CALL, REGISTERED_CALL };
RequestedCall(void* tag_arg, grpc_completion_queue* call_cq,
grpc_call** call_arg, grpc_metadata_array* initial_md,
grpc_call_details* details)
: type(Type::BATCH_CALL),
tag(tag_arg),
cq_bound_to_call(call_cq),
call(call_arg),
initial_metadata(initial_md) {
data.batch.details = details;
}
RequestedCall(void* tag_arg, grpc_completion_queue* call_cq,
grpc_call** call_arg, grpc_metadata_array* initial_md,
RegisteredMethod* rm, gpr_timespec* deadline,
grpc_byte_buffer** optional_payload)
: type(Type::REGISTERED_CALL),
tag(tag_arg),
cq_bound_to_call(call_cq),
call(call_arg),
initial_metadata(initial_md) {
data.registered.method = rm;
data.registered.deadline = deadline;
data.registered.optional_payload = optional_payload;
}
MultiProducerSingleConsumerQueue::Node mpscq_node;
const Type type;
void* const tag;
grpc_completion_queue* const cq_bound_to_call;
grpc_call** const call;
grpc_cq_completion completion;
grpc_metadata_array* const initial_metadata;
union {
struct {
grpc_call_details* details;
} batch;
struct {
RegisteredMethod* method;
gpr_timespec* deadline;
grpc_byte_buffer** optional_payload;
} registered;
} data;
};
//
// Server::RegisteredMethod
//
@ -248,6 +199,87 @@ class Server::RequestMatcherInterface {
virtual Server* server() const = 0;
};
//
// Server::RequestedCall
//
struct Server::RequestedCall {
enum class Type { BATCH_CALL, REGISTERED_CALL };
RequestedCall(void* tag_arg, grpc_completion_queue* call_cq,
grpc_call** call_arg, grpc_metadata_array* initial_md,
grpc_call_details* details)
: type(Type::BATCH_CALL),
tag(tag_arg),
cq_bound_to_call(call_cq),
call(call_arg),
initial_metadata(initial_md) {
data.batch.details = details;
}
RequestedCall(void* tag_arg, grpc_completion_queue* call_cq,
grpc_call** call_arg, grpc_metadata_array* initial_md,
RegisteredMethod* rm, gpr_timespec* deadline,
grpc_byte_buffer** optional_payload)
: type(Type::REGISTERED_CALL),
tag(tag_arg),
cq_bound_to_call(call_cq),
call(call_arg),
initial_metadata(initial_md) {
data.registered.method = rm;
data.registered.deadline = deadline;
data.registered.optional_payload = optional_payload;
}
void Complete(NextResult<MessageHandle> payload, ClientMetadata& md) {
Timestamp deadline = GetContext<CallContext>()->deadline();
switch (type) {
case RequestedCall::Type::BATCH_CALL:
GPR_ASSERT(!payload.has_value());
data.batch.details->host =
CSliceRef(md.get_pointer(HttpAuthorityMetadata())->c_slice());
data.batch.details->method =
CSliceRef(md.Take(HttpPathMetadata())->c_slice());
data.batch.details->deadline =
deadline.as_timespec(GPR_CLOCK_MONOTONIC);
break;
case RequestedCall::Type::REGISTERED_CALL:
md.Remove(HttpPathMetadata());
*data.registered.deadline = deadline.as_timespec(GPR_CLOCK_MONOTONIC);
if (data.registered.optional_payload != nullptr) {
if (payload.has_value()) {
auto* sb = payload.value()->payload()->c_slice_buffer();
*data.registered.optional_payload =
grpc_raw_byte_buffer_create(sb->slices, sb->count);
} else {
*data.registered.optional_payload = nullptr;
}
}
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
}
MultiProducerSingleConsumerQueue::Node mpscq_node;
const Type type;
void* const tag;
grpc_completion_queue* const cq_bound_to_call;
grpc_call** const call;
grpc_cq_completion completion;
grpc_metadata_array* const initial_metadata;
union {
struct {
grpc_call_details* details;
} batch;
struct {
RegisteredMethod* method;
gpr_timespec* deadline;
grpc_byte_buffer** optional_payload;
} registered;
} data;
};
// The RealRequestMatcher is an implementation of RequestMatcherInterface that
// actually uses all the features of RequestMatcherInterface: expecting the
// application to explicitly request RPCs and then matching those to incoming
@ -757,7 +789,9 @@ class ChannelBroadcaster {
const grpc_channel_filter Server::kServerTopFilter = {
Server::CallData::StartTransportStreamOpBatch,
Server::ChannelData::MakeCallPromise,
/* init_call: */ nullptr,
[](grpc_channel_element*, CallSpineInterface*) {
// TODO(ctiller): remove the server filter when call-v3 is finalized
},
grpc_channel_next_op,
sizeof(Server::CallData),
Server::CallData::InitCallElement,
@ -1275,16 +1309,31 @@ void Server::ChannelData::InitTransport(RefCountedPtr<Server> server,
}
// Start accept_stream transport op.
grpc_transport_op* op = grpc_make_transport_op(nullptr);
op->set_accept_stream = true;
op->set_accept_stream_fn = AcceptStream;
if (IsRegisteredMethodLookupInTransportEnabled()) {
op->set_registered_method_matcher_fn = [](void* arg,
ClientMetadata* metadata) {
static_cast<ChannelData*>(arg)->SetRegisteredMethodOnMetadata(*metadata);
};
}
// op->set_registered_method_matcher_fn = Registered
op->set_accept_stream_user_data = this;
int accept_stream_types = 0;
if (transport->filter_stack_transport() != nullptr) {
++accept_stream_types;
op->set_accept_stream = true;
op->set_accept_stream_fn = AcceptStream;
if (IsRegisteredMethodLookupInTransportEnabled()) {
op->set_registered_method_matcher_fn = [](void* arg,
ClientMetadata* metadata) {
static_cast<ChannelData*>(arg)->SetRegisteredMethodOnMetadata(
*metadata);
};
}
op->set_accept_stream_user_data = this;
}
if (transport->server_transport() != nullptr) {
++accept_stream_types;
transport->server_transport()->SetAcceptFunction(
[this](ClientMetadata& metadata) {
SetRegisteredMethodOnMetadata(metadata);
auto call = MakeServerCall(server_.get(), channel_.get());
InitCall(call);
return CallInitiator(std::move(call));
});
}
GPR_ASSERT(accept_stream_types == 1);
op->start_connectivity_watch = MakeOrphanable<ConnectivityWatcher>(this);
if (server_->ShutdownCalled()) {
op->disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown");
@ -1368,17 +1417,89 @@ auto CancelledDueToServerShutdown() {
}
} // namespace
void Server::ChannelData::InitCall(RefCountedPtr<CallSpineInterface> call) {
call->SpawnGuarded("request_matcher", [this, call]() {
return TrySeq(
// Wait for initial metadata to pass through all filters
Map(call->client_initial_metadata().receiver.Next(),
[](NextResult<ClientMetadataHandle> md)
-> absl::StatusOr<ClientMetadataHandle> {
if (!md.has_value()) {
return absl::InternalError("Missing metadata");
}
if (!md.value()->get_pointer(HttpPathMetadata())) {
return absl::InternalError("Missing :path header");
}
if (!md.value()->get_pointer(HttpAuthorityMetadata())) {
return absl::InternalError("Missing :authority header");
}
return std::move(*md);
}),
// Match request with requested call
[this, call](ClientMetadataHandle md) {
auto* registered_method = static_cast<RegisteredMethod*>(
md->get(GrpcRegisteredMethod()).value_or(nullptr));
RequestMatcherInterface* rm;
grpc_server_register_method_payload_handling payload_handling =
GRPC_SRM_PAYLOAD_NONE;
if (registered_method == nullptr) {
rm = server_->unregistered_request_matcher_.get();
} else {
rm = registered_method->matcher.get();
}
auto maybe_read_first_message = If(
payload_handling == GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER,
[call]() {
return call->client_to_server_messages().receiver.Next();
},
[]() -> NextResult<MessageHandle> {
return NextResult<MessageHandle>();
});
return TryJoin<absl::StatusOr>(
Map(std::move(maybe_read_first_message),
[](NextResult<MessageHandle> n) {
return ValueOrFailure<NextResult<MessageHandle>>{
std::move(n)};
}),
rm->MatchRequest(cq_idx()), [md = std::move(md)]() mutable {
return ValueOrFailure<ClientMetadataHandle>(std::move(md));
});
},
// Publish call to cq
[](std::tuple<NextResult<MessageHandle>,
RequestMatcherInterface::MatchResult,
ClientMetadataHandle>
r) {
RequestMatcherInterface::MatchResult& mr = std::get<1>(r);
auto md = std::move(std::get<2>(r));
auto* rc = mr.TakeCall();
rc->Complete(std::move(std::get<0>(r)), *md);
auto* call_context = GetContext<CallContext>();
*rc->call = call_context->c_call();
grpc_call_set_completion_queue(call_context->c_call(),
rc->cq_bound_to_call);
call_context->server_call_context()->PublishInitialMetadata(
std::move(md), rc->initial_metadata);
// TODO(ctiller): publish metadata
return Map(WaitForCqEndOp(false, rc->tag, absl::OkStatus(), mr.cq()),
[rc = std::unique_ptr<RequestedCall>(rc)](Empty) {
return absl::OkStatus();
});
});
});
}
ArenaPromise<ServerMetadataHandle> Server::ChannelData::MakeCallPromise(
grpc_channel_element* elem, CallArgs call_args, NextPromiseFactory) {
auto* chand = static_cast<Server::ChannelData*>(elem->channel_data);
auto* server = chand->server_.get();
absl::optional<Slice> path =
call_args.client_initial_metadata->Take(HttpPathMetadata());
if (server->ShutdownCalled()) return CancelledDueToServerShutdown();
auto cleanup_ref =
absl::MakeCleanup([server] { server->ShutdownUnrefOnRequest(); });
if (!server->ShutdownRefOnRequest()) return CancelledDueToServerShutdown();
if (!path.has_value()) {
auto path_ptr =
call_args.client_initial_metadata->get_pointer(HttpPathMetadata());
if (path_ptr == nullptr) {
return [] {
return ServerMetadataFromStatus(
absl::InternalError("Missing :path header"));
@ -1392,7 +1513,6 @@ ArenaPromise<ServerMetadataHandle> Server::ChannelData::MakeCallPromise(
absl::InternalError("Missing :authority header"));
};
}
Timestamp deadline = GetContext<CallContext>()->deadline();
// Find request matcher.
RequestMatcherInterface* matcher;
RegisteredMethod* rm = nullptr;
@ -1402,7 +1522,7 @@ ArenaPromise<ServerMetadataHandle> Server::ChannelData::MakeCallPromise(
.value_or(nullptr));
} else {
rm = chand->GetRegisteredMethod(host_ptr->as_string_view(),
path->as_string_view());
path_ptr->as_string_view());
}
ArenaPromise<absl::StatusOr<NextResult<MessageHandle>>>
maybe_read_first_message([] { return NextResult<MessageHandle>(); });
@ -1439,8 +1559,7 @@ ArenaPromise<ServerMetadataHandle> Server::ChannelData::MakeCallPromise(
return std::make_pair(std::move(*mr), std::move(payload));
});
},
[host_ptr, path = std::move(path), deadline,
call_args =
[call_args =
std::move(call_args)](std::pair<RequestMatcherInterface::MatchResult,
NextResult<MessageHandle>>
r) mutable {
@ -1448,41 +1567,19 @@ ArenaPromise<ServerMetadataHandle> Server::ChannelData::MakeCallPromise(
auto& payload = r.second;
auto* rc = mr.TakeCall();
auto* cq_for_new_request = mr.cq();
switch (rc->type) {
case RequestedCall::Type::BATCH_CALL:
GPR_ASSERT(!payload.has_value());
rc->data.batch.details->host = CSliceRef(host_ptr->c_slice());
rc->data.batch.details->method = CSliceRef(path->c_slice());
rc->data.batch.details->deadline =
deadline.as_timespec(GPR_CLOCK_MONOTONIC);
break;
case RequestedCall::Type::REGISTERED_CALL:
*rc->data.registered.deadline =
deadline.as_timespec(GPR_CLOCK_MONOTONIC);
if (rc->data.registered.optional_payload != nullptr) {
if (payload.has_value()) {
auto* sb = payload.value()->payload()->c_slice_buffer();
*rc->data.registered.optional_payload =
grpc_raw_byte_buffer_create(sb->slices, sb->count);
} else {
*rc->data.registered.optional_payload = nullptr;
}
}
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
return GetContext<CallContext>()
->server_call_context()
->MakeTopOfServerCallPromise(
std::move(call_args), rc->cq_bound_to_call,
rc->initial_metadata,
[rc, cq_for_new_request](grpc_call* call) {
*rc->call = call;
grpc_cq_end_op(cq_for_new_request, rc->tag, absl::OkStatus(),
Server::DoneRequestEvent, rc, &rc->completion,
true);
});
auto* server_call_context =
GetContext<CallContext>()->server_call_context();
rc->Complete(std::move(payload), *call_args.client_initial_metadata);
server_call_context->PublishInitialMetadata(
std::move(call_args.client_initial_metadata), rc->initial_metadata);
return server_call_context->MakeTopOfServerCallPromise(
std::move(call_args), rc->cq_bound_to_call,
[rc, cq_for_new_request](grpc_call* call) {
*rc->call = call;
grpc_cq_end_op(cq_for_new_request, rc->tag, absl::OkStatus(),
Server::DoneRequestEvent, rc, &rc->completion,
true);
});
});
}

@ -239,6 +239,7 @@ class Server : public InternallyRefCounted<Server>,
static void DestroyChannelElement(grpc_channel_element* elem);
static ArenaPromise<ServerMetadataHandle> MakeCallPromise(
grpc_channel_element* elem, CallArgs call_args, NextPromiseFactory);
void InitCall(RefCountedPtr<CallSpineInterface> call);
private:
class ConnectivityWatcher;

@ -0,0 +1,94 @@
// 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_SURFACE_WAIT_FOR_CQ_END_OP_H
#define GRPC_SRC_CORE_LIB_SURFACE_WAIT_FOR_CQ_END_OP_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/surface/completion_queue.h"
namespace grpc_core {
// Defines a promise that calls grpc_cq_end_op() (on first poll) and then waits
// for the callback supplied to grpc_cq_end_op() to be called, before resolving
// to Empty{}
class WaitForCqEndOp {
public:
WaitForCqEndOp(bool is_closure, void* tag, grpc_error_handle error,
grpc_completion_queue* cq)
: state_{NotStarted{is_closure, tag, std::move(error), cq}} {}
Poll<Empty> operator()() {
if (auto* n = absl::get_if<NotStarted>(&state_)) {
if (n->is_closure) {
ExecCtx::Run(DEBUG_LOCATION, static_cast<grpc_closure*>(n->tag),
std::move(n->error));
return Empty{};
} else {
auto not_started = std::move(*n);
auto& started =
state_.emplace<Started>(Activity::current()->MakeOwningWaker());
grpc_cq_end_op(
not_started.cq, not_started.tag, std::move(not_started.error),
[](void* p, grpc_cq_completion*) {
auto started = static_cast<Started*>(p);
started->done.store(true, std::memory_order_release);
},
&started, &started.completion);
}
}
auto& started = absl::get<Started>(state_);
if (started.done.load(std::memory_order_acquire)) {
return Empty{};
} else {
return Pending{};
}
}
WaitForCqEndOp(const WaitForCqEndOp&) = delete;
WaitForCqEndOp& operator=(const WaitForCqEndOp&) = delete;
WaitForCqEndOp(WaitForCqEndOp&& other) noexcept
: state_(std::move(absl::get<NotStarted>(other.state_))) {
other.state_.emplace<Invalid>();
}
WaitForCqEndOp& operator=(WaitForCqEndOp&& other) noexcept {
state_ = std::move(absl::get<NotStarted>(other.state_));
other.state_.emplace<Invalid>();
return *this;
}
private:
struct NotStarted {
bool is_closure;
void* tag;
grpc_error_handle error;
grpc_completion_queue* cq;
};
struct Started {
explicit Started(Waker waker) : waker(std::move(waker)) {}
Waker waker;
grpc_cq_completion completion;
std::atomic<bool> done{false};
};
struct Invalid {};
using State = absl::variant<NotStarted, Started, Invalid>;
State state_{Invalid{}};
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_SURFACE_WAIT_FOR_CQ_END_OP_H

@ -329,6 +329,8 @@ class CallSpineInterface {
class CallSpine final : public CallSpineInterface {
public:
CallSpine() { Crash("unimplemented"); }
Pipe<ClientMetadataHandle>& client_initial_metadata() override {
return client_initial_metadata_;
}
@ -366,7 +368,7 @@ class CallSpine final : public CallSpineInterface {
class CallInitiator {
public:
explicit CallInitiator(RefCountedPtr<CallSpine> spine)
explicit CallInitiator(RefCountedPtr<CallSpineInterface> spine)
: spine_(std::move(spine)) {}
auto PushClientInitialMetadata(ClientMetadataHandle md) {
@ -427,12 +429,12 @@ class CallInitiator {
}
private:
const RefCountedPtr<CallSpine> spine_;
const RefCountedPtr<CallSpineInterface> spine_;
};
class CallHandler {
public:
explicit CallHandler(RefCountedPtr<CallSpine> spine)
explicit CallHandler(RefCountedPtr<CallSpineInterface> spine)
: spine_(std::move(spine)) {}
auto PullClientInitialMetadata() {
@ -453,7 +455,7 @@ class CallHandler {
auto PushServerTrailingMetadata(ClientMetadataHandle md) {
GPR_DEBUG_ASSERT(Activity::current() == &spine_->party());
return Map(spine_->server_initial_metadata().sender.Push(std::move(md)),
return Map(spine_->server_trailing_metadata().sender.Push(std::move(md)),
[](bool ok) { return StatusFlag(ok); });
}
@ -488,7 +490,7 @@ class CallHandler {
}
private:
const RefCountedPtr<CallSpine> spine_;
const RefCountedPtr<CallSpineInterface> spine_;
};
struct CallInitiatorAndHandler {

@ -28,8 +28,9 @@ TEST(StatusFlagTest, Basics) {
EXPECT_FALSE(StatusCast<absl::Status>(StatusFlag(false)).ok());
EXPECT_TRUE(ValueOrFailure<int>(42).ok());
EXPECT_FALSE(ValueOrFailure<int>(Failure{}).ok());
EXPECT_TRUE(StatusCast<absl::Status>(ValueOrFailure<int>(42)).ok());
EXPECT_FALSE(StatusCast<absl::Status>(ValueOrFailure<int>(Failure{})).ok());
EXPECT_TRUE(StatusCast<absl::Status>(ValueOrFailure<int>(42).status()).ok());
EXPECT_FALSE(
StatusCast<absl::Status>(ValueOrFailure<int>(Failure{}).status()).ok());
EXPECT_EQ(ValueOrFailure<int>(42).value(), 42);
EXPECT_EQ(StatusCast<absl::StatusOr<int>>(ValueOrFailure<int>(42)).value(),
42);

@ -23,64 +23,134 @@
namespace grpc_core {
template <typename T>
using P = std::function<Poll<absl::StatusOr<T>>()>;
struct AbslStatusTraits {
template <typename... Promises>
static auto TryJoinImpl(Promises... promises) {
return TryJoin<absl::StatusOr>(std::move(promises)...);
}
template <typename T>
using Promise = std::function<Poll<absl::StatusOr<T>>()>;
template <typename T>
static Promise<T> instant_ok(T x) {
return [x] { return absl::StatusOr<T>(x); };
}
static auto instant_ok_status() {
return [] { return absl::OkStatus(); };
}
template <typename T>
static Promise<T> instant_fail() {
return [] { return absl::StatusOr<T>(); };
}
template <typename... T>
static Poll<absl::StatusOr<std::tuple<T...>>> ok(T... x) {
return absl::StatusOr<std::tuple<T...>>(absl::in_place, x...);
}
template <typename... T>
static Poll<absl::StatusOr<std::tuple<T...>>> fail() {
return absl::StatusOr<std::tuple<T...>>();
}
template <typename T>
static Promise<T> pending() {
return []() -> Poll<absl::StatusOr<T>> { return Pending(); };
}
};
struct ValueOrFailureTraits {
template <typename... Promises>
static auto TryJoinImpl(Promises... promises) {
return TryJoin<ValueOrFailure>(std::move(promises)...);
}
template <typename T>
using Promise = std::function<Poll<ValueOrFailure<T>>()>;
template <typename T>
static Promise<T> instant_ok(T x) {
return [x] { return ValueOrFailure<T>(x); };
}
static auto instant_ok_status() {
return [] { return StatusFlag(true); };
}
template <typename T>
static Promise<T> instant_fail() {
return [] { return Failure{}; };
}
template <typename... T>
static Poll<ValueOrFailure<std::tuple<T...>>> ok(T... x) {
return ValueOrFailure<std::tuple<T...>>(std::tuple<T...>(x...));
}
template <typename... T>
static Poll<ValueOrFailure<std::tuple<T...>>> fail() {
return Failure{};
}
template <typename T>
static Promise<T> pending() {
return []() -> Poll<ValueOrFailure<T>> { return Pending(); };
}
};
template <typename T>
P<T> instant_ok(T x) {
return [x] { return absl::StatusOr<T>(x); };
}
template <typename T>
P<T> instant_fail() {
return [] { return absl::StatusOr<T>(); };
}
class TryJoinTest : public ::testing::Test {};
template <typename... T>
Poll<absl::StatusOr<std::tuple<T...>>> ok(T... x) {
return absl::StatusOr<std::tuple<T...>>(absl::in_place, x...);
}
using Traits = ::testing::Types<AbslStatusTraits, ValueOrFailureTraits>;
TYPED_TEST_SUITE(TryJoinTest, Traits);
template <typename... T>
Poll<absl::StatusOr<std::tuple<T...>>> fail() {
return absl::StatusOr<std::tuple<T...>>();
TYPED_TEST(TryJoinTest, Join1) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::instant_ok(1))(),
TypeParam::ok(1));
}
template <typename T>
P<T> pending() {
return []() -> Poll<absl::StatusOr<T>> { return Pending(); };
}
TEST(TryJoinTest, Join1) { EXPECT_EQ(TryJoin(instant_ok(1))(), ok(1)); }
TEST(TryJoinTest, Join1Fail) {
EXPECT_EQ(TryJoin(instant_fail<int>())(), fail<int>());
TYPED_TEST(TryJoinTest, Join1Fail) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::template instant_fail<int>())(),
TypeParam::template fail<int>());
}
TEST(TryJoinTest, Join2Success) {
EXPECT_EQ(TryJoin(instant_ok(1), instant_ok(2))(), ok(1, 2));
TYPED_TEST(TryJoinTest, Join2Success) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::instant_ok(1),
TypeParam::instant_ok(2))(),
TypeParam::ok(1, 2));
}
TEST(TryJoinTest, Join2Fail1) {
EXPECT_EQ(TryJoin(instant_ok(1), instant_fail<int>())(), (fail<int, int>()));
TYPED_TEST(TryJoinTest, Join2Fail1) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::instant_ok(1),
TypeParam::template instant_fail<int>())(),
(TypeParam::template fail<int, int>()));
}
TEST(TryJoinTest, Join2Fail2) {
EXPECT_EQ(TryJoin(instant_fail<int>(), instant_ok(2))(), (fail<int, int>()));
TYPED_TEST(TryJoinTest, Join2Fail2) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::template instant_fail<int>(),
TypeParam::instant_ok(2))(),
(TypeParam::template fail<int, int>()));
}
TEST(TryJoinTest, Join2Fail1P) {
EXPECT_EQ(TryJoin(pending<int>(), instant_fail<int>())(), (fail<int, int>()));
TYPED_TEST(TryJoinTest, Join2Fail1P) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::template pending<int>(),
TypeParam::template instant_fail<int>())(),
(TypeParam::template fail<int, int>()));
}
TEST(TryJoinTest, Join2Fail2P) {
EXPECT_EQ(TryJoin(instant_fail<int>(), pending<int>())(), (fail<int, int>()));
TYPED_TEST(TryJoinTest, Join2Fail2P) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::template instant_fail<int>(),
TypeParam::template pending<int>())(),
(TypeParam::template fail<int, int>()));
}
TEST(TryJoinTest, JoinStatus) {
EXPECT_EQ(TryJoin([]() { return absl::OkStatus(); },
[]() { return absl::OkStatus(); })(),
ok(Empty{}, Empty{}));
TYPED_TEST(TryJoinTest, JoinStatus) {
EXPECT_EQ(TypeParam::TryJoinImpl(TypeParam::instant_ok_status(),
TypeParam::instant_ok_status())(),
TypeParam::ok(Empty{}, Empty{}));
}
} // namespace grpc_core

@ -23,53 +23,133 @@
namespace grpc_core {
TEST(TrySeqTest, SucceedAndThen) {
EXPECT_EQ(TrySeq([] { return absl::StatusOr<int>(1); },
[](int i) {
return [i]() { return absl::StatusOr<int>(i + 1); };
})(),
Poll<absl::StatusOr<int>>(absl::StatusOr<int>(2)));
struct AbslStatusTraits {
template <typename T>
using Promise = std::function<Poll<absl::StatusOr<T>>()>;
template <typename T>
static Promise<T> instant_ok(T x) {
return [x] { return absl::StatusOr<T>(x); };
}
static auto instant_ok_status() {
return [] { return absl::OkStatus(); };
}
template <typename T>
static Promise<T> instant_fail() {
return [] { return absl::StatusOr<T>(); };
}
template <typename T>
static Poll<absl::StatusOr<T>> instant_crash() {
abort();
}
template <typename T>
static Poll<absl::StatusOr<T>> ok(T x) {
return absl::StatusOr<T>(x);
}
static Poll<absl::Status> ok_status() { return absl::OkStatus(); }
template <typename T>
static Poll<absl::StatusOr<T>> fail() {
return absl::StatusOr<T>();
}
template <typename T>
static Promise<T> pending() {
return []() -> Poll<absl::StatusOr<T>> { return Pending(); };
}
};
struct ValueOrFailureTraits {
template <typename T>
using Promise = std::function<Poll<ValueOrFailure<T>>()>;
template <typename T>
static Promise<T> instant_ok(T x) {
return [x] { return ValueOrFailure<T>(x); };
}
static auto instant_ok_status() {
return [] { return StatusFlag(true); };
}
template <typename T>
static Promise<T> instant_fail() {
return [] { return Failure{}; };
}
template <typename T>
static Poll<ValueOrFailure<T>> instant_crash() {
abort();
}
template <typename T>
static Poll<ValueOrFailure<T>> ok(T x) {
return ValueOrFailure<T>(x);
}
static Poll<StatusFlag> ok_status() { return Success{}; }
template <typename T>
static Poll<ValueOrFailure<T>> fail() {
return Failure{};
}
template <typename T>
static Promise<T> pending() {
return []() -> Poll<ValueOrFailure<T>> { return Pending(); };
}
};
template <typename T>
class TrySeqTest : public ::testing::Test {};
using Traits = ::testing::Types<AbslStatusTraits, ValueOrFailureTraits>;
TYPED_TEST_SUITE(TrySeqTest, Traits);
TYPED_TEST(TrySeqTest, SucceedAndThen) {
EXPECT_EQ(TrySeq(TypeParam::instant_ok(1),
[](int i) { return TypeParam::instant_ok(i + 1); })(),
TypeParam::ok(2));
}
TEST(TrySeqTest, SucceedDirectlyAndThenDirectly) {
TYPED_TEST(TrySeqTest, SucceedDirectlyAndThenDirectly) {
EXPECT_EQ(
TrySeq([] { return 1; }, [](int i) { return [i]() { return i + 1; }; })(),
Poll<absl::StatusOr<int>>(absl::StatusOr<int>(2)));
Poll<absl::StatusOr<int>>(2));
}
TEST(TrySeqTest, SucceedAndThenChangeType) {
TYPED_TEST(TrySeqTest, SucceedAndThenChangeType) {
EXPECT_EQ(
TrySeq([] { return absl::StatusOr<int>(42); },
[](int i) {
return [i]() {
return absl::StatusOr<std::string>(std::to_string(i));
};
})(),
Poll<absl::StatusOr<std::string>>(absl::StatusOr<std::string>("42")));
TrySeq(TypeParam::instant_ok(42),
[](int i) { return TypeParam::instant_ok(std::to_string(i)); })(),
TypeParam::ok(std::string("42")));
}
TEST(TrySeqTest, FailAndThen) {
EXPECT_EQ(TrySeq([]() { return absl::StatusOr<int>(absl::CancelledError()); },
[](int) {
return []() -> Poll<absl::StatusOr<double>> { abort(); };
})(),
Poll<absl::StatusOr<double>>(
absl::StatusOr<double>(absl::CancelledError())));
TYPED_TEST(TrySeqTest, FailAndThen) {
EXPECT_EQ(
TrySeq(TypeParam::template instant_fail<int>(),
[](int) { return TypeParam::template instant_crash<double>(); })(),
TypeParam::template fail<double>());
}
TEST(TrySeqTest, RawSucceedAndThen) {
EXPECT_EQ(TrySeq([] { return absl::OkStatus(); },
[] { return []() { return absl::OkStatus(); }; })(),
Poll<absl::Status>(absl::OkStatus()));
TYPED_TEST(TrySeqTest, RawSucceedAndThen) {
EXPECT_EQ(TrySeq(TypeParam::instant_ok_status(),
[] { return TypeParam::instant_ok_status(); })(),
TypeParam::ok_status());
}
TEST(TrySeqTest, RawFailAndThen) {
TYPED_TEST(TrySeqTest, RawFailAndThen) {
EXPECT_EQ(TrySeq([] { return absl::CancelledError(); },
[]() { return []() -> Poll<absl::Status> { abort(); }; })(),
Poll<absl::Status>(absl::CancelledError()));
}
TEST(TrySeqTest, RawSucceedAndThenValue) {
TYPED_TEST(TrySeqTest, RawSucceedAndThenValue) {
EXPECT_EQ(TrySeq([] { return absl::OkStatus(); },
[] { return []() { return absl::StatusOr<int>(42); }; })(),
Poll<absl::StatusOr<int>>(absl::StatusOr<int>(42)));

@ -2639,10 +2639,12 @@ src/core/lib/matchers/matchers.cc \
src/core/lib/matchers/matchers.h \
src/core/lib/promise/activity.cc \
src/core/lib/promise/activity.h \
src/core/lib/promise/all_ok.h \
src/core/lib/promise/arena_promise.h \
src/core/lib/promise/cancel_callback.h \
src/core/lib/promise/context.h \
src/core/lib/promise/detail/basic_seq.h \
src/core/lib/promise/detail/join_state.h \
src/core/lib/promise/detail/promise_factory.h \
src/core/lib/promise/detail/promise_like.h \
src/core/lib/promise/detail/seq_state.h \
@ -2667,6 +2669,7 @@ src/core/lib/promise/sleep.h \
src/core/lib/promise/status_flag.h \
src/core/lib/promise/trace.cc \
src/core/lib/promise/trace.h \
src/core/lib/promise/try_join.h \
src/core/lib/promise/try_seq.h \
src/core/lib/resolver/endpoint_addresses.cc \
src/core/lib/resolver/endpoint_addresses.h \
@ -2870,6 +2873,7 @@ src/core/lib/surface/server.h \
src/core/lib/surface/validate_metadata.cc \
src/core/lib/surface/validate_metadata.h \
src/core/lib/surface/version.cc \
src/core/lib/surface/wait_for_cq_end_op.h \
src/core/lib/transport/batch_builder.cc \
src/core/lib/transport/batch_builder.h \
src/core/lib/transport/bdp_estimator.cc \

@ -2418,10 +2418,12 @@ src/core/lib/matchers/matchers.cc \
src/core/lib/matchers/matchers.h \
src/core/lib/promise/activity.cc \
src/core/lib/promise/activity.h \
src/core/lib/promise/all_ok.h \
src/core/lib/promise/arena_promise.h \
src/core/lib/promise/cancel_callback.h \
src/core/lib/promise/context.h \
src/core/lib/promise/detail/basic_seq.h \
src/core/lib/promise/detail/join_state.h \
src/core/lib/promise/detail/promise_factory.h \
src/core/lib/promise/detail/promise_like.h \
src/core/lib/promise/detail/seq_state.h \
@ -2446,6 +2448,7 @@ src/core/lib/promise/sleep.h \
src/core/lib/promise/status_flag.h \
src/core/lib/promise/trace.cc \
src/core/lib/promise/trace.h \
src/core/lib/promise/try_join.h \
src/core/lib/promise/try_seq.h \
src/core/lib/resolver/endpoint_addresses.cc \
src/core/lib/resolver/endpoint_addresses.h \
@ -2650,6 +2653,7 @@ src/core/lib/surface/server.h \
src/core/lib/surface/validate_metadata.cc \
src/core/lib/surface/validate_metadata.h \
src/core/lib/surface/version.cc \
src/core/lib/surface/wait_for_cq_end_op.h \
src/core/lib/transport/README.md \
src/core/lib/transport/batch_builder.cc \
src/core/lib/transport/batch_builder.h \

Loading…
Cancel
Save