• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_status:
2
3---------
4pw_status
5---------
6``pw_status`` provides features for communicating the result of an operation.
7The classes in ``pw_status`` are used extensively throughout Pigweed.
8
9pw::Status
10==========
11The primary feature of ``pw_status`` is the ``pw::Status`` class.
12``pw::Status`` (``pw_status/status.h``) is a simple, zero-overhead status
13object that wraps a status code.
14
15``pw::Status`` uses Google's standard status codes (see the `Google APIs
16repository <https://github.com/googleapis/googleapis/blob/HEAD/google/rpc/code.proto>`_).
17These codes are used extensively in Google projects including `Abseil
18<https://abseil.io>`_ (`status/status.h
19<https://cs.opensource.google/abseil/abseil-cpp/+/HEAD:absl/status/status.h>`_
20) and `gRPC <https://grpc.io>`_ (`doc/statuscodes.md
21<https://github.com/grpc/grpc/blob/HEAD/doc/statuscodes.md>`_).
22
23An OK ``Status`` is created by the ``pw::OkStatus`` function or by the default
24``Status`` constructor.  Non-OK ``Status`` is created with a static member
25function that corresponds with the status code.
26
27.. code-block:: cpp
28
29  // Ok (gRPC code "OK") does not indicate an error; this value is returned on
30  // success. It is typical to check for this value before proceeding on any
31  // given call across an API or RPC boundary. To check this value, use the
32  // `status.ok()` member function rather than inspecting the raw code.
33  //
34  // OkStatus() is provided as a free function, rather than a static member
35  // function like the error statuses to avoid conflicts with the ok() member
36  // function. Status::Ok() would be too similar to Status::ok().
37  pw::OkStatus()
38
39  // Cancelled (gRPC code "CANCELLED") indicates the operation was cancelled,
40  // typically by the caller.
41  pw::Status::Cancelled()
42
43  // Unknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In
44  // general, more specific errors should be raised, if possible. Errors raised
45  // by APIs that do not return enough error information may be converted to
46  // this error.
47  pw::Status::Unknown()
48
49  // InvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller
50  // specified an invalid argument, such a malformed filename. Note that such
51  // errors should be narrowly limited to indicate to the invalid nature of the
52  // arguments themselves. Errors with validly formed arguments that may cause
53  // errors with the state of the receiving system should be denoted with
54  // `FailedPrecondition` instead.
55  pw::Status::InvalidArgument()
56
57  // DeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline
58  // expired before the operation could complete. For operations that may change
59  // state within a system, this error may be returned even if the operation has
60  // completed successfully. For example, a successful response from a server
61  // could have been delayed long enough for the deadline to expire.
62  pw::Status::DeadlineExceeded()
63
64  // NotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as
65  // a file or directory) was not found.
66  //
67  // `NotFound` is useful if a request should be denied for an entire class of
68  // users, such as during a gradual feature rollout or undocumented allow list.
69  // If, instead, a request should be denied for specific sets of users, such as
70  // through user-based access control, use `PermissionDenied` instead.
71  pw::Status::NotFound()
72
73  // AlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a
74  // caller attempted to create (such as file or directory) is already present.
75  pw::Status::AlreadyExists()
76
77  // PermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller
78  // does not have permission to execute the specified operation. Note that this
79  // error is different than an error due to an *un*authenticated user. This
80  // error code does not imply the request is valid or the requested entity
81  // exists or satisfies any other pre-conditions.
82  //
83  // `PermissionDenied` must not be used for rejections caused by exhausting
84  // some resource. Instead, use `ResourceExhausted` for those errors.
85  // `PermissionDenied` must not be used if the caller cannot be identified.
86  // Instead, use `Unauthenticated` for those errors.
87  pw::Status::PermissionDenied()
88
89  // ResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource
90  // has been exhausted, perhaps a per-user quota, or perhaps the entire file
91  // system is out of space.
92  pw::Status::ResourceExhausted()
93
94  // FailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the
95  // operation was rejected because the system is not in a state required for
96  // the operation's execution. For example, a directory to be deleted may be
97  // non-empty, an "rmdir" operation is applied to a non-directory, etc.
98  //
99  // Some guidelines that may help a service implementer in deciding between
100  // `FailedPrecondition`, `Aborted`, and `Unavailable`:
101  //
102  //  (a) Use `Unavailable` if the client can retry just the failing call.
103  //  (b) Use `Aborted` if the client should retry at a higher transaction
104  //      level (such as when a client-specified test-and-set fails, indicating
105  //      the client should restart a read-modify-write sequence).
106  //  (c) Use `FailedPrecondition` if the client should not retry until
107  //      the system state has been explicitly fixed. For example, if an "rmdir"
108  //      fails because the directory is non-empty, `FailedPrecondition`
109  //      should be returned since the client should not retry unless
110  //      the files are deleted from the directory.
111  pw::Status::FailedPrecondition()
112
113  // Aborted (gRPC code "ABORTED") indicates the operation was aborted,
114  // typically due to a concurrency issue such as a sequencer check failure or a
115  // failed transaction.
116  //
117  // See the guidelines above for deciding between `FailedPrecondition`,
118  // `Aborted`, and `Unavailable`.
119  pw::Status::Aborted()
120
121  // OutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was
122  // attempted past the valid range, such as seeking or reading past an
123  // end-of-file.
124  //
125  // Unlike `InvalidArgument`, this error indicates a problem that may
126  // be fixed if the system state changes. For example, a 32-bit file
127  // system will generate `InvalidArgument` if asked to read at an
128  // offset that is not in the range [0,2^32-1], but it will generate
129  // `OutOfRange` if asked to read from an offset past the current
130  // file size.
131  //
132  // There is a fair bit of overlap between `FailedPrecondition` and
133  // `OutOfRange`.  We recommend using `OutOfRange` (the more specific
134  // error) when it applies so that callers who are iterating through
135  // a space can easily look for an `OutOfRange` error to detect when
136  // they are done.
137  pw::Status::OutOfRange()
138
139  // Unimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not
140  // implemented or supported in this service. In this case, the operation
141  // should not be re-attempted.
142  pw::Status::Unimplemented()
143
144  // Internal (gRPC code "INTERNAL") indicates an internal error has occurred
145  // and some invariants expected by the underlying system have not been
146  // satisfied. This error code is reserved for serious errors.
147  pw::Status::Internal()
148
149  // Unavailable (gRPC code "UNAVAILABLE") indicates the service is currently
150  // unavailable and that this is most likely a transient condition. An error
151  // such as this can be corrected by retrying with a backoff scheme. Note that
152  // it is not always safe to retry non-idempotent operations.
153  //
154  // See the guidelines above for deciding between `FailedPrecondition`,
155  // `Aborted`, and `Unavailable`.
156  pw::Status::Unavailable()
157
158  // DataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or
159  // corruption has occurred. As this error is serious, proper alerting should
160  // be attached to errors such as this.
161  pw::Status::DataLoss()
162
163  // Unauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request
164  // does not have valid authentication credentials for the operation. Correct
165  // the authentication and try again.
166  pw::Status::Unauthenticated()
167
168.. note::
169  Status enumerations are also supported for Python and Typescript.
170
171Tracking the first error encountered
172------------------------------------
173In some contexts it is useful to track the first error encountered while
174allowing execution to continue. Manually writing out ``if`` statements to check
175and then assign quickly becomes verbose, and doesn't explicitly highlight the
176intended behavior of "latching" to the first error.
177
178  .. code-block:: cpp
179
180    Status overall_status;
181    for (Sector& sector : sectors) {
182      Status erase_status = sector.Erase();
183      if (!overall_status.ok()) {
184        overall_status = erase_status;
185      }
186
187      if (erase_status.ok()) {
188        Status header_write_status = sector.WriteHeader();
189        if (!overall_status.ok()) {
190          overall_status = header_write_status;
191        }
192      }
193    }
194    return overall_status;
195
196``pw::Status`` has an ``Update()`` helper function that does exactly this to
197reduce visual clutter and succinctly highlight the intended behavior.
198
199  .. code-block:: cpp
200
201    Status overall_status;
202    for (Sector& sector : sectors) {
203      Status erase_status = sector.Erase();
204      overall_status.Update(erase_status);
205
206      if (erase_status.ok()) {
207        overall_status.Update(sector.WriteHeader());
208      }
209    }
210    return overall_status;
211
212Unused result warnings
213----------------------
214If the ``PW_STATUS_CFG_CHECK_IF_USED`` option is enabled, ``pw::Status`` objects
215returned from function calls must be used or it is a compilation error. To
216silence these warnings call ``IgnoreError()`` on the returned status object.
217
218``PW_STATUS_CFG_CHECK_IF_USED`` defaults to off. Pigweed compiles with this
219option enabled, but projects that use Pigweed will need to be updated to compile
220with this option. After all projects have migrated, unused result warnings will
221be enabled unconditionally.
222
223C compatibility
224---------------
225``pw_status`` provides the C-compatible ``pw_Status`` enum for the status codes.
226For ease of use, ``pw::Status`` implicitly converts to and from ``pw_Status``.
227However, the ``pw_Status`` enum should never be used in C++; instead use the
228``Status`` class.
229
230The values of the ``pw_Status`` enum are all-caps and prefixed with
231``PW_STATUS_``. For example, ``PW_STATUS_DATA_LOSS`` corresponds with the C++
232``Status::DataLoss()``.
233
234StatusWithSize
235==============
236``pw::StatusWithSize`` (``pw_status/status_with_size.h``) is a convenient,
237efficient class for reporting a status along with an unsigned integer value.
238It is similar to the ``pw::Result<T>`` class, but it stores both a size and a
239status, regardless of the status value, and only supports a limited range (27
240bits).
241
242``pw::StatusWithSize`` values may be created with functions similar to
243``pw::Status``. For example,
244
245  .. code-block:: cpp
246
247    // An OK StatusWithSize with a size of 123.
248    StatusWithSize(123)
249
250    // A NOT_FOUND StatusWithSize with a size of 0.
251    StatusWithSize::NotFound()
252
253    // A RESOURCE_EXHAUSTED StatusWithSize with a size of 10.
254    StatusWithSize::ResourceExhausted(10)
255
256PW_TRY
257======
258``PW_TRY`` (``pw_status/try.h``) is a convenient set of macros for working
259with Status and StatusWithSize objects in functions that return Status or
260StatusWithSize. The PW_TRY and PW_TRY_WITH_SIZE macros call a function and
261do an early return if the function's return status is not ok.
262
263Example:
264
265.. code-block:: cpp
266
267  Status PwTryExample() {
268    PW_TRY(FunctionThatReturnsStatus());
269    PW_TRY(FunctionThatReturnsStatusWithSize());
270
271    // Do something, only executed if both functions above return OK.
272  }
273
274  StatusWithSize PwTryWithSizeExample() {
275    PW_TRY_WITH_SIZE(FunctionThatReturnsStatus());
276    PW_TRY_WITH_SIZE(FunctionThatReturnsStatusWithSize());
277
278    // Do something, only executed if both functions above return OK.
279  }
280
281PW_TRY_ASSIGN is for working with StatusWithSize objects in in functions
282that return Status. It is similar to PW_TRY with the addition of assigning
283the size from the StatusWithSize on ok.
284
285.. code-block:: cpp
286
287  Status PwTryAssignExample() {
288    size_t size_value
289    PW_TRY_ASSIGN(size_value, FunctionThatReturnsStatusWithSize());
290
291    // Do something that uses size_value. size_value is only assigned and this
292    // following code executed if the PW_TRY_ASSIGN function above returns OK.
293  }
294
295Compatibility
296=============
297C++14
298
299Zephyr
300======
301To enable ``pw_status`` for Zephyr add ``CONFIG_PIGWEED_STATUS=y`` to the
302project's configuration.
303