From 0a2c6ba6607bc6f262174189935aaa93468d20bb Mon Sep 17 00:00:00 2001 From: Wyatt Hepler Date: Sat, 8 Apr 2023 01:08:58 +0000 Subject: [PATCH] pw_status: Consolidate Status docs - Move the status description from C++ to the docs so there is a single description of the status codes that applies to all languages. This also allows anywhere in the docs / Doxygen comments to link to the status codes. - Document using status codes in all supported languages. - Link to the status descriptions in Pigweed's docs from C++, Python, and TypeScript. - Introduce Doxygen alias so status codes can be referenced with @pw_status{CODE} in Doxygen comments. Change-Id: I7a59bc90da9cec09a08376952cf8472e02c67f03 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/136732 Pigweed-Auto-Submit: Wyatt Hepler Commit-Queue: Auto-Submit Reviewed-by: Kayce Basques --- docs/BUILD.gn | 1 + docs/Doxyfile | 5 +- pw_status/docs.rst | 574 ++++++++++++++++++---------- pw_status/public/pw_status/status.h | 194 +++------- pw_status/py/pw_status/__init__.py | 7 + pw_status/ts/status.ts | 8 +- 6 files changed, 438 insertions(+), 351 deletions(-) diff --git a/docs/BUILD.gn b/docs/BUILD.gn index b4de8f6298..078a540c49 100644 --- a/docs/BUILD.gn +++ b/docs/BUILD.gn @@ -138,6 +138,7 @@ _doxygen_input_files = [ "$dir_pw_sync/public/pw_sync/borrow.h", "$dir_pw_sync/public/pw_sync/counting_semaphore.h", "$dir_pw_sync/public/pw_sync/inline_borrowable.h", + "$dir_pw_status/public/pw_status/status.h", "$dir_pw_sync/public/pw_sync/interrupt_spin_lock.h", "$dir_pw_sync/public/pw_sync/lock_annotations.h", "$dir_pw_sync/public/pw_sync/mutex.h", diff --git a/docs/Doxyfile b/docs/Doxyfile index 28f2b8f224..8132a75817 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -290,7 +290,8 @@ ALIASES = "rst=^^\verbatim embed:rst:leading-asterisk^^" \ "c_macro{1}=@crossref{c,macro,\1}" \ "cpp_class{1}=@crossref{cpp,class,\1}" \ "cpp_func{1}=@crossref{cpp,func,\1}" \ - "cpp_type{1}=@crossref{cpp,type,\1}" + "cpp_type{1}=@crossref{cpp,type,\1}" \ + "pw_status{1}=@crossref{c,enumerator,\1}" # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -2390,7 +2391,7 @@ PREDEFINED = __cplusplus \ PW_EXTERN_C_START= \ PW_LOCKS_EXCLUDED(...)= \ PW_EXCLUSIVE_LOCKS_REQUIRED(...)= \ - PW_GUARDED_BY(...)= \ + PW_GUARDED_BY(...)= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/pw_status/docs.rst b/pw_status/docs.rst index 997ca539c0..77e6ac5250 100644 --- a/pw_status/docs.rst +++ b/pw_status/docs.rst @@ -1,172 +1,353 @@ .. _module-pw_status: ---------- +========= pw_status ---------- +========= ``pw_status`` provides features for communicating the result of an operation. The classes in ``pw_status`` are used extensively throughout Pigweed. -pw::Status -========== -The primary feature of ``pw_status`` is the ``pw::Status`` class. -``pw::Status`` (``pw_status/status.h``) is a simple, zero-overhead status -object that wraps a status code. +------ +Status +------ +The primary feature of ``pw_status`` is the ``Status`` class (in C++) or enum +(in other languages). ``pw_status`` provides an implementation of status in +every supported Pigweed language. -``pw::Status`` uses Google's standard status codes (see the `Google APIs +The C++ implementation is :cpp:class:`pw::Status`, a simple, zero-overhead +status object that wraps a status code. Other languages use an enum. + +Pigweed's status uses Google's standard status codes (see the `Google APIs repository `_). These codes are used extensively in Google projects including `Abseil `_ (`status/status.h -`_ -) and `gRPC `_ (`doc/statuscodes.md +`_) +and `gRPC `_ (`doc/statuscodes.md `_). -An OK ``Status`` is created by the ``pw::OkStatus`` function or by the default -``Status`` constructor. Non-OK ``Status`` is created with a static member -function that corresponds with the status code. +Status codes +============ +.. c:enumerator:: OK = 0 -.. code-block:: cpp + ``OK`` does not indicate an error; this value is returned on success. It is + typical to check for this value before proceeding on any given call across an + API or RPC boundary. To check this value, use the ``ok()`` member function + rather than inspecting the raw code. + + .. list-table:: + + * - C++ + - ``pw::OkStatus()`` + * - C + - ``PW_STATUS_OK`` + * - Python / Java / TypeScript + - ``Status.OK`` + +.. c:enumerator:: CANCELLED = 1 + + ``CANCELLED`` indicates the operation was cancelled, typically by the caller. + + .. list-table:: + + * - C++ + - ``pw::Status::Cancelled()`` + * - C + - ``PW_STATUS_CANCELLED`` + * - Python / Java / TypeScript + - ``Status.CANCELLED`` + +.. c:enumerator:: UNKNOWN = 2 + + ``UNKNOWN`` indicates an unknown error occurred. In general, more specific + errors should be raised, if possible. Errors raised by APIs that do not + return enough error information may be converted to this error. + + .. list-table:: + + * - C++ + - ``pw::Status::Unknown()`` + * - C + - ``PW_STATUS_UNKNOWN`` + * - Python / Java / TypeScript + - ``Status.UNKNOWN`` + +.. c:enumerator:: INVALID_ARGUMENT = 3 + + ``INVALID_ARGUMENT`` indicates the caller specified an invalid argument, such + as a malformed filename. Note that use of such errors should be narrowly + limited to indicate the invalid nature of the arguments themselves. Errors + with validly formed arguments that may cause errors with the state of the + receiving system should be denoted with :c:enumerator:`FAILED_PRECONDITION` + instead. + + .. list-table:: + + * - C++ + - ``pw::Status::InvalidArgument()`` + * - C + - ``PW_STATUS_INVALID_ARGUMENT`` + * - Python / Java / TypeScript + - ``Status.INVALID_ARGUMENT`` + +.. c:enumerator:: DEADLINE_EXCEEDED = 4 + + ``DEADLINE_EXCEEDED`` indicates a deadline expired before the operation could + complete. For operations that may change state within a system, this error + may be returned even if the operation has completed successfully. For + example, a successful response from a server could have been delayed long + enough for the deadline to expire. + + .. list-table:: + + * - C++ + - ``pw::Status::DeadlineExceeded()`` + * - C + - ``PW_STATUS_DEADLINE_EXCEEDED`` + * - Python / Java / TypeScript + - ``Status.DEADLINE_EXCEEDED`` + +.. c:enumerator:: NOT_FOUND = 5 + + ``NOT_FOUND`` indicates some requested entity (such as a file or directory) + was not found. + + :c:enumerator:`NOT_FOUND` is useful if a request should be denied for an + entire class of users, such as during a gradual feature rollout or + undocumented allowlist. If a request should be denied for specific sets of + users, such as through user-based access control, use + :c:enumerator:`PERMISSION_DENIED` instead. + + .. list-table:: + + * - C++ + - ``pw::Status::NotFound()`` + * - C + - ``PW_STATUS_NOT_FOUND`` + * - Python / Java / TypeScript + - ``Status.NOT_FOUND`` + +.. c:enumerator:: ALREADY_EXISTS = 6 + + ``ALREADY_EXISTS`` indicates that the entity a caller attempted to create + (such as a file or directory) is already present. + + .. list-table:: + + * - C++ + - ``pw::Status::AlreadyExists()`` + * - C + - ``PW_STATUS_ALREADY_EXISTS`` + * - Python / Java / TypeScript + - ``Status.ALREADY_EXISTS`` + +.. c:enumerator:: PERMISSION_DENIED = 7 + + ``PERMISSION_DENIED`` indicates that the caller does not have permission to + execute the specified operation. Note that this error is different than an + error due to an unauthenticated user. This error code does not imply the + request is valid or the requested entity exists or satisfies any other + pre-conditions. + + :c:enumerator:`PERMISSION_DENIED` must not be used for rejections caused by + exhausting some resource. Instead, use :c:enumerator:`RESOURCE_EXHAUSTED` for + those errors. :c:enumerator:`PERMISSION_DENIED` must not be used if the + caller cannot be identified. Instead, use :c:enumerator:`UNAUTHENTICATED` + for those errors. + + .. list-table:: + + * - C++ + - ``pw::Status::PermissionDenied()`` + * - C + - ``PW_STATUS_PERMISSION_DENIED`` + * - Python / Java / TypeScript + - ``Status.PERMISSION_DENIED`` + +.. c:enumerator:: RESOURCE_EXHAUSTED = 8 + + ``RESOURCE_EXHAUSTED`` indicates some resource has been exhausted, perhaps a + per-user quota, or perhaps the entire file system is out of space. + + .. list-table:: + + * - C++ + - ``pw::Status::ResourceExhausted()`` + * - C + - ``PW_STATUS_RESOURCE_EXHAUSTED`` + * - Python / Java / TypeScript + - ``Status.RESOURCE_EXHAUSTED`` + +.. c:enumerator:: FAILED_PRECONDITION = 9 + + ``FAILED_PRECONDITION`` indicates that the operation was rejected because the + system is not in a state required for the operation's execution. For example, + a directory to be deleted may be non-empty, an ``rmdir`` operation is applied + to a non-directory, etc. + + .. _module-pw_status-guidelines: + + Some guidelines that may help a service implementer in deciding between + :c:enumerator:`FAILED_PRECONDITION`, :c:enumerator:`ABORTED`, and + :c:enumerator:`UNAVAILABLE`: + + a. Use :c:enumerator:`UNAVAILABLE` if the client can retry just the failing + call. + b. Use :c:enumerator:`ABORTED` if the client should retry at a higher + transaction level (such as when a client-specified test-and-set fails, + indicating the client should restart a read-modify-write sequence). + c. Use :c:enumerator:`FAILED_PRECONDITION` if the client should not retry + until the system state has been explicitly fixed. For example, if a + ``rmdir`` fails because the directory is non-empty, + :c:enumerator:`FAILED_PRECONDITION` should be returned since the client + should not retry unless the files are deleted from the directory. + + .. list-table:: + + * - C++ + - ``pw::Status::FailedPrecondition()`` + * - C + - ``PW_STATUS_FAILED_PRECONDITION`` + * - Python / Java / TypeScript + - ``Status.FAILED_PRECONDITION`` + +.. c:enumerator:: ABORTED = 10 + + ``ABORTED`` indicates the operation was aborted, typically due to a + concurrency issue such as a sequencer check failure or a failed transaction. + + See the :ref:`guidelines ` above for deciding + between :c:enumerator:`FAILED_PRECONDITION`, :c:enumerator:`ABORTED`, and + :c:enumerator:`UNAVAILABLE`. + + .. list-table:: + + * - C++ + - ``pw::Status::Aborted()`` + * - C + - ``PW_STATUS_ABORTED`` + * - Python / Java / TypeScript + - ``Status.ABORTED`` + +.. c:enumerator:: OUT_OF_RANGE = 11 + + ``OUT_OF_RANGE`` indicates the operation was attempted past the valid range, + such as seeking or reading past an end-of-file. + + Unlike :c:enumerator:`INVALID_ARGUMENT`, this error indicates a problem that + may be fixed if the system state changes. For example, a 32-bit file system + will generate :c:enumerator:`INVALID_ARGUMENT` if asked to read at an offset + that is not in the range [0,2^32-1], but it will generate + :c:enumerator:`OUT_OF_RANGE` if asked to read from an offset past the current + file size. + + There is a fair bit of overlap between :c:enumerator:`FAILED_PRECONDITION` + and :c:enumerator:`OUT_OF_RANGE`. We recommend using + :c:enumerator:`OUT_OF_RANGE` (the more specific error) when it applies so + that callers who are iterating through a space can easily look for an + :c:enumerator:`OUT_OF_RANGE` error to detect when they are done. + + .. list-table:: - // Ok (gRPC code "OK") does not indicate an error; this value is returned on - // success. It is typical to check for this value before proceeding on any - // given call across an API or RPC boundary. To check this value, use the - // `status.ok()` member function rather than inspecting the raw code. - // - // OkStatus() is provided as a free function, rather than a static member - // function like the error statuses to avoid conflicts with the ok() member - // function. Status::Ok() would be too similar to Status::ok(). - pw::OkStatus() - - // Cancelled (gRPC code "CANCELLED") indicates the operation was cancelled, - // typically by the caller. - pw::Status::Cancelled() - - // Unknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In - // general, more specific errors should be raised, if possible. Errors raised - // by APIs that do not return enough error information may be converted to - // this error. - pw::Status::Unknown() - - // InvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller - // specified an invalid argument, such a malformed filename. Note that such - // errors should be narrowly limited to indicate to the invalid nature of the - // arguments themselves. Errors with validly formed arguments that may cause - // errors with the state of the receiving system should be denoted with - // `FailedPrecondition` instead. - pw::Status::InvalidArgument() - - // DeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline - // expired before the operation could complete. For operations that may change - // state within a system, this error may be returned even if the operation has - // completed successfully. For example, a successful response from a server - // could have been delayed long enough for the deadline to expire. - pw::Status::DeadlineExceeded() - - // NotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as - // a file or directory) was not found. - // - // `NotFound` is useful if a request should be denied for an entire class of - // users, such as during a gradual feature rollout or undocumented allow list. - // If, instead, a request should be denied for specific sets of users, such as - // through user-based access control, use `PermissionDenied` instead. - pw::Status::NotFound() - - // AlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a - // caller attempted to create (such as file or directory) is already present. - pw::Status::AlreadyExists() - - // PermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller - // does not have permission to execute the specified operation. Note that this - // error is different than an error due to an *un*authenticated user. This - // error code does not imply the request is valid or the requested entity - // exists or satisfies any other pre-conditions. - // - // `PermissionDenied` must not be used for rejections caused by exhausting - // some resource. Instead, use `ResourceExhausted` for those errors. - // `PermissionDenied` must not be used if the caller cannot be identified. - // Instead, use `Unauthenticated` for those errors. - pw::Status::PermissionDenied() - - // ResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource - // has been exhausted, perhaps a per-user quota, or perhaps the entire file - // system is out of space. - pw::Status::ResourceExhausted() - - // FailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the - // operation was rejected because the system is not in a state required for - // the operation's execution. For example, a directory to be deleted may be - // non-empty, an "rmdir" operation is applied to a non-directory, etc. - // - // Some guidelines that may help a service implementer in deciding between - // `FailedPrecondition`, `Aborted`, and `Unavailable`: - // - // (a) Use `Unavailable` if the client can retry just the failing call. - // (b) Use `Aborted` if the client should retry at a higher transaction - // level (such as when a client-specified test-and-set fails, indicating - // the client should restart a read-modify-write sequence). - // (c) Use `FailedPrecondition` if the client should not retry until - // the system state has been explicitly fixed. For example, if an "rmdir" - // fails because the directory is non-empty, `FailedPrecondition` - // should be returned since the client should not retry unless - // the files are deleted from the directory. - pw::Status::FailedPrecondition() - - // Aborted (gRPC code "ABORTED") indicates the operation was aborted, - // typically due to a concurrency issue such as a sequencer check failure or a - // failed transaction. - // - // See the guidelines above for deciding between `FailedPrecondition`, - // `Aborted`, and `Unavailable`. - pw::Status::Aborted() - - // OutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was - // attempted past the valid range, such as seeking or reading past an - // end-of-file. - // - // Unlike `InvalidArgument`, this error indicates a problem that may - // be fixed if the system state changes. For example, a 32-bit file - // system will generate `InvalidArgument` if asked to read at an - // offset that is not in the range [0,2^32-1], but it will generate - // `OutOfRange` if asked to read from an offset past the current - // file size. - // - // There is a fair bit of overlap between `FailedPrecondition` and - // `OutOfRange`. We recommend using `OutOfRange` (the more specific - // error) when it applies so that callers who are iterating through - // a space can easily look for an `OutOfRange` error to detect when - // they are done. - pw::Status::OutOfRange() - - // Unimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not - // implemented or supported in this service. In this case, the operation - // should not be re-attempted. - pw::Status::Unimplemented() - - // Internal (gRPC code "INTERNAL") indicates an internal error has occurred - // and some invariants expected by the underlying system have not been - // satisfied. This error code is reserved for serious errors. - pw::Status::Internal() - - // Unavailable (gRPC code "UNAVAILABLE") indicates the service is currently - // unavailable and that this is most likely a transient condition. An error - // such as this can be corrected by retrying with a backoff scheme. Note that - // it is not always safe to retry non-idempotent operations. - // - // See the guidelines above for deciding between `FailedPrecondition`, - // `Aborted`, and `Unavailable`. - pw::Status::Unavailable() - - // DataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or - // corruption has occurred. As this error is serious, proper alerting should - // be attached to errors such as this. - pw::Status::DataLoss() - - // Unauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request - // does not have valid authentication credentials for the operation. Correct - // the authentication and try again. - pw::Status::Unauthenticated() - -.. note:: - Status enumerations are also supported for Python and Typescript. + * - C++ + - ``pw::Status::OutOfRange()`` + * - C + - ``PW_STATUS_OUT_OF_RANGE`` + * - Python / Java / TypeScript + - ``Status.OUT_OF_RANGE`` + +.. c:enumerator:: UNIMPLEMENTED = 12 + + ``UNIMPLEMENTED`` indicates the operation is not implemented or supported in + this service. In this case, the operation should not be re-attempted. + + .. list-table:: + + * - C++ + - ``pw::Status::Unimplemented()`` + * - C + - ``PW_STATUS_UNIMPLEMENTED`` + * - Python / Java / TypeScript + - ``Status.UNIMPLEMENTED`` + +.. c:enumerator:: INTERNAL = 13 + + ``INTERNAL`` indicates an internal error has occurred and some invariants + expected by the underlying system have not been satisfied. This error code is + reserved for serious errors. + + .. list-table:: + + * - C++ + - ``pw::Status::Internal()`` + * - C + - ``PW_STATUS_INTERNAL`` + * - Python / Java / TypeScript + - ``Status.INTERNAL`` + +.. c:enumerator:: UNAVAILABLE = 14 + + ``UNAVAILABLE`` indicates the service is currently unavailable and that this + is most likely a transient condition. An error such as this can be corrected + by retrying with a backoff scheme. Note that it is not always safe to retry + non-idempotent operations. + + See the :ref:`guidelines ` above for deciding + between :c:enumerator:`FAILED_PRECONDITION`, :c:enumerator:`ABORTED`, and + :c:enumerator:`UNAVAILABLE`. + + .. list-table:: + + * - C++ + - ``pw::Status::Unavailable()`` + * - C + - ``PW_STATUS_UNAVAILABLE`` + * - Python / Java / TypeScript + - ``Status.UNAVAILABLE`` + +.. c:enumerator:: DATA_LOSS = 15 + + ``DATA_LOSS`` indicates that unrecoverable data loss or corruption has + occurred. As this error is serious, proper alerting should be attached to + errors such as this. + + .. list-table:: + + * - C++ + - ``pw::Status::DataLoss()`` + * - C + - ``PW_STATUS_DATA_LOSS`` + * - Python / Java / TypeScript + - ``Status.DATA_LOSS`` + +.. c:enumerator:: UNAUTHENTICATED = 16 + + ``UNAUTHENTICATED`` indicates that the request does not have valid + authentication credentials for the operation. Correct the authentication and + try again. + + .. list-table:: + + * - C++ + - ``pw::Status::Unauthenticated()`` + * - C + - ``PW_STATUS_UNAUTHENTICATED`` + * - Python / Java / TypeScript + - ``Status.UNAUTHENTICATED`` + +C++ API +======= +.. doxygenclass:: pw::Status + :members: + +.. doxygenfunction:: pw::OkStatus + +.. c:enum:: pw_Status + + Enum to use in place of :cpp:class:`pw::Status` in C code. Always use + :cpp:class:`pw::Status` in C++ code. + + The values of the :c:enum:`pw_Status` enum are all-caps and prefixed with + ``PW_STATUS_``. For example, ``PW_STATUS_DATA_LOSS`` corresponds with + :c:enumerator:`DATA_LOSS`. Tracking the first error encountered ------------------------------------ @@ -175,39 +356,40 @@ allowing execution to continue. Manually writing out ``if`` statements to check and then assign quickly becomes verbose, and doesn't explicitly highlight the intended behavior of "latching" to the first error. - .. code-block:: cpp +.. code-block:: cpp - Status overall_status; - for (Sector& sector : sectors) { - Status erase_status = sector.Erase(); - if (!overall_status.ok()) { - overall_status = erase_status; - } + Status overall_status; + for (Sector& sector : sectors) { + Status erase_status = sector.Erase(); + if (!overall_status.ok()) { + overall_status = erase_status; + } - if (erase_status.ok()) { - Status header_write_status = sector.WriteHeader(); - if (!overall_status.ok()) { - overall_status = header_write_status; - } + if (erase_status.ok()) { + Status header_write_status = sector.WriteHeader(); + if (!overall_status.ok()) { + overall_status = header_write_status; } } - return overall_status; + } + return overall_status; -``pw::Status`` has an ``Update()`` helper function that does exactly this to -reduce visual clutter and succinctly highlight the intended behavior. +:cpp:class:`pw::Status` has a :cpp:func:`pw::Status::Update()` helper function +that does exactly this to reduce visual clutter and succinctly highlight the +intended behavior. - .. code-block:: cpp +.. code-block:: cpp - Status overall_status; - for (Sector& sector : sectors) { - Status erase_status = sector.Erase(); - overall_status.Update(erase_status); + Status overall_status; + for (Sector& sector : sectors) { + Status erase_status = sector.Erase(); + overall_status.Update(erase_status); - if (erase_status.ok()) { - overall_status.Update(sector.WriteHeader()); - } + if (erase_status.ok()) { + overall_status.Update(sector.WriteHeader()); } - return overall_status; + } + return overall_status; Unused result warnings ---------------------- @@ -222,17 +404,14 @@ be enabled unconditionally. C compatibility --------------- -``pw_status`` provides the C-compatible ``pw_Status`` enum for the status codes. -For ease of use, ``pw::Status`` implicitly converts to and from ``pw_Status``. -However, the ``pw_Status`` enum should never be used in C++; instead use the -``Status`` class. - -The values of the ``pw_Status`` enum are all-caps and prefixed with -``PW_STATUS_``. For example, ``PW_STATUS_DATA_LOSS`` corresponds with the C++ -``Status::DataLoss()``. +``pw_status`` provides the C-compatible :c:enum:`pw_Status` enum for the status +codes. For ease of use, :cpp:class:`pw::Status` implicitly converts to and from +:c:enum:`pw_Status`. However, the :c:enum:`pw_Status` enum should never be used +in C++; instead use the :cpp:class:`pw::Status` class. +-------------- StatusWithSize -============== +-------------- ``pw::StatusWithSize`` (``pw_status/status_with_size.h``) is a convenient, efficient class for reporting a status along with an unsigned integer value. It is similar to the ``pw::Result`` class, but it stores both a size and a @@ -253,12 +432,13 @@ bits). // A RESOURCE_EXHAUSTED StatusWithSize with a size of 10. StatusWithSize::ResourceExhausted(10) +------ PW_TRY -====== +------ ``PW_TRY`` (``pw_status/try.h``) is a convenient set of macros for working -with Status and StatusWithSize objects in functions that return Status or -StatusWithSize. The PW_TRY and PW_TRY_WITH_SIZE macros call a function and -do an early return if the function's return status is not ok. +with Status and ``StatusWithSize`` objects in functions that return Status or +``StatusWithSize``. The ``PW_TRY`` and ``PW_TRY_WITH_SIZE`` macros call a +function and do an early return if the function's return status is not ok. Example: @@ -278,9 +458,9 @@ Example: // Do something, only executed if both functions above return OK. } -PW_TRY_ASSIGN is for working with StatusWithSize objects in in functions -that return Status. It is similar to PW_TRY with the addition of assigning -the size from the StatusWithSize on ok. +``PW_TRY_ASSIGN`` is for working with ``StatusWithSize`` objects in in functions +that return Status. It is similar to ``PW_TRY`` with the addition of assigning +the size from the ``StatusWithSize`` on ok. .. code-block:: cpp @@ -292,10 +472,6 @@ the size from the StatusWithSize on ok. // following code executed if the PW_TRY_ASSIGN function above returns OK. } -Compatibility -============= -C++14 - Zephyr ====== To enable ``pw_status`` for Zephyr add ``CONFIG_PIGWEED_STATUS=y`` to the diff --git a/pw_status/public/pw_status/status.h b/pw_status/public/pw_status/status.h index 8ed5330ade..51be466dd7 100644 --- a/pw_status/public/pw_status/status.h +++ b/pw_status/public/pw_status/status.h @@ -29,141 +29,27 @@ extern "C" { // pw_Status uses the canonical Google error codes. The following enum was based // on Abseil's status/status.h. The values are all-caps and prefixed with // PW_STATUS_ instead of using C++ constant style. +// +// The status codes are described at https://pigweed.dev/pw_status#status-codes. +// Consult that guide when deciding which status code to use. typedef enum { - // Ok (gRPC code "OK") does not indicate an error; this value is returned on - // success. It is typical to check for this value before proceeding on any - // given call across an API or RPC boundary. To check this value, use the - // `Status::ok()` member function rather than inspecting the raw code. - PW_STATUS_OK = 0, // Use OkStatus() in C++ - - // Cancelled (gRPC code "CANCELLED") indicates the operation was cancelled, - // typically by the caller. - PW_STATUS_CANCELLED = 1, // Use Status::Cancelled() in C++ - - // Unknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In - // general, more specific errors should be raised, if possible. Errors raised - // by APIs that do not return enough error information may be converted to - // this error. - PW_STATUS_UNKNOWN = 2, // Use Status::Unknown() in C++ - - // InvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller - // specified an invalid argument, such a malformed filename. Note that such - // errors should be narrowly limited to indicate to the invalid nature of the - // arguments themselves. Errors with validly formed arguments that may cause - // errors with the state of the receiving system should be denoted with - // `FailedPrecondition` instead. - PW_STATUS_INVALID_ARGUMENT = 3, // Use Status::InvalidArgument() in C++ - - // DeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline - // expired before the operation could complete. For operations that may change - // state within a system, this error may be returned even if the operation has - // completed successfully. For example, a successful response from a server - // could have been delayed long enough for the deadline to expire. - PW_STATUS_DEADLINE_EXCEEDED = 4, // Use Status::DeadlineExceeded() in C++ - - // NotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as - // a file or directory) was not found. - // - // `NotFound` is useful if a request should be denied for an entire class of - // users, such as during a gradual feature rollout or undocumented allow list. - // If, instead, a request should be denied for specific sets of users, such as - // through user-based access control, use `PermissionDenied` instead. - PW_STATUS_NOT_FOUND = 5, // Use Status::NotFound() in C++ - - // AlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a - // caller attempted to create (such as file or directory) is already present. - PW_STATUS_ALREADY_EXISTS = 6, // Use Status::AlreadyExists() in C++ - - // PermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller - // does not have permission to execute the specified operation. Note that this - // error is different than an error due to an *un*authenticated user. This - // error code does not imply the request is valid or the requested entity - // exists or satisfies any other pre-conditions. - // - // `PermissionDenied` must not be used for rejections caused by exhausting - // some resource. Instead, use `ResourceExhausted` for those errors. - // `PermissionDenied` must not be used if the caller cannot be identified. - // Instead, use `Unauthenticated` for those errors. - PW_STATUS_PERMISSION_DENIED = 7, // Use Status::PermissionDenied() in C++ - - // ResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource - // has been exhausted, perhaps a per-user quota, or perhaps the entire file - // system is out of space. - PW_STATUS_RESOURCE_EXHAUSTED = 8, // Use Status::ResourceExhausted() in C++ - - // FailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the - // operation was rejected because the system is not in a state required for - // the operation's execution. For example, a directory to be deleted may be - // non-empty, an "rmdir" operation is applied to a non-directory, etc. - // - // Some guidelines that may help a service implementer in deciding between - // `FailedPrecondition`, `Aborted`, and `Unavailable`: - // - // (a) Use `Unavailable` if the client can retry just the failing call. - // (b) Use `Aborted` if the client should retry at a higher transaction - // level (such as when a client-specified test-and-set fails, indicating - // the client should restart a read-modify-write sequence). - // (c) Use `FailedPrecondition` if the client should not retry until - // the system state has been explicitly fixed. For example, if an "rmdir" - // fails because the directory is non-empty, `FailedPrecondition` - // should be returned since the client should not retry unless - // the files are deleted from the directory. + PW_STATUS_OK = 0, // Use OkStatus() in C++ + PW_STATUS_CANCELLED = 1, // Use Status::Cancelled() in C++ + PW_STATUS_UNKNOWN = 2, // Use Status::Unknown() in C++ + PW_STATUS_INVALID_ARGUMENT = 3, // Use Status::InvalidArgument() in C++ + PW_STATUS_DEADLINE_EXCEEDED = 4, // Use Status::DeadlineExceeded() in C++ + PW_STATUS_NOT_FOUND = 5, // Use Status::NotFound() in C++ + PW_STATUS_ALREADY_EXISTS = 6, // Use Status::AlreadyExists() in C++ + PW_STATUS_PERMISSION_DENIED = 7, // Use Status::PermissionDenied() in C++ + PW_STATUS_RESOURCE_EXHAUSTED = 8, // Use Status::ResourceExhausted() in C++ PW_STATUS_FAILED_PRECONDITION = 9, // Use Status::FailedPrecondition() in C++ - - // Aborted (gRPC code "ABORTED") indicates the operation was aborted, - // typically due to a concurrency issue such as a sequencer check failure or a - // failed transaction. - // - // See the guidelines above for deciding between `FailedPrecondition`, - // `Aborted`, and `Unavailable`. - PW_STATUS_ABORTED = 10, // Use Status::Aborted() in C++ - - // OutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was - // attempted past the valid range, such as seeking or reading past an - // end-of-file. - // - // Unlike `InvalidArgument`, this error indicates a problem that may - // be fixed if the system state changes. For example, a 32-bit file - // system will generate `InvalidArgument` if asked to read at an - // offset that is not in the range [0,2^32-1], but it will generate - // `OutOfRange` if asked to read from an offset past the current - // file size. - // - // There is a fair bit of overlap between `FailedPrecondition` and - // `OutOfRange`. We recommend using `OutOfRange` (the more specific - // error) when it applies so that callers who are iterating through - // a space can easily look for an `OutOfRange` error to detect when - // they are done. - PW_STATUS_OUT_OF_RANGE = 11, // Use Status::OutOfRange() in C++ - - // Unimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not - // implemented or supported in this service. In this case, the operation - // should not be re-attempted. - PW_STATUS_UNIMPLEMENTED = 12, // Use Status::Unimplemented() in C++ - - // Internal (gRPC code "INTERNAL") indicates an internal error has occurred - // and some invariants expected by the underlying system have not been - // satisfied. This error code is reserved for serious errors. - PW_STATUS_INTERNAL = 13, // Use Status::Internal() in C++ - - // Unavailable (gRPC code "UNAVAILABLE") indicates the service is currently - // unavailable and that this is most likely a transient condition. An error - // such as this can be corrected by retrying with a backoff scheme. Note that - // it is not always safe to retry non-idempotent operations. - // - // See the guidelines above for deciding between `FailedPrecondition`, - // `Aborted`, and `Unavailable`. - PW_STATUS_UNAVAILABLE = 14, // Use Status::Unavailable() in C++ - - // DataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or - // corruption has occurred. As this error is serious, proper alerting should - // be attached to errors such as this. - PW_STATUS_DATA_LOSS = 15, // Use Status::DataLoss() in C++ - - // Unauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request - // does not have valid authentication credentials for the operation. Correct - // the authentication and try again. - PW_STATUS_UNAUTHENTICATED = 16, // Use Status::Unauthenticated() in C++ + PW_STATUS_ABORTED = 10, // Use Status::Aborted() in C++ + PW_STATUS_OUT_OF_RANGE = 11, // Use Status::OutOfRange() in C++ + PW_STATUS_UNIMPLEMENTED = 12, // Use Status::Unimplemented() in C++ + PW_STATUS_INTERNAL = 13, // Use Status::Internal() in C++ + PW_STATUS_UNAVAILABLE = 14, // Use Status::Unavailable() in C++ + PW_STATUS_DATA_LOSS = 15, // Use Status::DataLoss() in C++ + PW_STATUS_UNAUTHENTICATED = 16, // Use Status::Unauthenticated() in C++ // NOTE: this error code entry should not be used and you should not rely on // its value, which may change. @@ -184,14 +70,23 @@ const char* pw_StatusString(pw_Status status); namespace pw { -// The Status class is a thin, zero-cost abstraction around the pw_Status enum. -// It initializes to OkStatus() by default and adds ok() and str() methods. -// Implicit conversions are permitted between pw_Status and pw::Status. +/// `Status` is a thin, zero-cost abstraction around the `pw_Status` enum. It +/// initializes to @pw_status{OK} by default and adds `ok()` and `str()` +/// methods. Implicit conversions are permitted between `pw_Status` and +/// `pw::Status`. +/// +/// An @pw_status{OK} `Status` is created by the @cpp_func{pw::OkStatus} +/// function or by the default `Status` constructor. Non-OK `Status` is created +/// with a static member function that corresponds with the status code. class _PW_STATUS_NO_DISCARD Status { public: using Code = pw_Status; // Functions that create a Status with the specified code. + // + // The status codes are described at + // https://pigweed.dev/pw_status#status-codes. Consult that guide when + // deciding which status code to use. // clang-format off [[nodiscard]] static constexpr Status Cancelled() { return PW_STATUS_CANCELLED; @@ -249,10 +144,12 @@ class _PW_STATUS_NO_DISCARD Status { constexpr Status(const Status&) = default; constexpr Status& operator=(const Status&) = default; - // Returns the Status::Code (pw_Status) for this Status. + /// Returns the `Status::Code` (`pw_Status`) for this `Status`. constexpr Code code() const { return code_; } - // True if the status is OK. + /// True if the status is @pw_status{OK}. + /// + /// This function is provided in place of an `IsOk()` function. [[nodiscard]] constexpr bool ok() const { return code_ == PW_STATUS_OK; } // Functions for checking which status this is. @@ -305,30 +202,31 @@ class _PW_STATUS_NO_DISCARD Status { return code_ == PW_STATUS_UNAUTHENTICATED; } - // Updates this Status to the provided Status IF this status is OK. This is - // useful for tracking the first encountered error, as calls to this helper - // will not change one error status to another error status. + /// Updates this `Status` to the provided `Status` IF this status is + /// @pw_status{OK}. This is useful for tracking the first encountered error, + /// as calls to this helper will not change one error status to another error + /// status. constexpr void Update(Status other) { if (ok()) { code_ = other.code(); } } - // Ignores any errors. This method does nothing except potentially suppress - // complaints from any tools that are checking that errors are not dropped on - // the floor. + /// Ignores any errors. This method does nothing except potentially suppress + /// complaints from any tools that are checking that errors are not dropped on + /// the floor. constexpr void IgnoreError() const {} - // Returns a null-terminated string representation of the Status. + /// Returns a null-terminated string representation of the `Status`. [[nodiscard]] const char* str() const { return pw_StatusString(code_); } private: Code code_; }; -// Returns an OK status. Equivalent to Status() or Status(PW_STATUS_OK). This -// function is used instead of a Status::Ok() function, which would be too -// similar to Status::ok(). +/// Returns an @pw_status{OK} status. Equivalent to `Status()` or +/// `Status(PW_STATUS_OK)`. This function is used instead of a `Status::Ok()` +/// function, which would be too similar to `Status::ok()`. [[nodiscard]] constexpr Status OkStatus() { return Status(); } constexpr bool operator==(const Status& lhs, const Status& rhs) { diff --git a/pw_status/py/pw_status/__init__.py b/pw_status/py/pw_status/__init__.py index 7fcc19e982..527afb7dcd 100644 --- a/pw_status/py/pw_status/__init__.py +++ b/pw_status/py/pw_status/__init__.py @@ -17,6 +17,13 @@ class Status(enum.Enum): + """Pigweed status codes. + + The status codes are described at + https://pigweed.dev/pw_status#status-codes. Consult that guide when deciding + which status code to use. + """ + OK = 0 CANCELLED = 1 UNKNOWN = 2 diff --git a/pw_status/ts/status.ts b/pw_status/ts/status.ts index 5b4c0ba458..3d47424127 100644 --- a/pw_status/ts/status.ts +++ b/pw_status/ts/status.ts @@ -12,8 +12,12 @@ // License for the specific language governing permissions and limitations under // the License. -/** Pigweed Status class; mirrors pw::Status. */ - +/** Pigweed Status class; mirrors pw::Status. + * + * The status codes are described at + * https://pigweed.dev/pw_status#status-codes. Consult that guide when + * deciding which status code to use. + */ export enum Status { OK = 0, CANCELLED = 1,