• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <ostream>
21 
22 #include "absl/log/check.h"
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/types/optional.h"
27 #include "src/core/lib/promise/detail/status.h"
28 
29 namespace grpc_core {
30 
31 struct Failure {
32   template <typename Sink>
AbslStringifyFailure33   friend void AbslStringify(Sink& sink, Failure) {
34     sink.Append("failed");
35   }
36 };
37 struct Success {
38   template <typename Sink>
AbslStringifySuccess39   friend void AbslStringify(Sink& sink, Success) {
40     sink.Append("ok");
41   }
42 };
43 
IsStatusOk(Failure)44 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(Failure) {
45   return false;
46 }
IsStatusOk(Success)47 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(Success) {
48   return true;
49 }
50 
51 template <>
52 struct StatusCastImpl<absl::Status, Success> {
53   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Success) {
54     return absl::OkStatus();
55   }
56 };
57 
58 template <>
59 struct StatusCastImpl<absl::Status, Success&> {
60   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Success) {
61     return absl::OkStatus();
62   }
63 };
64 
65 template <>
66 struct StatusCastImpl<absl::Status, const Success&> {
67   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Success) {
68     return absl::OkStatus();
69   }
70 };
71 
72 template <>
73 struct StatusCastImpl<absl::Status, Failure> {
74   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(Failure) {
75     return absl::CancelledError();
76   }
77 };
78 
79 template <typename T>
80 struct StatusCastImpl<absl::StatusOr<T>, Failure> {
81   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(Failure) {
82     return absl::CancelledError();
83   }
84 };
85 
86 // A boolean representing whether an operation succeeded (true) or failed
87 // (false).
88 class StatusFlag {
89  public:
90   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag() : value_(true) {}
91   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION explicit StatusFlag(bool value)
92       : value_(value) {}
93   // NOLINTNEXTLINE(google-explicit-constructor)
94   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag(Failure) : value_(false) {}
95   // NOLINTNEXTLINE(google-explicit-constructor)
96   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag(Success) : value_(true) {}
97 
98   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool ok() const { return value_; }
99 
100   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator==(StatusFlag other) const {
101     return value_ == other.value_;
102   }
103   std::string ToString() const { return value_ ? "ok" : "failed"; }
104 
105   template <typename Sink>
106   friend void AbslStringify(Sink& sink, StatusFlag flag) {
107     if (flag.ok()) {
108       sink.Append("ok");
109     } else {
110       sink.Append("failed");
111     }
112   }
113 
114  private:
115   bool value_;
116 };
117 
118 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(StatusFlag flag,
119                                                             Failure) {
120   return !flag.ok();
121 }
122 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(Failure,
123                                                             StatusFlag flag) {
124   return !flag.ok();
125 }
126 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(StatusFlag flag,
127                                                             Success) {
128   return flag.ok();
129 }
130 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator==(Success,
131                                                             StatusFlag flag) {
132   return flag.ok();
133 }
134 
135 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(StatusFlag flag,
136                                                             Failure) {
137   return flag.ok();
138 }
139 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(Failure,
140                                                             StatusFlag flag) {
141   return flag.ok();
142 }
143 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(StatusFlag flag,
144                                                             Success) {
145   return !flag.ok();
146 }
147 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool operator!=(Success,
148                                                             StatusFlag flag) {
149   return !flag.ok();
150 }
151 
152 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(
153     const StatusFlag& flag) {
154   return flag.ok();
155 }
156 
157 template <>
158 struct StatusCastImpl<absl::Status, StatusFlag> {
159   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(
160       StatusFlag flag) {
161     return flag.ok() ? absl::OkStatus() : absl::CancelledError();
162   }
163 };
164 
165 template <>
166 struct StatusCastImpl<absl::Status, StatusFlag&> {
167   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(
168       StatusFlag flag) {
169     return flag.ok() ? absl::OkStatus() : absl::CancelledError();
170   }
171 };
172 
173 template <>
174 struct StatusCastImpl<absl::Status, const StatusFlag&> {
175   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::Status Cast(
176       StatusFlag flag) {
177     return flag.ok() ? absl::OkStatus() : absl::CancelledError();
178   }
179 };
180 
181 template <>
182 struct StatusCastImpl<StatusFlag, Success> {
183   static StatusFlag Cast(Success) { return StatusFlag(true); }
184 };
185 
186 template <>
187 struct StatusCastImpl<StatusFlag, Failure> {
188   static StatusFlag Cast(Failure) { return StatusFlag(false); }
189 };
190 
191 template <>
192 struct FailureStatusCastImpl<StatusFlag, Failure> {
193   static StatusFlag Cast(Failure) { return StatusFlag(false); }
194 };
195 
196 template <typename T>
197 struct FailureStatusCastImpl<absl::StatusOr<T>, StatusFlag> {
198   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
199       StatusFlag flag) {
200     DCHECK(!flag.ok());
201     return absl::CancelledError();
202   }
203 };
204 
205 template <typename T>
206 struct FailureStatusCastImpl<absl::StatusOr<T>, StatusFlag&> {
207   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
208       StatusFlag flag) {
209     DCHECK(!flag.ok());
210     return absl::CancelledError();
211   }
212 };
213 
214 template <typename T>
215 struct FailureStatusCastImpl<absl::StatusOr<T>, const StatusFlag&> {
216   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
217       StatusFlag flag) {
218     DCHECK(!flag.ok());
219     return absl::CancelledError();
220   }
221 };
222 
223 // A value if an operation was successful, or a failure flag if not.
224 template <typename T>
225 class ValueOrFailure {
226  public:
227   // NOLINTNEXTLINE(google-explicit-constructor)
228   ValueOrFailure(T value) : value_(std::move(value)) {}
229   // NOLINTNEXTLINE(google-explicit-constructor)
230   ValueOrFailure(Failure) {}
231   // NOLINTNEXTLINE(google-explicit-constructor)
232   ValueOrFailure(StatusFlag status) { CHECK(!status.ok()); }
233 
234   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure FromOptional(
235       absl::optional<T> value) {
236     return ValueOrFailure{std::move(value)};
237   }
238 
239   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool ok() const {
240     return value_.has_value();
241   }
242   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION StatusFlag status() const {
243     return StatusFlag(ok());
244   }
245 
246   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION const T& value() const {
247     return value_.value();
248   }
249   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION T& value() { return value_.value(); }
250   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION const T& operator*() const {
251     return *value_;
252   }
253   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION T& operator*() { return *value_; }
254   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION const T* operator->() const {
255     return &*value_;
256   }
257   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION T* operator->() { return &*value_; }
258 
259   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator==(
260       const ValueOrFailure& other) const {
261     return value_ == other.value_;
262   }
263 
264   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator!=(
265       const ValueOrFailure& other) const {
266     return value_ != other.value_;
267   }
268 
269   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator==(const T& other) const {
270     return value_ == other;
271   }
272 
273   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION bool operator!=(const T& other) const {
274     return value_ != other;
275   }
276 
277   template <typename Sink>
278   friend void AbslStringify(Sink& sink, const ValueOrFailure& value) {
279     if (value.ok()) {
280       sink.Append("Success(");
281       sink.Append(absl::StrCat(*value));
282       sink.Append(")");
283     } else {
284       sink.Append("Failure");
285     }
286   }
287 
288  private:
289   absl::optional<T> value_;
290 };
291 
292 template <typename T>
293 inline std::ostream& operator<<(std::ostream& os,
294                                 const ValueOrFailure<T>& value) {
295   if (value.ok()) {
296     return os << "Success(" << *value << ")";
297   } else {
298     return os << "Failure";
299   }
300 }
301 
302 template <typename T>
303 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline bool IsStatusOk(
304     const ValueOrFailure<T>& value) {
305   return value.ok();
306 }
307 
308 template <typename T>
309 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline T TakeValue(
310     ValueOrFailure<T>&& value) {
311   return std::move(value.value());
312 }
313 
314 template <typename T>
315 struct StatusCastImpl<absl::StatusOr<T>, ValueOrFailure<T>> {
316   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static absl::StatusOr<T> Cast(
317       ValueOrFailure<T> value) {
318     return value.ok() ? absl::StatusOr<T>(std::move(value.value()))
319                       : absl::CancelledError();
320   }
321 };
322 
323 template <typename T>
324 struct StatusCastImpl<ValueOrFailure<T>, Failure> {
325   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure<T> Cast(Failure) {
326     return ValueOrFailure<T>(Failure{});
327   }
328 };
329 
330 template <typename T>
331 struct StatusCastImpl<ValueOrFailure<T>, StatusFlag&> {
332   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure<T> Cast(
333       StatusFlag f) {
334     CHECK(!f.ok());
335     return ValueOrFailure<T>(Failure{});
336   }
337 };
338 
339 template <typename T>
340 struct StatusCastImpl<ValueOrFailure<T>, StatusFlag> {
341   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static ValueOrFailure<T> Cast(
342       StatusFlag f) {
343     CHECK(!f.ok());
344     return ValueOrFailure<T>(Failure{});
345   }
346 };
347 
348 }  // namespace grpc_core
349 
350 #endif  // GRPC_SRC_CORE_LIB_PROMISE_STATUS_FLAG_H
351