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 #include "pw_status/internal/config.h"
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif // __cplusplus
21
22 // This is the pw_Status enum. pw_Status is used to return the status from an
23 // operation.
24 //
25 // In C++, use the pw::Status class instead of the pw_Status enum. pw_Status and
26 // Status implicitly convert to one another and can be passed cleanly between C
27 // and C++ APIs.
28 //
29 // pw_Status uses the canonical Google error codes. The following enum was based
30 // on Abseil's status/status.h. The values are all-caps and prefixed with
31 // PW_STATUS_ instead of using C++ constant style.
32 //
33 // The status codes are described at
34 // https://pigweed.dev/pw_status/reference.html#status-codes. Consult that
35 // guide when deciding which status code to use.
36 typedef enum {
37 PW_STATUS_OK = 0, // Use OkStatus() in C++
38 PW_STATUS_CANCELLED = 1, // Use Status::Cancelled() in C++
39 PW_STATUS_UNKNOWN = 2, // Use Status::Unknown() in C++
40 PW_STATUS_INVALID_ARGUMENT = 3, // Use Status::InvalidArgument() in C++
41 PW_STATUS_DEADLINE_EXCEEDED = 4, // Use Status::DeadlineExceeded() in C++
42 PW_STATUS_NOT_FOUND = 5, // Use Status::NotFound() in C++
43 PW_STATUS_ALREADY_EXISTS = 6, // Use Status::AlreadyExists() in C++
44 PW_STATUS_PERMISSION_DENIED = 7, // Use Status::PermissionDenied() in C++
45 PW_STATUS_RESOURCE_EXHAUSTED = 8, // Use Status::ResourceExhausted() in C++
46 PW_STATUS_FAILED_PRECONDITION = 9, // Use Status::FailedPrecondition() in C++
47 PW_STATUS_ABORTED = 10, // Use Status::Aborted() in C++
48 PW_STATUS_OUT_OF_RANGE = 11, // Use Status::OutOfRange() in C++
49 PW_STATUS_UNIMPLEMENTED = 12, // Use Status::Unimplemented() in C++
50 PW_STATUS_INTERNAL = 13, // Use Status::Internal() in C++
51 PW_STATUS_UNAVAILABLE = 14, // Use Status::Unavailable() in C++
52 PW_STATUS_DATA_LOSS = 15, // Use Status::DataLoss() in C++
53 PW_STATUS_UNAUTHENTICATED = 16, // Use Status::Unauthenticated() in C++
54
55 // NOTE: this error code entry should not be used and you should not rely on
56 // its value, which may change.
57 //
58 // The purpose of this enumerated value is to force people who handle status
59 // codes with `switch()` statements to *not* simply enumerate all possible
60 // values, but instead provide a "default:" case. Providing such a default
61 // case ensures that code will compile when new codes are added.
62 PW_STATUS_DO_NOT_USE_RESERVED_FOR_FUTURE_EXPANSION_USE_DEFAULT_IN_SWITCH_INSTEAD_,
63 } pw_Status; // Use pw::Status in C++
64
65 // Returns a null-terminated string representation of the pw_Status.
66 const char* pw_StatusString(pw_Status status);
67
68 // Indicates the status code with the highest valid value.
69 #define PW_STATUS_LAST PW_STATUS_UNAUTHENTICATED
70
71 #ifdef __cplusplus
72
73 } // extern "C"
74
75 namespace pw {
76
77 /// `Status` is a thin, zero-cost abstraction around the `pw_Status` enum. It
78 /// initializes to @pw_status{OK} by default and adds `ok()` and `str()`
79 /// methods. Implicit conversions are permitted between `pw_Status` and
80 /// `pw::Status`.
81 ///
82 /// An @pw_status{OK} `Status` is created by the @cpp_func{pw::OkStatus}
83 /// function or by the default `Status` constructor. Non-OK `Status` is created
84 /// with a static member function that corresponds with the status code.
85 class _PW_STATUS_NO_DISCARD Status {
86 public:
87 using Code = pw_Status;
88
89 // Functions that create a Status with the specified code.
90 //
91 // The status codes are described at
92 // https://pigweed.dev/pw_status#status-codes. Consult that guide when
93 // deciding which status code to use.
94 // clang-format off
Cancelled()95 [[nodiscard]] static constexpr Status Cancelled() {
96 return PW_STATUS_CANCELLED;
97 }
Unknown()98 [[nodiscard]] static constexpr Status Unknown() {
99 return PW_STATUS_UNKNOWN;
100 }
InvalidArgument()101 [[nodiscard]] static constexpr Status InvalidArgument() {
102 return PW_STATUS_INVALID_ARGUMENT;
103 }
DeadlineExceeded()104 [[nodiscard]] static constexpr Status DeadlineExceeded() {
105 return PW_STATUS_DEADLINE_EXCEEDED;
106 }
NotFound()107 [[nodiscard]] static constexpr Status NotFound() {
108 return PW_STATUS_NOT_FOUND;
109 }
AlreadyExists()110 [[nodiscard]] static constexpr Status AlreadyExists() {
111 return PW_STATUS_ALREADY_EXISTS;
112 }
PermissionDenied()113 [[nodiscard]] static constexpr Status PermissionDenied() {
114 return PW_STATUS_PERMISSION_DENIED;
115 }
ResourceExhausted()116 [[nodiscard]] static constexpr Status ResourceExhausted() {
117 return PW_STATUS_RESOURCE_EXHAUSTED;
118 }
FailedPrecondition()119 [[nodiscard]] static constexpr Status FailedPrecondition() {
120 return PW_STATUS_FAILED_PRECONDITION;
121 }
Aborted()122 [[nodiscard]] static constexpr Status Aborted() {
123 return PW_STATUS_ABORTED;
124 }
OutOfRange()125 [[nodiscard]] static constexpr Status OutOfRange() {
126 return PW_STATUS_OUT_OF_RANGE;
127 }
Unimplemented()128 [[nodiscard]] static constexpr Status Unimplemented() {
129 return PW_STATUS_UNIMPLEMENTED;
130 }
Internal()131 [[nodiscard]] static constexpr Status Internal() {
132 return PW_STATUS_INTERNAL;
133 }
Unavailable()134 [[nodiscard]] static constexpr Status Unavailable() {
135 return PW_STATUS_UNAVAILABLE;
136 }
DataLoss()137 [[nodiscard]] static constexpr Status DataLoss() {
138 return PW_STATUS_DATA_LOSS;
139 }
Unauthenticated()140 [[nodiscard]] static constexpr Status Unauthenticated() {
141 return PW_STATUS_UNAUTHENTICATED;
142 }
143 // clang-format on
144
145 // Statuses are created with a Status::Code.
code_(code)146 constexpr Status(Code code = PW_STATUS_OK) : code_(code) {}
147
148 constexpr Status(const Status&) = default;
149 constexpr Status& operator=(const Status&) = default;
150
151 /// Returns the `Status::Code` (`pw_Status`) for this `Status`.
code()152 constexpr Code code() const { return code_; }
153
154 /// True if the status is @pw_status{OK}.
155 ///
156 /// This function is provided in place of an `IsOk()` function.
ok()157 [[nodiscard]] constexpr bool ok() const { return code_ == PW_STATUS_OK; }
158
159 // Functions for checking which status this is.
IsCancelled()160 [[nodiscard]] constexpr bool IsCancelled() const {
161 return code_ == PW_STATUS_CANCELLED;
162 }
IsUnknown()163 [[nodiscard]] constexpr bool IsUnknown() const {
164 return code_ == PW_STATUS_UNKNOWN;
165 }
IsInvalidArgument()166 [[nodiscard]] constexpr bool IsInvalidArgument() const {
167 return code_ == PW_STATUS_INVALID_ARGUMENT;
168 }
IsDeadlineExceeded()169 [[nodiscard]] constexpr bool IsDeadlineExceeded() const {
170 return code_ == PW_STATUS_DEADLINE_EXCEEDED;
171 }
IsNotFound()172 [[nodiscard]] constexpr bool IsNotFound() const {
173 return code_ == PW_STATUS_NOT_FOUND;
174 }
IsAlreadyExists()175 [[nodiscard]] constexpr bool IsAlreadyExists() const {
176 return code_ == PW_STATUS_ALREADY_EXISTS;
177 }
IsPermissionDenied()178 [[nodiscard]] constexpr bool IsPermissionDenied() const {
179 return code_ == PW_STATUS_PERMISSION_DENIED;
180 }
IsResourceExhausted()181 [[nodiscard]] constexpr bool IsResourceExhausted() const {
182 return code_ == PW_STATUS_RESOURCE_EXHAUSTED;
183 }
IsFailedPrecondition()184 [[nodiscard]] constexpr bool IsFailedPrecondition() const {
185 return code_ == PW_STATUS_FAILED_PRECONDITION;
186 }
IsAborted()187 [[nodiscard]] constexpr bool IsAborted() const {
188 return code_ == PW_STATUS_ABORTED;
189 }
IsOutOfRange()190 [[nodiscard]] constexpr bool IsOutOfRange() const {
191 return code_ == PW_STATUS_OUT_OF_RANGE;
192 }
IsUnimplemented()193 [[nodiscard]] constexpr bool IsUnimplemented() const {
194 return code_ == PW_STATUS_UNIMPLEMENTED;
195 }
IsInternal()196 [[nodiscard]] constexpr bool IsInternal() const {
197 return code_ == PW_STATUS_INTERNAL;
198 }
IsUnavailable()199 [[nodiscard]] constexpr bool IsUnavailable() const {
200 return code_ == PW_STATUS_UNAVAILABLE;
201 }
IsDataLoss()202 [[nodiscard]] constexpr bool IsDataLoss() const {
203 return code_ == PW_STATUS_DATA_LOSS;
204 }
IsUnauthenticated()205 [[nodiscard]] constexpr bool IsUnauthenticated() const {
206 return code_ == PW_STATUS_UNAUTHENTICATED;
207 }
208
209 /// Updates this `Status` to the provided `Status` IF this status is
210 /// @pw_status{OK}. This is useful for tracking the first encountered error,
211 /// as calls to this helper will not change one error status to another error
212 /// status.
Update(Status other)213 constexpr void Update(Status other) {
214 if (ok()) {
215 code_ = other.code();
216 }
217 }
218
219 /// Ignores any errors. This method does nothing except potentially suppress
220 /// complaints from any tools that are checking that errors are not dropped on
221 /// the floor.
IgnoreError()222 constexpr void IgnoreError() const {}
223
224 /// Returns a null-terminated string representation of the `Status`.
str()225 [[nodiscard]] const char* str() const { return pw_StatusString(code_); }
226
227 private:
228 Code code_;
229 };
230
231 /// Returns an @pw_status{OK} status. Equivalent to `Status()` or
232 /// `Status(PW_STATUS_OK)`. This function is used instead of a `Status::Ok()`
233 /// function, which would be too similar to `Status::ok()`.
OkStatus()234 [[nodiscard]] constexpr Status OkStatus() { return Status(); }
235
236 constexpr bool operator==(const Status& lhs, const Status& rhs) {
237 return lhs.code() == rhs.code();
238 }
239
240 constexpr bool operator!=(const Status& lhs, const Status& rhs) {
241 return lhs.code() != rhs.code();
242 }
243
244 namespace internal {
245
246 // This function and its various overloads are for use by internal macros
247 // like PW_TRY.
ConvertToStatus(Status status)248 constexpr Status ConvertToStatus(Status status) { return status; }
249
250 } // namespace internal
251 } // namespace pw
252
253 // Create a C++ overload of pw_StatusString so that it supports pw::Status in
254 // addition to pw_Status.
pw_StatusString(pw::Status status)255 inline const char* pw_StatusString(pw::Status status) {
256 return pw_StatusString(status.code());
257 }
258
259 #endif // __cplusplus
260