[promises] Add some status-like types for TrySeq (#34906)

`StatusFlag` acts like a status, but is just a boolean (we don't want to
accidentally treat a boolean as something that indicates failure in case
it's not)

Similarly `ValueOrFailure` looks like `StatusOr` but reduces the failure
space to one value.

---------

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/34918/head
Craig Tiller 1 year ago committed by GitHub
parent b99d63f423
commit dc41f42073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      CMakeLists.txt
  2. 14
      build_autogenerated.yaml
  3. 121
      src/core/BUILD
  4. 95
      src/core/lib/promise/status_flag.h
  5. 11
      test/core/promise/BUILD
  6. 43
      test/core/promise/status_flag_test.cc
  7. 24
      tools/run_tests/generated/tests.json

35
CMakeLists.txt generated

@ -1355,6 +1355,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx static_stride_scheduler_test)
add_dependencies(buildtests_cxx stats_test)
add_dependencies(buildtests_cxx status_conversion_test)
add_dependencies(buildtests_cxx status_flag_test)
add_dependencies(buildtests_cxx status_helper_test)
add_dependencies(buildtests_cxx status_util_test)
add_dependencies(buildtests_cxx stream_leak_with_queued_flow_control_update_test)
@ -23267,6 +23268,40 @@ target_link_libraries(status_conversion_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(status_flag_test
test/core/promise/status_flag_test.cc
)
target_compile_features(status_flag_test PUBLIC cxx_std_14)
target_include_directories(status_flag_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(status_flag_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::status
absl::statusor
)
endif()
if(gRPC_BUILD_TESTS)

@ -16013,6 +16013,20 @@ targets:
- gtest
- grpc_test_util
uses_polling: false
- name: status_flag_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/status_flag.h
src:
- test/core/promise/status_flag_test.cc
deps:
- gtest
- absl/status:status
- absl/status:statusor
uses_polling: false
- name: status_helper_test
gtest: true
build: test

@ -117,10 +117,12 @@ grpc_cc_library(
"lib/experiments/config.h",
"lib/experiments/experiments.h",
],
defines = select({
"//:grpc_experiments_are_final": ["GRPC_EXPERIMENTS_ARE_FINAL"],
"//conditions:default": [],
}),
defines = select(
{
"//:grpc_experiments_are_final": ["GRPC_EXPERIMENTS_ARE_FINAL"],
"//conditions:default": [],
},
),
external_deps = [
"absl/functional:any_invocable",
"absl/strings",
@ -420,6 +422,23 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "status_flag",
external_deps = [
"absl/status",
"absl/status:statusor",
"absl/types:optional",
],
language = "c++",
public_hdrs = [
"lib/promise/status_flag.h",
],
deps = [
"promise_status",
"//:gpr_platform",
],
)
grpc_cc_library(
name = "map_pipe",
external_deps = ["absl/status"],
@ -2329,27 +2348,29 @@ grpc_cc_library(
srcs = ["lib/event_engine/default_event_engine_factory.cc"],
hdrs = ["lib/event_engine/default_event_engine_factory.h"],
external_deps = ["absl/memory"],
select_deps = [{
"//:windows": ["windows_event_engine"],
"//:windows_msvc": ["windows_event_engine"],
"//:windows_other": ["windows_event_engine"],
"//:mac": [
"posix_event_engine",
"cf_event_engine",
],
"//:mac_x86_64": [
"posix_event_engine",
"cf_event_engine",
],
"//:mac_arm64": [
"posix_event_engine",
"cf_event_engine",
],
"//:ios": ["cf_event_engine"],
"//:tvos": ["cf_event_engine"],
"//:watchos": ["cf_event_engine"],
"//conditions:default": ["posix_event_engine"],
}],
select_deps = [
{
"//:windows": ["windows_event_engine"],
"//:windows_msvc": ["windows_event_engine"],
"//:windows_other": ["windows_event_engine"],
"//:mac": [
"posix_event_engine",
"cf_event_engine",
],
"//:mac_x86_64": [
"posix_event_engine",
"cf_event_engine",
],
"//:mac_arm64": [
"posix_event_engine",
"cf_event_engine",
],
"//:ios": ["cf_event_engine"],
"//:tvos": ["cf_event_engine"],
"//:watchos": ["cf_event_engine"],
"//conditions:default": ["posix_event_engine"],
},
],
deps = [
"//:event_engine_base_hdrs",
"//:gpr_platform",
@ -5447,8 +5468,12 @@ grpc_cc_library(
grpc_cc_library(
name = "service_config_helper",
srcs = ["ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc"],
hdrs = ["ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h"],
srcs = [
"ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.cc",
],
hdrs = [
"ext/filters/client_channel/resolver/dns/event_engine/service_config_helper.h",
],
external_deps = [
"absl/status:statusor",
"absl/strings",
@ -5468,8 +5493,12 @@ grpc_cc_library(
grpc_cc_library(
name = "grpc_resolver_dns_event_engine",
srcs = ["ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc"],
hdrs = ["ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h"],
srcs = [
"ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.cc",
],
hdrs = [
"ext/filters/client_channel/resolver/dns/event_engine/event_engine_client_channel_resolver.h",
],
external_deps = [
"absl/base:core_headers",
"absl/cleanup",
@ -6411,7 +6440,9 @@ grpc_upb_proto_library(
grpc_upb_proto_library(
name = "envoy_extensions_load_balancing_policies_client_side_weighted_round_robin_upb",
deps = ["@envoy_api//envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3:pkg"],
deps = [
"@envoy_api//envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3:pkg",
],
)
grpc_upb_proto_library(
@ -6431,12 +6462,16 @@ grpc_upb_proto_library(
grpc_upb_proto_library(
name = "envoy_extensions_filters_network_http_connection_manager_upb",
deps = ["@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg"],
deps = [
"@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg",
],
)
grpc_upb_proto_reflection_library(
name = "envoy_extensions_filters_network_http_connection_manager_upbdefs",
deps = ["@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg"],
deps = [
"@envoy_api//envoy/extensions/filters/network/http_connection_manager/v3:pkg",
],
)
grpc_upb_proto_library(
@ -6563,14 +6598,20 @@ WELL_KNOWN_PROTO_TARGETS = [
"wrappers",
]
[grpc_upb_proto_library(
name = "protobuf_" + target + "_upb",
deps = ["@com_google_protobuf//:" + target + "_proto"],
) for target in WELL_KNOWN_PROTO_TARGETS]
[
grpc_upb_proto_library(
name = "protobuf_" + target + "_upb",
deps = ["@com_google_protobuf//:" + target + "_proto"],
)
for target in WELL_KNOWN_PROTO_TARGETS
]
[grpc_upb_proto_reflection_library(
name = "protobuf_" + target + "_upbdefs",
deps = ["@com_google_protobuf//:" + target + "_proto"],
) for target in WELL_KNOWN_PROTO_TARGETS]
[
grpc_upb_proto_reflection_library(
name = "protobuf_" + target + "_upbdefs",
deps = ["@com_google_protobuf//:" + target + "_proto"],
)
for target in WELL_KNOWN_PROTO_TARGETS
]
grpc_generate_one_off_internal_targets()

@ -0,0 +1,95 @@
// 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_STATUS_FLAG_H
#define GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H
#include <grpc/support/port_platform.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/types/optional.h"
#include "src/core/lib/promise/detail/status.h"
namespace grpc_core {
// A boolean representing whether an operation succeeded (true) or failed
// (false).
class StatusFlag {
public:
explicit StatusFlag(bool value) : value_(value) {}
bool ok() const { return value_; }
private:
bool value_;
};
inline bool IsStatusOk(const StatusFlag& flag) { return flag.ok(); }
template <>
struct StatusCastImpl<absl::Status, StatusFlag> {
static absl::Status Cast(StatusFlag flag) {
return flag.ok() ? absl::OkStatus() : absl::CancelledError();
}
};
struct Failure {};
// A value if an operation was successful, or a failure flag if not.
template <typename T>
class ValueOrFailure {
public:
explicit ValueOrFailure(T value) : value_(std::move(value)) {}
explicit ValueOrFailure(Failure) {}
static ValueOrFailure FromOptional(absl::optional<T> value) {
return ValueOrFailure{std::move(value)};
}
bool ok() const { return value_.has_value(); }
const T& value() const { return value_.value(); }
T& value() { return value_.value(); }
const T& operator*() const { return *value_; }
T& operator*() { return *value_; }
private:
absl::optional<T> value_;
};
template <typename T>
inline bool IsStatusOk(const ValueOrFailure<T>& value) {
return value.ok();
}
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) {
return value.ok() ? absl::StatusOr<T>(std::move(value.value()))
: absl::CancelledError();
}
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H

@ -543,6 +543,17 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "status_flag_test",
srcs = ["status_flag_test.cc"],
external_deps = ["gtest"],
language = "c++",
tags = ["promise_test"],
uses_event_engine = False,
uses_polling = False,
deps = ["//src/core:status_flag"],
)
grpc_cc_test(
name = "promise_mutex_test",
srcs = ["promise_mutex_test.cc"],

@ -0,0 +1,43 @@
// 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/status_flag.h"
#include <memory>
#include <utility>
#include "gtest/gtest.h"
namespace grpc_core {
TEST(StatusFlagTest, Basics) {
EXPECT_TRUE(StatusFlag(true).ok());
EXPECT_FALSE(StatusFlag(false).ok());
EXPECT_TRUE(StatusCast<absl::Status>(StatusFlag(true)).ok());
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_EQ(ValueOrFailure<int>(42).value(), 42);
EXPECT_EQ(StatusCast<absl::StatusOr<int>>(ValueOrFailure<int>(42)).value(),
42);
}
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -9619,6 +9619,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": "status_flag_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save