xref: /aosp_15_r20/external/pigweed/pw_status/guide.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_status-guide:
2
3====================
4Get started & guides
5====================
6.. pigweed-module-subpage::
7   :name: pw_status
8
9.. _module-pw_status-get-started:
10
11-----------
12Get started
13-----------
14To deploy ``pw_status``, depend on the library:
15
16.. tab-set::
17
18   .. tab-item:: Bazel
19
20      Add ``@pigweed//pw_status`` to the ``deps`` list in your Bazel target:
21
22      .. code-block::
23
24         cc_library("...") {
25           # ...
26           deps = [
27             # ...
28             "@pigweed//pw_status",
29             # ...
30           ]
31         }
32
33      This assumes that your Bazel ``WORKSPACE`` has a `repository
34      <https://bazel.build/concepts/build-ref#repositories>`_ named ``@pigweed``
35      that points to the upstream Pigweed repository.
36
37   .. tab-item:: GN
38
39      Add ``$dir_pw_status`` to the ``deps`` list in your ``pw_executable()``
40      build target:
41
42      .. code-block::
43
44         pw_executable("...") {
45           # ...
46           deps = [
47             # ...
48             "$dir_pw_status",
49             # ...
50           ]
51         }
52
53   .. tab-item:: CMake
54
55      Add ``pw_status`` to your ``pw_add_library`` or similar CMake target:
56
57      .. code-block::
58
59         pw_add_library(my_library STATIC
60           HEADERS
61             ...
62           PRIVATE_DEPS
63             # ...
64             pw_status
65             # ...
66         )
67
68   .. tab-item:: Zephyr
69
70      There are two ways to use ``pw_status`` from a Zephyr project:
71
72      * Depend on ``pw_status`` in your CMake target (see CMake tab). This is
73        the Pigweed team's suggested approach since it enables precise CMake
74        dependency analysis.
75
76      * Add ``CONFIG_PIGWEED_STATUS=y`` to the Zephyr project's configuration,
77        which causes ``pw_status`` to become a global dependency and have the
78        includes exposed to all targets. The Pigweed team does not recommend
79        this approach, though it is the typical Zephyr solution.
80
81Then use the status object or try macros:
82
83.. code-block:: cpp
84
85   #include "pw_status/try.h"
86   #include "pw_status/status.h"
87
88   pw::Status MyOperation() {
89     PW_TRY(SubOp1());
90     PW_TRY(SubOp2());
91     // ...
92     return pw::OkStatus();
93   }
94
95------
96Guides
97------
98
99Tracking the first error encountered
100------------------------------------
101In some contexts it is useful to track the first error encountered while
102allowing execution to continue. Manually writing out ``if`` statements to check
103and then assign quickly becomes verbose, and doesn't explicitly highlight the
104intended behavior of "latching" to the first error.
105
106.. admonition:: **No**: Track status manually across calls
107   :class: error
108
109   .. code-block:: cpp
110
111      Status overall_status;
112      for (Sector& sector : sectors) {
113        Status erase_status = sector.Erase();
114        if (!overall_status.ok()) {
115          overall_status = erase_status;
116        }
117
118        if (erase_status.ok()) {
119          Status header_write_status = sector.WriteHeader();
120          if (!overall_status.ok()) {
121            overall_status = header_write_status;
122          }
123        }
124      }
125      return overall_status;
126
127:cpp:class:`pw::Status` has a :cpp:func:`pw::Status::Update()` helper function
128that does exactly this to reduce visual clutter and succinctly highlight the
129intended behavior.
130
131.. admonition:: **Yes**: Track status with :cpp:func:`pw::Status::Update()`
132   :class: checkmark
133
134   .. code-block:: cpp
135
136      Status overall_status;
137      for (Sector& sector : sectors) {
138        Status erase_status = sector.Erase();
139        overall_status.Update(erase_status);
140
141        if (erase_status.ok()) {
142          overall_status.Update(sector.WriteHeader());
143        }
144      }
145      return overall_status;
146
147.. _module-pw_status-guide-status-with-size:
148
149----------------------------------
150Jointly reporting status with size
151----------------------------------
152``pw::StatusWithSize`` (``pw_status/status_with_size.h``) is a convenient,
153efficient class for reporting a status along with an unsigned integer value.
154It is similar to the ``pw::Result<T>`` class, but it stores both a size and a
155status, regardless of the status value, and only supports a limited range (27
156bits).
157
158``pw::StatusWithSize`` values may be created with functions similar to
159``pw::Status``. For example:
160
161.. code-block:: cpp
162
163   #include "pw_status/status_with_size.h"
164
165   // An OK StatusWithSize with a size of 123.
166   StatusWithSize(123)
167
168   // A NOT_FOUND StatusWithSize with a size of 0.
169   StatusWithSize::NotFound()
170
171   // A RESOURCE_EXHAUSTED StatusWithSize with a size of 10.
172   StatusWithSize::ResourceExhausted(10)
173
174``pw::StatusWithSize`` is useful for cases where an operation may partially
175complete - for example read operations may read some number of bytes into an
176output buffer, but not all.
177
178-----------------------------------
179Reducing error handling boilerplate
180-----------------------------------
181Manual error handling through return codes is easy to understand and
182straightforward to write, but leads to verbose code. To reduce boilerplate,
183Pigweed has the ``PW_TRY`` (``pw_status/try.h``) macro, easing development of
184functions checking or returning ``pw::Status`` and ``pw::StatusWithSize``
185objects. The ``PW_TRY`` and ``PW_TRY_WITH_SIZE`` macros call a function and do
186an early return if the function's return status is not :c:enumerator:`OK`.
187
188Example:
189
190.. code-block:: cpp
191
192   Status PwTryExample() {
193     PW_TRY(FunctionThatReturnsStatus());
194     PW_TRY(FunctionThatReturnsStatusWithSize());
195
196     // Do something, only executed if both functions above return OK.
197   }
198
199   StatusWithSize PwTryWithSizeExample() {
200     PW_TRY_WITH_SIZE(FunctionThatReturnsStatus());
201     PW_TRY_WITH_SIZE(FunctionThatReturnsStatusWithSize());
202
203     // Do something, only executed if both functions above return OK.
204   }
205
206``PW_TRY_ASSIGN`` is for working with ``pw::StatusWithSize`` objects in in
207functions that return Status. It is similar to ``PW_TRY`` with the addition of
208assigning the size from the ``pw::StatusWithSize`` on ok.
209
210.. code-block:: cpp
211
212   Status PwTryAssignExample() {
213     size_t size_value
214     PW_TRY_ASSIGN(size_value, FunctionThatReturnsStatusWithSize());
215
216     // Do something that uses size_value. size_value is only assigned and this
217     // following code executed if the PW_TRY_ASSIGN function above returns OK.
218   }
219