Boost C++ Libraries

PrevUpHomeNext

Class template async_generator

boost::taar::async_generator — A coroutine-based asynchronous generator of values of type T.

Synopsis

// In header: <boost/taar/core/async_generator.hpp>

template<typename T> 
class async_generator {
public:
  // types
  typedef std::coroutine_handle< promise_type > handle_type;            
  typedef boost::asio::any_io_executor          executor_type;          
  typedef unspecified                           completion_handler_type;

  // member classes/structs/unions

  struct promise_type {
    // member classes/structs/unions

    struct final_awaiter {

      // public member functions
      bool await_ready() noexcept;
      void await_suspend(handle_type) noexcept;
      void await_resume() noexcept;
    };

    struct yield_awaiter {

      // public member functions
      bool await_ready() noexcept;
      void await_suspend(handle_type) noexcept;
      void await_resume() noexcept;
    };

    // public member functions
    async_generator get_return_object();
    std::suspend_always initial_suspend() noexcept;
    final_awaiter final_suspend() noexcept;
    yield_awaiter yield_value(T);
    void return_void() noexcept;
    void unhandled_exception();
    template<typename U, typename Executor> 
      auto await_transform(boost::asio::awaitable< U, Executor >);
    template<typename Executor> 
      auto await_transform(boost::asio::awaitable< void, Executor >);
    auto await_transform(boost::asio::this_coro::executor_t) noexcept;
    auto await_transform(boost::asio::this_coro::cancellation_state_t) noexcept;

    // public data members
    auto await_transform(Deferred &&d) -> decltype(this->await_transform(std::forward< Deferred >(d)(boost::asio::use_awaitable_t< executor_type >{}))) flatten_awaiter yield_value;
    std::optional< T > current_value_;
    completion_handler_type completion_handler_;
    std::optional< executor_type > executor_;
    std::exception_ptr exception_;
    std::optional< boost::asio::cancellation_slot > cancellation_slot_;
    boost::asio::cancellation_signal internal_signal_;
    std::optional< boost::asio::cancellation_state > cancellation_state_;
    std::shared_ptr< bool > alive_;
    std::shared_ptr< boost::asio::cancellation_signal > active_co_spawn_signal_;
    std::shared_ptr< boost::asio::cancellation_signal > flattening_cancel_signal_;
    std::optional< async_generator< T > > flattening_inner_storage_;
    async_generator< T > * flattening_inner_;
    handle_type flattening_outer_handle_;
  };

  // public member functions
  async_generator();
  explicit async_generator(handle_type) noexcept;
  async_generator(async_generator &&) noexcept;
  async_generator & operator=(async_generator &&) noexcept;
  async_generator(async_generator const &) = delete;
  async_generator & operator=(async_generator const &) = delete;
  ~async_generator();
  void set_executor(executor_type);
  void set_cancellation_slot(boost::asio::cancellation_slot);
  void rethrow_if_exception();
  auto next();

  // private member functions
  template<typename Handler> void next_impl(Handler);
  void destroy_handle() noexcept;
};

Description

async_generator<T> is the building block for HTTP responses produced incrementally: streaming JSON, server-sent events, NDJSON, or any other body that should be written to the wire as the data becomes available.

Inside the generator body, suspend with co_yield value to produce a value. The session drives the generator with next, which returns an awaitable resolving to std::optional<T>: empty when the generator has exhausted. The generator may also co_await arbitrary asio::awaitables as long as an executor has been installed via set_executor.

async_generator<T> may yield another async_generator<T> to splice its values into the outer stream (flattening). Exceptions thrown from the generator body are stashed on the promise and rethrown from the next next call. Cancellation propagates via set_cancellation_slot.

See boost::taar::chunked_response for the variant that additionally lets the producer set the HTTP status and headers before the first chunk goes on the wire.

Template Parameters

  1. typename T

    The yielded value type. Any type accepted by boost::taar::chunk_body_from is supported.

async_generator public member functions

  1. async_generator();
  2. explicit async_generator(handle_type h) noexcept;
  3. async_generator(async_generator && other) noexcept;
  4. async_generator & operator=(async_generator && other) noexcept;
  5. async_generator(async_generator const &) = delete;
  6. async_generator & operator=(async_generator const &) = delete;
  7. ~async_generator();
  8. void set_executor(executor_type executor);
    Install the executor used to drive co_awaits and post completions.
  9. void set_cancellation_slot(boost::asio::cancellation_slot slot);
    Wire slot so that cancelling it cancels all pending work in the generator.
  10. void rethrow_if_exception();
    If the generator body stashed an exception, rethrow and clear it.
  11. auto next();
    Drive the generator forward by one step.

    Returns an awaitable that resolves to a tuple (error_code, std::optional<T>). The optional is empty when the generator has finished producing values; the error code carries any transport-level failure (currently always empty, exceptions from the body are propagated by rethrow inside the coroutine).

    If no executor has been installed via set_executor, the one associated with the calling coroutine is captured on the first call.

async_generator private member functions

  1. template<typename Handler> void next_impl(Handler handler);
  2. void destroy_handle() noexcept;

PrevUpHomeNext