Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. C/C++
  4. pw_async2
  5. Coroutines
  6. pw::async2::Coro< T > Class Template Reference
Loading...
Searching...
No Matches
pw::async2::Coro< T > Class Template Reference

Overview

template<typename T>
class pw::async2::Coro< T >

An asynchronous coroutine which implements the C++20 coroutine API.

Why coroutines?

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.

Allocation

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.

Creating a coroutine function

To create a coroutine, a function must:

  • Have an annotated return type of Coro<T>, where T is the type that will be returned from within the coroutine.
  • Use 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.
  • Accept a 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.

Using co_await

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
 

Member Function Documentation

◆ is_pendable()

template<typename T >
bool pw::async2::Coro< T >::is_pendable ( ) const
inline

Returns whether Pend() can be called.

A default-constructed coroutine, an unallocated coroutine, or a completed coroutine is not pendable.

◆ MakeFallible() [1/2]

template<typename T >
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 > pw::async2::Coro< T >::MakeFallible ( Arg &&  handler = {})
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).

◆ MakeFallible() [2/2]

template<typename T >
template<std::convertible_to< T > Value>
requires (!std::invocable<Value>)
FallibleCoro< T, internal::ReturnValueHandler< std::decay_t< Value > > > pw::async2::Coro< T >::MakeFallible ( Value &&  fallback_value)
inline

Returns a FallibleCoro that runs this coroutine and yields fallback_value if coroutine allocation fails.

◆ Pend()

template<typename T >
Poll< T > pw::async2::Coro< T >::Pend ( Context &  cx)
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.


The documentation for this class was generated from the following file: