From dcbe39839b38dd25381e14e61ef93cde1fdb0f82 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Thu, 16 May 2024 19:17:29 +0000 Subject: [PATCH] pw_async2: Move PW_CO_TRY functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9d35803370e5294bcd411e2124db99a01e17a544 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/209911 Commit-Queue: Taylor Cramer Lint: Lint 🤖 Reviewed-by: Wyatt Hepler --- docs/BUILD.gn | 1 + pw_async2/docs.rst | 27 +++++++++++++++----- pw_async2/public/pw_async2/coro.h | 29 --------------------- pw_status/public/pw_status/try.h | 42 ++++++++++++++++++++++++++++--- pw_status/reference.rst | 6 +++++ 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/docs/BUILD.gn b/docs/BUILD.gn index 4e808acb4..2a228e735 100644 --- a/docs/BUILD.gn +++ b/docs/BUILD.gn @@ -243,6 +243,7 @@ _doxygen_input_files = [ # keep-sorted: start "$dir_pw_spi/public/pw_spi/chip_selector.h", "$dir_pw_spi/public/pw_spi/chip_selector_digital_out.h", "$dir_pw_status/public/pw_status/status.h", + "$dir_pw_status/public/pw_status/try.h", "$dir_pw_stream/public/pw_stream/stream.h", "$dir_pw_stream_uart_linux/public/pw_stream_uart_linux/stream.h", "$dir_pw_string/public/pw_string/format.h", diff --git a/pw_async2/docs.rst b/pw_async2/docs.rst index 8d8b9eb65..3262301b4 100644 --- a/pw_async2/docs.rst +++ b/pw_async2/docs.rst @@ -16,10 +16,10 @@ pw_async2 like other tasks, and can easily plug into an existing ``pw_async2`` systems. -:cpp:type:`pw::async2::Task` is Pigweed's async primitive. ``Task`` objects -are cooperatively-scheduled "threads" which yield to the ``Dispatcher`` -when waiting. When the ``Task`` is able to make progress, the ``Dispatcher`` -will run it again. For example: +:cpp:class:`pw::async2::Task` is Pigweed's async primitive. ``Task`` objects +are cooperatively-scheduled "threads" which yield to the +:cpp:class:`pw::async2::Dispatcher` when waiting. When the ``Task`` is able to make +progress, the ``Dispatcher`` will run it again. For example: .. code-block:: cpp @@ -82,8 +82,8 @@ will run it again. For example: std::optional send_future_ = std::nullopt; }; -Tasks can then be run on a ``Dispatcher`` using the ``Dispatcher::Post`` -method: +Tasks can then be run on a :cpp:class:`pw::async2::Dispatcher` using the +:cpp:func:`pw::async2::Dispatcher::Post` method: .. code-block:: cpp @@ -108,6 +108,18 @@ C++20 users can also define tasks using coroutines! :start-after: [pw_async2-examples-coro-injection] :end-before: [pw_async2-examples-coro-injection] +Any value with a ``Poll Pend(Context&)`` method can be passed to +``co_await``, which will return with a ``T`` when the result is ready. + +To return from a coroutine, ``co_return `` must be used instead of +the usual ``return `` syntax. Because of this, the +:c:macro:`PW_TRY` and :c:macro:`PW_TRY_ASSIGN` macros are not usable within +coroutines. :c:macro:`PW_CO_TRY` and :c:macro:`PW_CO_TRY_ASSIGN` should be +used instead. + +For a more detailed explanation of Pigweed's coroutine support, see the +documentation on the :cpp:class:`pw::async2::Coro` type. + ----------------- C++ API reference ----------------- @@ -137,6 +149,9 @@ C++ API reference .. doxygenclass:: pw::async2::Coro :members: +.. doxygenclass:: pw::async2::CoroContext + :members: + ------------- C++ Utilities ------------- diff --git a/pw_async2/public/pw_async2/coro.h b/pw_async2/public/pw_async2/coro.h index ff971f248..f2c7d12c6 100644 --- a/pw_async2/public/pw_async2/coro.h +++ b/pw_async2/public/pw_async2/coro.h @@ -496,32 +496,3 @@ Coro CoroPromiseType::get_return_object_on_allocation_failure() { } // namespace internal } // namespace pw::async2 - -/// Like `PW_TRY`, but using `co_return` instead of early `return`. -/// -/// This is necessary because only `co_return` can be used inside of a -/// coroutine, and there is no way to detect whether particular code is running -/// within a coroutine or not. -#define PW_CO_TRY(expr) _PW_CO_TRY(_PW_TRY_UNIQUE(__LINE__), expr) - -#define _PW_CO_TRY(result, expr) \ - do { \ - if (auto result = (expr); !result.ok()) { \ - co_return ::pw::internal::ConvertToStatus(result); \ - } \ - } while (0) - -/// Like `PW_TRY_ASSIGN`, but using `co_return` instead of early `return`. -/// -/// This is necessary because only `co_return` can be used inside of a -/// coroutine, and there is no way to detect whether particular code is running -/// within a coroutine or not. -#define PW_CO_TRY_ASSIGN(assignment_lhs, expression) \ - _PW_CO_TRY_ASSIGN(_PW_TRY_UNIQUE(__LINE__), assignment_lhs, expression) - -#define _PW_CO_TRY_ASSIGN(result, lhs, expr) \ - auto result = (expr); \ - if (!result.ok()) { \ - co_return ::pw::internal::ConvertToStatus(result); \ - } \ - lhs = ::pw::internal::ConvertToValue(result); diff --git a/pw_status/public/pw_status/try.h b/pw_status/public/pw_status/try.h index 38ab26e87..836838881 100644 --- a/pw_status/public/pw_status/try.h +++ b/pw_status/public/pw_status/try.h @@ -20,6 +20,8 @@ // Macros for cleanly working with Status or StatusWithSize objects in functions // that return Status. + +/// Returns early if \a expr is a non-OK `Status` or `Result`. #define PW_TRY(expr) _PW_TRY(_PW_TRY_UNIQUE(__LINE__), expr) #define _PW_TRY(result, expr) \ @@ -29,8 +31,10 @@ } \ } while (0) -#define PW_TRY_ASSIGN(assignment_lhs, expression) \ - _PW_TRY_ASSIGN(_PW_TRY_UNIQUE(__LINE__), assignment_lhs, expression) +/// Returns early if \a expression is a non-OK `Result`. +/// If \a expression is okay, assigns the inner value to \a lhs. +#define PW_TRY_ASSIGN(lhs, expression) \ + _PW_TRY_ASSIGN(_PW_TRY_UNIQUE(__LINE__), lhs, expression) #define _PW_TRY_ASSIGN(result, lhs, expr) \ auto result = (expr); \ @@ -39,8 +43,9 @@ } \ lhs = ::pw::internal::ConvertToValue(result); -// Macro for cleanly working with Status or StatusWithSize objects in functions -// that return StatusWithSize. +/// Returns early if \a expr is a non-OK `Status` or `StatusWithSize`. +/// +/// This is designed for use in functions that return a `StatusWithSize`. #define PW_TRY_WITH_SIZE(expr) _PW_TRY_WITH_SIZE(_PW_TRY_UNIQUE(__LINE__), expr) #define _PW_TRY_WITH_SIZE(result, expr) \ @@ -53,6 +58,35 @@ #define _PW_TRY_UNIQUE(line) _PW_TRY_UNIQUE_EXPANDED(line) #define _PW_TRY_UNIQUE_EXPANDED(line) _pw_try_unique_name_##line +/// Like `PW_TRY`, but using `co_return` instead of early `return`. +/// +/// This is necessary because only `co_return` can be used inside of a +/// coroutine, and there is no way to detect whether particular code is running +/// within a coroutine or not. +#define PW_CO_TRY(expr) _PW_CO_TRY(_PW_TRY_UNIQUE(__LINE__), expr) + +#define _PW_CO_TRY(result, expr) \ + do { \ + if (auto result = (expr); !result.ok()) { \ + co_return ::pw::internal::ConvertToStatus(result); \ + } \ + } while (0) + +/// Like `PW_TRY_ASSIGN`, but using `co_return` instead of early `return`. +/// +/// This is necessary because only `co_return` can be used inside of a +/// coroutine, and there is no way to detect whether particular code is running +/// within a coroutine or not. +#define PW_CO_TRY_ASSIGN(lhs, expression) \ + _PW_CO_TRY_ASSIGN(_PW_TRY_UNIQUE(__LINE__), lhs, expression) + +#define _PW_CO_TRY_ASSIGN(result, lhs, expr) \ + auto result = (expr); \ + if (!result.ok()) { \ + co_return ::pw::internal::ConvertToStatus(result); \ + } \ + lhs = ::pw::internal::ConvertToValue(result); + namespace pw::internal { constexpr Status ConvertToStatus(Status status) { return status; } diff --git a/pw_status/reference.rst b/pw_status/reference.rst index 6c644c017..745486abc 100644 --- a/pw_status/reference.rst +++ b/pw_status/reference.rst @@ -373,6 +373,12 @@ C++ API ``PW_STATUS_``. For example, ``PW_STATUS_DATA_LOSS`` corresponds with :c:enumerator:`DATA_LOSS`. +.. doxygendefine:: PW_TRY +.. doxygendefine:: PW_TRY_ASSIGN +.. doxygendefine:: PW_TRY_WITH_SIZE +.. doxygendefine:: PW_CO_TRY +.. doxygendefine:: PW_CO_TRY_ASSIGN + Unused result warnings ---------------------- If the ``PW_STATUS_CFG_CHECK_IF_USED`` option is enabled, ``pw::Status`` objects