An asynchronous coroutine which implements the C++20 coroutine API.
Coroutines allow a series of asynchronous operations to be written as straight line code. Rather than manually writing a state machine, users can co_await any pw_async2 future or another coroutine.
Pigweed's Coro<T> API supports checked, fallible allocations with pw::Allocator. The first argument to any coroutine function must be a CoroContext passed by value (CoroContext is implicitly constructible from pw::Allocator&). This allows the coroutine to allocate space for asynchronously-held stack variables using the CoroContext's allocator.
If initial coroutine frame allocation fails, the returned Coro<T> is invalid (!coro.is_pendable()). If a nested coroutine invoked via co_await fails to allocate while the coroutine is running, the coroutine aborts and unwinds its active coroutine frames.
Pending a Coro<T> directly when initial or nested allocation fails will crash with PW_CRASH (note that Dispatcher::Post checks is_pendable() for the initial allocation and returns nullptr on failure).
Use coro.MakeFallible(...) to wrap a Coro<T> in a FallibleCoroFuture that handles initial and nested allocation failures gracefully instead of crashing:
coro.MakeFallible(): yields std::optional<T> (std::nullopt on allocation failure) or void (if T is void).coro.MakeFallible(fallback_value): yields T, returning fallback_value on allocation failure.coro.MakeFallible(handler): invokes handler() on allocation failure, yielding T if handler() returns a value convertible to T, or std::optional<T> / void if handler() returns void.To create a coroutine, a function must:
Coro<T>, where T is the type that will be returned from within the coroutine.co_return <value> rather than return <value> for any return statements. For pw::Status or pw::Result, use PW_CO_TRY and PW_CO_TRY_ASSIGN rather than PW_TRY and PW_TRY_ASSIGN.CoroContext by value as its first argument. The CoroContext's allocator is used to allocate storage for coroutine stack variables held across a co_await point.Inside a coroutine function, co_await <expr> can be used for pw_async2 futures or other coroutines. The result will be a value of type T.
Public Types | |
| using | value_type = T |
The type this coroutine returns from a co_return expression. | |
Public Member Functions | |
| constexpr | Coro () |
| Creates an empty, invalid coroutine object. | |
| Coro (const Coro &)=delete | |
| Coro & | operator= (const Coro &)=delete |
| Coro (Coro &&other) noexcept=default | |
| Coro & | operator= (Coro &&other) noexcept=default |
| bool | is_pendable () const |
| bool | is_complete () const |
| Returns whether the coroutine has completed. | |
| Poll< T > | Pend (Context &cx) |
| template<typename Handler = void, int &... kExplicitGuard, typename Arg = internal::NoOpAllocFailureHandler, typename ActualHandler = std::conditional_t<std::is_void_v<Handler>, std::decay_t<Arg>, Handler>> requires internal::AllocFailureHandler<ActualHandler, T> | |
| FallibleCoro< T, ActualHandler > | MakeFallible (Arg &&handler={}) |
| template<std::convertible_to< T > Value> requires (!std::invocable<Value>) | |
| FallibleCoro< T, internal::ReturnValueHandler< std::decay_t< Value > > > | MakeFallible (Value &&fallback_value) |
Friends | |
| template<typename , typename > | |
| class | internal::Awaitable |
| template<typename , typename > | |
| class | FallibleCoro |
|
inline |
Returns whether Pend() can be called.
A default-constructed coroutine, an unallocated coroutine, or a completed coroutine is not pendable.
|
inline |
Returns a FallibleCoro that runs this coroutine and handles allocation failures using handler.
If coroutine frame allocation fails (either for this coroutine or for a nested coroutine invoked with co_await), the returned future executes handler instead of crashing.
If handler returns a value convertible to T, the future's value_type is T. If handler returns void, the future's value_type is void (if T is void) or std::optional<T> (yielding std::nullopt on failure).
|
inline |
Returns a FallibleCoro that runs this coroutine and yields fallback_value if coroutine allocation fails.
|
inline |
Attempt to complete this coroutine, returning the result if complete.
Crashes if is_pendable() is false (which occurs when coroutine state allocation fails, if the coroutine was uninitialized, or if Pend previously returned Ready) or if a nested coroutine fails to allocate.