1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #ifdef __cplusplus
17 extern "C" {
18 #endif // __cplusplus
19
20 // This is the pw_Status enum. pw_Status is used to return the status from an
21 // operation.
22 //
23 // In C++, use the pw::Status class instead of the pw_Status enum. pw_Status and
24 // Status implicitly convert to one another and can be passed cleanly between C
25 // and C++ APIs.
26 //
27 // pw_Status uses the canonical Google error codes. The following enum was based
28 // on Abseil's status/status.h. The values are all-caps and prefixed with
29 // PW_STATUS_ instead of using C++ constant style.
30 typedef enum {
31 // Ok (gRPC code "OK") does not indicate an error; this value is returned on
32 // success. It is typical to check for this value before proceeding on any
33 // given call across an API or RPC boundary. To check this value, use the
34 // `Status::ok()` member function rather than inspecting the raw code.
35 PW_STATUS_OK = 0, // Use OkStatus() in C++
36
37 // Cancelled (gRPC code "CANCELLED") indicates the operation was cancelled,
38 // typically by the caller.
39 PW_STATUS_CANCELLED = 1, // Use Status::Cancelled() in C++
40
41 // Unknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In
42 // general, more specific errors should be raised, if possible. Errors raised
43 // by APIs that do not return enough error information may be converted to
44 // this error.
45 PW_STATUS_UNKNOWN = 2, // Use Status::Unknown() in C++
46
47 // InvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller
48 // specified an invalid argument, such a malformed filename. Note that such
49 // errors should be narrowly limited to indicate to the invalid nature of the
50 // arguments themselves. Errors with validly formed arguments that may cause
51 // errors with the state of the receiving system should be denoted with
52 // `FailedPrecondition` instead.
53 PW_STATUS_INVALID_ARGUMENT = 3, // Use Status::InvalidArgument() in C++
54
55 // DeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline
56 // expired before the operation could complete. For operations that may change
57 // state within a system, this error may be returned even if the operation has
58 // completed successfully. For example, a successful response from a server
59 // could have been delayed long enough for the deadline to expire.
60 PW_STATUS_DEADLINE_EXCEEDED = 4, // Use Status::DeadlineExceeded() in C++
61
62 // NotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as
63 // a file or directory) was not found.
64 //
65 // `NotFound` is useful if a request should be denied for an entire class of
66 // users, such as during a gradual feature rollout or undocumented allow list.
67 // If, instead, a request should be denied for specific sets of users, such as
68 // through user-based access control, use `PermissionDenied` instead.
69 PW_STATUS_NOT_FOUND = 5, // Use Status::NotFound() in C++
70
71 // AlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a
72 // caller attempted to create (such as file or directory) is already present.
73 PW_STATUS_ALREADY_EXISTS = 6, // Use Status::AlreadyExists() in C++
74
75 // PermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller
76 // does not have permission to execute the specified operation. Note that this
77 // error is different than an error due to an *un*authenticated user. This
78 // error code does not imply the request is valid or the requested entity
79 // exists or satisfies any other pre-conditions.
80 //
81 // `PermissionDenied` must not be used for rejections caused by exhausting
82 // some resource. Instead, use `ResourceExhausted` for those errors.
83 // `PermissionDenied` must not be used if the caller cannot be identified.
84 // Instead, use `Unauthenticated` for those errors.
85 PW_STATUS_PERMISSION_DENIED = 7, // Use Status::PermissionDenied() in C++
86
87 // ResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource
88 // has been exhausted, perhaps a per-user quota, or perhaps the entire file
89 // system is out of space.
90 PW_STATUS_RESOURCE_EXHAUSTED = 8, // Use Status::ResourceExhausted() in C++
91
92 // FailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the
93 // operation was rejected because the system is not in a state required for
94 // the operation's execution. For example, a directory to be deleted may be
95 // non-empty, an "rmdir" operation is applied to a non-directory, etc.
96 //
97 // Some guidelines that may help a service implementer in deciding between
98 // `FailedPrecondition`, `Aborted`, and `Unavailable`:
99 //
100 // (a) Use `Unavailable` if the client can retry just the failing call.
101 // (b) Use `Aborted` if the client should retry at a higher transaction
102 // level (such as when a client-specified test-and-set fails, indicating
103 // the client should restart a read-modify-write sequence).
104 // (c) Use `FailedPrecondition` if the client should not retry until
105 // the system state has been explicitly fixed. For example, if an "rmdir"
106 // fails because the directory is non-empty, `FailedPrecondition`
107 // should be returned since the client should not retry unless
108 // the files are deleted from the directory.
109 PW_STATUS_FAILED_PRECONDITION = 9, // Use Status::FailedPrecondition() in C++
110
111 // Aborted (gRPC code "ABORTED") indicates the operation was aborted,
112 // typically due to a concurrency issue such as a sequencer check failure or a
113 // failed transaction.
114 //
115 // See the guidelines above for deciding between `FailedPrecondition`,
116 // `Aborted`, and `Unavailable`.
117 PW_STATUS_ABORTED = 10, // Use Status::Aborted() in C++
118
119 // OutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was
120 // attempted past the valid range, such as seeking or reading past an
121 // end-of-file.
122 //
123 // Unlike `InvalidArgument`, this error indicates a problem that may
124 // be fixed if the system state changes. For example, a 32-bit file
125 // system will generate `InvalidArgument` if asked to read at an
126 // offset that is not in the range [0,2^32-1], but it will generate
127 // `OutOfRange` if asked to read from an offset past the current
128 // file size.
129 //
130 // There is a fair bit of overlap between `FailedPrecondition` and
131 // `OutOfRange`. We recommend using `OutOfRange` (the more specific
132 // error) when it applies so that callers who are iterating through
133 // a space can easily look for an `OutOfRange` error to detect when
134 // they are done.
135 PW_STATUS_OUT_OF_RANGE = 11, // Use Status::OutOfRange() in C++
136
137 // Unimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not
138 // implemented or supported in this service. In this case, the operation
139 // should not be re-attempted.
140 PW_STATUS_UNIMPLEMENTED = 12, // Use Status::Unimplemented() in C++
141
142 // Internal (gRPC code "INTERNAL") indicates an internal error has occurred
143 // and some invariants expected by the underlying system have not been
144 // satisfied. This error code is reserved for serious errors.
145 PW_STATUS_INTERNAL = 13, // Use Status::Internal() in C++
146
147 // Unavailable (gRPC code "UNAVAILABLE") indicates the service is currently
148 // unavailable and that this is most likely a transient condition. An error
149 // such as this can be corrected by retrying with a backoff scheme. Note that
150 // it is not always safe to retry non-idempotent operations.
151 //
152 // See the guidelines above for deciding between `FailedPrecondition`,
153 // `Aborted`, and `Unavailable`.
154 PW_STATUS_UNAVAILABLE = 14, // Use Status::Unavailable() in C++
155
156 // DataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or
157 // corruption has occurred. As this error is serious, proper alerting should
158 // be attached to errors such as this.
159 PW_STATUS_DATA_LOSS = 15, // Use Status::DataLoss() in C++
160
161 // Unauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request
162 // does not have valid authentication credentials for the operation. Correct
163 // the authentication and try again.
164 PW_STATUS_UNAUTHENTICATED = 16, // Use Status::Unauthenticated() in C++
165
166 // NOTE: this error code entry should not be used and you should not rely on
167 // its value, which may change.
168 //
169 // The purpose of this enumerated value is to force people who handle status
170 // codes with `switch()` statements to *not* simply enumerate all possible
171 // values, but instead provide a "default:" case. Providing such a default
172 // case ensures that code will compile when new codes are added.
173 PW_STATUS_DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_,
174 } pw_Status; // Use pw::Status in C++
175
176 // Returns a null-terminated string representation of the pw_Status.
177 const char* pw_StatusString(pw_Status status);
178
179 #ifdef __cplusplus
180
181 } // extern "C"
182
183 namespace pw {
184
185 // The Status class is a thin, zero-cost abstraction around the pw_Status enum.
186 // It initializes to OkStatus() by default and adds ok() and str() methods.
187 // Implicit conversions are permitted between pw_Status and pw::Status.
188 class Status {
189 public:
190 using Code = pw_Status;
191
192 // Functions that create a Status with the specified code.
193 // clang-format off
Cancelled()194 [[nodiscard]] static constexpr Status Cancelled() {
195 return PW_STATUS_CANCELLED;
196 }
Unknown()197 [[nodiscard]] static constexpr Status Unknown() {
198 return PW_STATUS_UNKNOWN;
199 }
InvalidArgument()200 [[nodiscard]] static constexpr Status InvalidArgument() {
201 return PW_STATUS_INVALID_ARGUMENT;
202 }
DeadlineExceeded()203 [[nodiscard]] static constexpr Status DeadlineExceeded() {
204 return PW_STATUS_DEADLINE_EXCEEDED;
205 }
NotFound()206 [[nodiscard]] static constexpr Status NotFound() {
207 return PW_STATUS_NOT_FOUND;
208 }
AlreadyExists()209 [[nodiscard]] static constexpr Status AlreadyExists() {
210 return PW_STATUS_ALREADY_EXISTS;
211 }
PermissionDenied()212 [[nodiscard]] static constexpr Status PermissionDenied() {
213 return PW_STATUS_PERMISSION_DENIED;
214 }
ResourceExhausted()215 [[nodiscard]] static constexpr Status ResourceExhausted() {
216 return PW_STATUS_RESOURCE_EXHAUSTED;
217 }
FailedPrecondition()218 [[nodiscard]] static constexpr Status FailedPrecondition() {
219 return PW_STATUS_FAILED_PRECONDITION;
220 }
Aborted()221 [[nodiscard]] static constexpr Status Aborted() {
222 return PW_STATUS_ABORTED;
223 }
OutOfRange()224 [[nodiscard]] static constexpr Status OutOfRange() {
225 return PW_STATUS_OUT_OF_RANGE;
226 }
Unimplemented()227 [[nodiscard]] static constexpr Status Unimplemented() {
228 return PW_STATUS_UNIMPLEMENTED;
229 }
Internal()230 [[nodiscard]] static constexpr Status Internal() {
231 return PW_STATUS_INTERNAL;
232 }
Unavailable()233 [[nodiscard]] static constexpr Status Unavailable() {
234 return PW_STATUS_UNAVAILABLE;
235 }
DataLoss()236 [[nodiscard]] static constexpr Status DataLoss() {
237 return PW_STATUS_DATA_LOSS;
238 }
Unauthenticated()239 [[nodiscard]] static constexpr Status Unauthenticated() {
240 return PW_STATUS_UNAUTHENTICATED;
241 }
242 // clang-format on
243
244 // Statuses are created with a Status::Code.
code_(code)245 constexpr Status(Code code = PW_STATUS_OK) : code_(code) {}
246
247 constexpr Status(const Status&) = default;
248 constexpr Status& operator=(const Status&) = default;
249
250 // Returns the Status::Code (pw_Status) for this Status.
code()251 constexpr Code code() const { return code_; }
252
253 // True if the status is OK.
ok()254 [[nodiscard]] constexpr bool ok() const { return code_ == PW_STATUS_OK; }
255
256 // Functions for checking which status this is.
IsCancelled()257 [[nodiscard]] constexpr bool IsCancelled() const {
258 return code_ == PW_STATUS_CANCELLED;
259 }
IsUnknown()260 [[nodiscard]] constexpr bool IsUnknown() const {
261 return code_ == PW_STATUS_UNKNOWN;
262 }
IsInvalidArgument()263 [[nodiscard]] constexpr bool IsInvalidArgument() const {
264 return code_ == PW_STATUS_INVALID_ARGUMENT;
265 }
IsDeadlineExceeded()266 [[nodiscard]] constexpr bool IsDeadlineExceeded() const {
267 return code_ == PW_STATUS_DEADLINE_EXCEEDED;
268 }
IsNotFound()269 [[nodiscard]] constexpr bool IsNotFound() const {
270 return code_ == PW_STATUS_NOT_FOUND;
271 }
IsAlreadyExists()272 [[nodiscard]] constexpr bool IsAlreadyExists() const {
273 return code_ == PW_STATUS_ALREADY_EXISTS;
274 }
IsPermissionDenied()275 [[nodiscard]] constexpr bool IsPermissionDenied() const {
276 return code_ == PW_STATUS_PERMISSION_DENIED;
277 }
IsResourceExhausted()278 [[nodiscard]] constexpr bool IsResourceExhausted() const {
279 return code_ == PW_STATUS_RESOURCE_EXHAUSTED;
280 }
IsFailedPrecondition()281 [[nodiscard]] constexpr bool IsFailedPrecondition() const {
282 return code_ == PW_STATUS_FAILED_PRECONDITION;
283 }
IsAborted()284 [[nodiscard]] constexpr bool IsAborted() const {
285 return code_ == PW_STATUS_ABORTED;
286 }
IsOutOfRange()287 [[nodiscard]] constexpr bool IsOutOfRange() const {
288 return code_ == PW_STATUS_OUT_OF_RANGE;
289 }
IsUnimplemented()290 [[nodiscard]] constexpr bool IsUnimplemented() const {
291 return code_ == PW_STATUS_UNIMPLEMENTED;
292 }
IsInternal()293 [[nodiscard]] constexpr bool IsInternal() const {
294 return code_ == PW_STATUS_INTERNAL;
295 }
IsUnavailable()296 [[nodiscard]] constexpr bool IsUnavailable() const {
297 return code_ == PW_STATUS_UNAVAILABLE;
298 }
IsDataLoss()299 [[nodiscard]] constexpr bool IsDataLoss() const {
300 return code_ == PW_STATUS_DATA_LOSS;
301 }
IsUnauthenticated()302 [[nodiscard]] constexpr bool IsUnauthenticated() const {
303 return code_ == PW_STATUS_UNAUTHENTICATED;
304 }
305
306 // Returns a null-terminated string representation of the Status.
str()307 [[nodiscard]] const char* str() const { return pw_StatusString(code_); }
308
309 private:
310 Code code_;
311 };
312
313 // Returns an OK status. Equivalent to Status() or Status(PW_STATUS_OK). This
314 // function is used instead of a Status::Ok() function, which would be too
315 // similar to Status::ok().
OkStatus()316 [[nodiscard]] constexpr Status OkStatus() { return Status(); }
317
318 constexpr bool operator==(const Status& lhs, const Status& rhs) {
319 return lhs.code() == rhs.code();
320 }
321
322 constexpr bool operator!=(const Status& lhs, const Status& rhs) {
323 return lhs.code() != rhs.code();
324 }
325
326 } // namespace pw
327
328 // Create a C++ overload of pw_StatusString so that it supports pw::Status in
329 // addition to pw_Status.
pw_StatusString(pw::Status status)330 inline const char* pw_StatusString(pw::Status status) {
331 return pw_StatusString(status.code());
332 }
333
334 #endif // __cplusplus
335