xref: /aosp_15_r20/external/grpc-grpc/src/core/lib/promise/status_flag.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Copyright 2023 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include "absl/status/status.h"
21 #include "absl/status/statusor.h"
22 #include "absl/types/optional.h"
23 
24 #include <grpc/support/log.h>
25 
26 #include "src/core/lib/promise/detail/status.h"
27 
28 namespace grpc_core {
29 
30 struct Failure {
31   template <typename Sink>
AbslStringifyFailure32   friend void AbslStringify(Sink& sink, Failure) {
33     sink.Append("failed");
34   }
35 };
36 struct Success {
37   template <typename Sink>
AbslStringifySuccess38   friend void AbslStringify(Sink& sink, Success) {
39     sink.Append("ok");
40   }
41 };
42 
IsStatusOk(Failure)43 inline bool IsStatusOk(Failure) { return false; }
IsStatusOk(Success)44 inline bool IsStatusOk(Success) { return true; }
45 
46 template <>
47 struct StatusCastImpl<absl::Status, Success> {
48   static absl::Status Cast(Success) { return absl::OkStatus(); }
49 };
50 
51 template <>
52 struct StatusCastImpl<absl::Status, const Success&> {
53   static absl::Status Cast(Success) { return absl::OkStatus(); }
54 };
55 
56 template <>
57 struct StatusCastImpl<absl::Status, Failure> {
58   static absl::Status Cast(Failure) { return absl::CancelledError(); }
59 };
60 
61 template <typename T>
62 struct StatusCastImpl<absl::StatusOr<T>, Failure> {
63   static absl::StatusOr<T> Cast(Failure) { return absl::CancelledError(); }
64 };
65 
66 // A boolean representing whether an operation succeeded (true) or failed
67 // (false).
68 class StatusFlag {
69  public:
70   StatusFlag() : value_(true) {}
71   explicit StatusFlag(bool value) : value_(value) {}
72   // NOLINTNEXTLINE(google-explicit-constructor)
73   StatusFlag(Failure) : value_(false) {}
74   // NOLINTNEXTLINE(google-explicit-constructor)
75   StatusFlag(Success) : value_(true) {}
76 
77   bool ok() const { return value_; }
78 
79   bool operator==(StatusFlag other) const { return value_ == other.value_; }
80   std::string ToString() const { return value_ ? "ok" : "failed"; }
81 
82   template <typename Sink>
83   friend void AbslStringify(Sink& sink, StatusFlag flag) {
84     if (flag.ok()) {
85       sink.Append("ok");
86     } else {
87       sink.Append("failed");
88     }
89   }
90 
91  private:
92   bool value_;
93 };
94 
95 inline bool operator==(StatusFlag flag, Failure) { return !flag.ok(); }
96 inline bool operator==(Failure, StatusFlag flag) { return !flag.ok(); }
97 inline bool operator==(StatusFlag flag, Success) { return flag.ok(); }
98 inline bool operator==(Success, StatusFlag flag) { return flag.ok(); }
99 
100 inline bool operator!=(StatusFlag flag, Failure) { return flag.ok(); }
101 inline bool operator!=(Failure, StatusFlag flag) { return flag.ok(); }
102 inline bool operator!=(StatusFlag flag, Success) { return !flag.ok(); }
103 inline bool operator!=(Success, StatusFlag flag) { return !flag.ok(); }
104 
105 inline bool IsStatusOk(const StatusFlag& flag) { return flag.ok(); }
106 
107 template <>
108 struct StatusCastImpl<absl::Status, StatusFlag> {
109   static absl::Status Cast(StatusFlag flag) {
110     return flag.ok() ? absl::OkStatus() : absl::CancelledError();
111   }
112 };
113 
114 template <>
115 struct StatusCastImpl<absl::Status, StatusFlag&> {
116   static absl::Status Cast(StatusFlag flag) {
117     return flag.ok() ? absl::OkStatus() : absl::CancelledError();
118   }
119 };
120 
121 template <>
122 struct StatusCastImpl<absl::Status, const StatusFlag&> {
123   static absl::Status Cast(StatusFlag flag) {
124     return flag.ok() ? absl::OkStatus() : absl::CancelledError();
125   }
126 };
127 
128 template <typename T>
129 struct FailureStatusCastImpl<absl::StatusOr<T>, StatusFlag> {
130   static absl::StatusOr<T> Cast(StatusFlag flag) {
131     GPR_DEBUG_ASSERT(!flag.ok());
132     return absl::CancelledError();
133   }
134 };
135 
136 template <typename T>
137 struct FailureStatusCastImpl<absl::StatusOr<T>, StatusFlag&> {
138   static absl::StatusOr<T> Cast(StatusFlag flag) {
139     GPR_DEBUG_ASSERT(!flag.ok());
140     return absl::CancelledError();
141   }
142 };
143 
144 template <typename T>
145 struct FailureStatusCastImpl<absl::StatusOr<T>, const StatusFlag&> {
146   static absl::StatusOr<T> Cast(StatusFlag flag) {
147     GPR_DEBUG_ASSERT(!flag.ok());
148     return absl::CancelledError();
149   }
150 };
151 
152 // A value if an operation was successful, or a failure flag if not.
153 template <typename T>
154 class ValueOrFailure {
155  public:
156   // NOLINTNEXTLINE(google-explicit-constructor)
157   ValueOrFailure(T value) : value_(std::move(value)) {}
158   // NOLINTNEXTLINE(google-explicit-constructor)
159   ValueOrFailure(Failure) {}
160   // NOLINTNEXTLINE(google-explicit-constructor)
161   ValueOrFailure(StatusFlag status) { GPR_ASSERT(!status.ok()); }
162 
163   static ValueOrFailure FromOptional(absl::optional<T> value) {
164     return ValueOrFailure{std::move(value)};
165   }
166 
167   bool ok() const { return value_.has_value(); }
168   StatusFlag status() const { return StatusFlag(ok()); }
169 
170   const T& value() const { return value_.value(); }
171   T& value() { return value_.value(); }
172   const T& operator*() const { return *value_; }
173   T& operator*() { return *value_; }
174 
175   bool operator==(const ValueOrFailure& other) const {
176     return value_ == other.value_;
177   }
178 
179   bool operator!=(const ValueOrFailure& other) const {
180     return value_ != other.value_;
181   }
182 
183   bool operator==(const T& other) const { return value_ == other; }
184 
185   bool operator!=(const T& other) const { return value_ != other; }
186 
187  private:
188   absl::optional<T> value_;
189 };
190 
191 template <typename T>
192 inline bool IsStatusOk(const ValueOrFailure<T>& value) {
193   return value.ok();
194 }
195 
196 template <typename T>
197 inline T TakeValue(ValueOrFailure<T>&& value) {
198   return std::move(value.value());
199 }
200 
201 template <typename T>
202 struct StatusCastImpl<absl::StatusOr<T>, ValueOrFailure<T>> {
203   static absl::StatusOr<T> Cast(ValueOrFailure<T> value) {
204     return value.ok() ? absl::StatusOr<T>(std::move(value.value()))
205                       : absl::CancelledError();
206   }
207 };
208 
209 template <typename T>
210 struct StatusCastImpl<ValueOrFailure<T>, Failure> {
211   static ValueOrFailure<T> Cast(Failure) {
212     return ValueOrFailure<T>(Failure{});
213   }
214 };
215 
216 template <typename T>
217 struct StatusCastImpl<ValueOrFailure<T>, StatusFlag&> {
218   static ValueOrFailure<T> Cast(StatusFlag f) {
219     GPR_ASSERT(!f.ok());
220     return ValueOrFailure<T>(Failure{});
221   }
222 };
223 
224 template <typename T>
225 struct StatusCastImpl<ValueOrFailure<T>, StatusFlag> {
226   static ValueOrFailure<T> Cast(StatusFlag f) {
227     GPR_ASSERT(!f.ok());
228     return ValueOrFailure<T>(Failure{});
229   }
230 };
231 
232 }  // namespace grpc_core
233 
234 #endif  // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H