// 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 #include "absl/log/check.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/types/optional.h" #include #include #include "src/core/lib/promise/detail/status.h" namespace grpc_core { struct Failure { template friend void AbslStringify(Sink& sink, Failure) { sink.Append("failed"); } }; struct Success { template friend void AbslStringify(Sink& sink, Success) { sink.Append("ok"); } }; GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(Failure) { return false; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(Success) { return true; } template <> struct StatusCastImpl { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Success) { return absl::OkStatus(); } }; template <> struct StatusCastImpl { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Success) { return absl::OkStatus(); } }; template <> struct StatusCastImpl { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Failure) { return absl::CancelledError(); } }; template struct StatusCastImpl, Failure> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr Cast(Failure) { return absl::CancelledError(); } }; // A boolean representing whether an operation succeeded (true) or failed // (false). class StatusFlag { public: GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag() : value_(true) {} GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION explicit StatusFlag(bool value) : value_(value) {} // NOLINTNEXTLINE(google-explicit-constructor) GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag(Failure) : value_(false) {} // NOLINTNEXTLINE(google-explicit-constructor) GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag(Success) : value_(true) {} GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool ok() const { return value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator==(StatusFlag other) const { return value_ == other.value_; } std::string ToString() const { return value_ ? "ok" : "failed"; } template friend void AbslStringify(Sink& sink, StatusFlag flag) { if (flag.ok()) { sink.Append("ok"); } else { sink.Append("failed"); } } private: bool value_; }; GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(StatusFlag flag, Failure) { return !flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(Failure, StatusFlag flag) { return !flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(StatusFlag flag, Success) { return flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(Success, StatusFlag flag) { return flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(StatusFlag flag, Failure) { return flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(Failure, StatusFlag flag) { return flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(StatusFlag flag, Success) { return !flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(Success, StatusFlag flag) { return !flag.ok(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk( const StatusFlag& flag) { return flag.ok(); } template <> struct StatusCastImpl { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast( StatusFlag flag) { return flag.ok() ? absl::OkStatus() : absl::CancelledError(); } }; template <> struct StatusCastImpl { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast( StatusFlag flag) { return flag.ok() ? absl::OkStatus() : absl::CancelledError(); } }; template <> struct StatusCastImpl { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast( StatusFlag flag) { return flag.ok() ? absl::OkStatus() : absl::CancelledError(); } }; template <> struct StatusCastImpl { static StatusFlag Cast(Success) { return StatusFlag(true); } }; template struct FailureStatusCastImpl, StatusFlag> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr Cast( StatusFlag flag) { DCHECK(!flag.ok()); return absl::CancelledError(); } }; template struct FailureStatusCastImpl, StatusFlag&> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr Cast( StatusFlag flag) { DCHECK(!flag.ok()); return absl::CancelledError(); } }; template struct FailureStatusCastImpl, const StatusFlag&> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr Cast( StatusFlag flag) { DCHECK(!flag.ok()); return absl::CancelledError(); } }; // A value if an operation was successful, or a failure flag if not. template class ValueOrFailure { public: // NOLINTNEXTLINE(google-explicit-constructor) ValueOrFailure(T value) : value_(std::move(value)) {} // NOLINTNEXTLINE(google-explicit-constructor) ValueOrFailure(Failure) {} // NOLINTNEXTLINE(google-explicit-constructor) ValueOrFailure(StatusFlag status) { CHECK(!status.ok()); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure FromOptional( absl::optional value) { return ValueOrFailure{std::move(value)}; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool ok() const { return value_.has_value(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag status() const { return StatusFlag(ok()); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION const T& value() const { return value_.value(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION T& value() { return value_.value(); } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION const T& operator*() const { return *value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION T& operator*() { return *value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION const T* operator->() const { return &*value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION T* operator->() { return &*value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator==( const ValueOrFailure& other) const { return value_ == other.value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator!=( const ValueOrFailure& other) const { return value_ != other.value_; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator==(const T& other) const { return value_ == other; } GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator!=(const T& other) const { return value_ != other; } template friend void AbslStringify(Sink& sink, const ValueOrFailure& value) { if (value.ok()) { sink.Append("Success("); sink.Append(absl::StrCat(*value)); sink.Append(")"); } else { sink.Append("Failure"); } } private: absl::optional value_; }; template inline std::ostream& operator<<(std::ostream& os, const ValueOrFailure& value) { if (value.ok()) { return os << "Success(" << *value << ")"; } else { return os << "Failure"; } } template GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk( const ValueOrFailure& value) { return value.ok(); } template GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline T TakeValue( ValueOrFailure&& value) { return std::move(value.value()); } template struct StatusCastImpl, ValueOrFailure> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr Cast( ValueOrFailure value) { return value.ok() ? absl::StatusOr(std::move(value.value())) : absl::CancelledError(); } }; template struct StatusCastImpl, Failure> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure Cast(Failure) { return ValueOrFailure(Failure{}); } }; template struct StatusCastImpl, StatusFlag&> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure Cast( StatusFlag f) { CHECK(!f.ok()); return ValueOrFailure(Failure{}); } }; template struct StatusCastImpl, StatusFlag> { GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure Cast( StatusFlag f) { CHECK(!f.ok()); return ValueOrFailure(Failure{}); } }; } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H