| .. _module-pw_status-guide: |
| |
| ==================== |
| Get started & guides |
| ==================== |
| .. pigweed-module-subpage:: |
| :name: pw_status |
| :tagline: pw_status: Exception-free error propagation for embedded |
| |
| .. _module-pw_status-get-started: |
| |
| ----------- |
| Get started |
| ----------- |
| To deploy ``pw_status``, depend on the library: |
| |
| .. tab-set:: |
| |
| .. tab-item:: Bazel |
| |
| Add ``@pigweed//pw_status`` to the ``deps`` list in your Bazel target: |
| |
| .. code-block:: |
| |
| cc_library("...") { |
| # ... |
| deps = [ |
| # ... |
| "@pigweed//pw_status", |
| # ... |
| ] |
| } |
| |
| This assumes ``@pigweed`` is the name you pulled Pigweed into your Bazel |
| ``WORKSPACE`` as. |
| |
| .. tab-item:: GN |
| |
| Add ``$dir_pw_status`` to the ``deps`` list in your ``pw_executable()`` |
| build target: |
| |
| .. code-block:: |
| |
| pw_executable("...") { |
| # ... |
| deps = [ |
| # ... |
| "$dir_pw_status", |
| # ... |
| ] |
| } |
| |
| .. tab-item:: CMake |
| |
| Add ``pw_status`` to your ``pw_add_library`` or similar CMake target: |
| |
| .. code-block:: |
| |
| pw_add_library(my_library STATIC |
| HEADERS |
| ... |
| PRIVATE_DEPS |
| # ... |
| pw_status |
| # ... |
| ) |
| |
| .. tab-item:: Zephyr |
| |
| There are two ways to use ``pw_status`` from a Zephyr project: |
| |
| * Depend on ``pw_status`` in your CMake target (see CMake tab). This is |
| the Pigweed team's suggested approach since it enables precise CMake |
| dependency analysis. |
| |
| * Add ``CONFIG_PIGWEED_STATUS=y`` to the Zephyr project's configuration, |
| which causes ``pw_status`` to become a global dependency and have the |
| includes exposed to all targets. The Pigweed team does not recommend |
| this approach, though it is the typical Zephyr solution. |
| |
| Then use the status object or try macros: |
| |
| .. code-block:: cpp |
| |
| #include "pw_status/try.h" |
| #include "pw_status/status.h" |
| |
| pw::Status MyOperation() { |
| PW_TRY(SubOp1()); |
| PW_TRY(SubOp2()); |
| // ... |
| return pw::OkStatus(); |
| } |
| |
| ------ |
| Guides |
| ------ |
| |
| Tracking the first error encountered |
| ------------------------------------ |
| In some contexts it is useful to track the first error encountered while |
| 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. |
| |
| .. admonition:: **No**: Track status manually across calls |
| :class: error |
| |
| .. code-block:: cpp |
| |
| 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; |
| } |
| } |
| } |
| return overall_status; |
| |
| :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. |
| |
| .. admonition:: **Yes**: Track status with :cpp:func:`pw::Status::Update()` |
| :class: checkmark |
| |
| .. code-block:: cpp |
| |
| 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()); |
| } |
| } |
| return overall_status; |
| |
| ---------------------------------- |
| Jointly reporting status with size |
| ---------------------------------- |
| ``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<T>`` class, but it stores both a size and a |
| status, regardless of the status value, and only supports a limited range (27 |
| bits). |
| |
| ``pw::StatusWithSize`` values may be created with functions similar to |
| ``pw::Status``. For example, |
| |
| .. code-block:: cpp |
| |
| // An OK StatusWithSize with a size of 123. |
| StatusWithSize(123) |
| |
| // A NOT_FOUND StatusWithSize with a size of 0. |
| StatusWithSize::NotFound() |
| |
| // A RESOURCE_EXHAUSTED StatusWithSize with a size of 10. |
| StatusWithSize::ResourceExhausted(10) |
| |
| ----------------------------------- |
| Reducing error handling boilerplate |
| ----------------------------------- |
| Manual error handling through return codes is easy to understand and |
| straightforward to write, but leads to verbose code. To reduce boilerplate, |
| Pigweed has the ``PW_TRY`` (``pw_status/try.h``) macro, easing development of |
| functions checking or returning ``pw::Status`` and ``pw::StatusWithSize`` |
| objects. 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 :c:enumerator:`OK`. |
| |
| Example: |
| |
| .. code-block:: cpp |
| |
| Status PwTryExample() { |
| PW_TRY(FunctionThatReturnsStatus()); |
| PW_TRY(FunctionThatReturnsStatusWithSize()); |
| |
| // Do something, only executed if both functions above return OK. |
| } |
| |
| StatusWithSize PwTryWithSizeExample() { |
| PW_TRY_WITH_SIZE(FunctionThatReturnsStatus()); |
| PW_TRY_WITH_SIZE(FunctionThatReturnsStatusWithSize()); |
| |
| // Do something, only executed if both functions above return OK. |
| } |
| |
| ``PW_TRY_ASSIGN`` is for working with ``pw::StatusWithSize`` objects in in |
| functions that return Status. It is similar to ``PW_TRY`` with the addition of |
| assigning the size from the ``pw::StatusWithSize`` on ok. |
| |
| .. code-block:: cpp |
| |
| Status PwTryAssignExample() { |
| size_t size_value |
| PW_TRY_ASSIGN(size_value, FunctionThatReturnsStatusWithSize()); |
| |
| // Do something that uses size_value. size_value is only assigned and this |
| // following code executed if the PW_TRY_ASSIGN function above returns OK. |
| } |