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