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