145 lines
5.1 KiB
C++
145 lines
5.1 KiB
C++
//
|
|
// experimental/co_composed.hpp
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
|
|
#ifndef ASIO_EXPERIMENTAL_CO_COMPOSED_HPP
|
|
#define ASIO_EXPERIMENTAL_CO_COMPOSED_HPP
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
# pragma once
|
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
|
|
#include "asio/detail/config.hpp"
|
|
#include "asio/async_result.hpp"
|
|
|
|
#include "asio/detail/push_options.hpp"
|
|
|
|
namespace asio {
|
|
namespace experimental {
|
|
|
|
/// Creates an initiation function object that may be used to launch a
|
|
/// coroutine-based composed asynchronous operation.
|
|
/**
|
|
* The experimental::co_composed utility simplifies the implementation of
|
|
* composed asynchronous operations by automatically adapting a coroutine to be
|
|
* an initiation function object for use with @c async_initiate. When awaiting
|
|
* asynchronous operations, the coroutine automatically uses a conforming
|
|
* intermediate completion handler.
|
|
*
|
|
* @param implementation A function object that contains the coroutine-based
|
|
* implementation of the composed asynchronous operation. The first argument to
|
|
* the function object represents the state of the operation, and may be used
|
|
* to test for cancellation. The remaining arguments are those passed to @c
|
|
* async_initiate after the completion token.
|
|
*
|
|
* @param io_objects_or_executors Zero or more I/O objects or I/O executors for
|
|
* which outstanding work must be maintained while the operation is incomplete.
|
|
*
|
|
* @par Per-Operation Cancellation
|
|
* By default, per-operation cancellation is disabled for composed operations
|
|
* that use experimental::co_composed. It must be explicitly enabled by calling
|
|
* the state's @c reset_cancellation_state function.
|
|
*
|
|
* @par Examples
|
|
* The following example illustrates manual error handling and explicit checks
|
|
* for cancellation. The completion handler is invoked via a @c co_yield to the
|
|
* state's @c complete function, which never returns.
|
|
*
|
|
* @code template <typename CompletionToken>
|
|
* auto async_echo(tcp::socket& socket,
|
|
* CompletionToken&& token)
|
|
* {
|
|
* return asio::async_initiate<
|
|
* CompletionToken, void(std::error_code)>(
|
|
* asio::experimental::co_composed(
|
|
* [](auto state, tcp::socket& socket) -> void
|
|
* {
|
|
* state.reset_cancellation_state(
|
|
* asio::enable_terminal_cancellation());
|
|
*
|
|
* while (!state.cancelled())
|
|
* {
|
|
* char data[1024];
|
|
* auto [e1, n1] =
|
|
* co_await socket.async_read_some(
|
|
* asio::buffer(data),
|
|
* asio::as_tuple(asio::deferred));
|
|
*
|
|
* if (e1)
|
|
* co_yield state.complete(e1);
|
|
*
|
|
* if (!!state.cancelled())
|
|
* co_yield state.complete(
|
|
* make_error_code(asio::error::operation_aborted));
|
|
*
|
|
* auto [e2, n2] =
|
|
* co_await asio::async_write(socket,
|
|
* asio::buffer(data, n1),
|
|
* asio::as_tuple(asio::deferred));
|
|
*
|
|
* if (e2)
|
|
* co_yield state.complete(e2);
|
|
* }
|
|
* }, socket),
|
|
* token, std::ref(socket));
|
|
* } @endcode
|
|
*
|
|
* This next example shows exception-based error handling and implicit checks
|
|
* for cancellation. The completion handler is invoked after returning from the
|
|
* coroutine via @c co_return. Valid @c co_return values are specified using
|
|
* completion signatures passed to the @c co_composed function.
|
|
*
|
|
* @code template <typename CompletionToken>
|
|
* auto async_echo(tcp::socket& socket,
|
|
* CompletionToken&& token)
|
|
* {
|
|
* return asio::async_initiate<
|
|
* CompletionToken, void(std::error_code)>(
|
|
* asio::experimental::co_composed<
|
|
* void(std::error_code)>(
|
|
* [](auto state, tcp::socket& socket) -> void
|
|
* {
|
|
* try
|
|
* {
|
|
* state.throw_if_cancelled(true);
|
|
* state.reset_cancellation_state(
|
|
* asio::enable_terminal_cancellation());
|
|
*
|
|
* for (;;)
|
|
* {
|
|
* char data[1024];
|
|
* std::size_t n = co_await socket.async_read_some(
|
|
* asio::buffer(data), asio::deferred);
|
|
*
|
|
* co_await asio::async_write(socket,
|
|
* asio::buffer(data, n), asio::deferred);
|
|
* }
|
|
* }
|
|
* catch (const std::system_error& e)
|
|
* {
|
|
* co_return {e.code()};
|
|
* }
|
|
* }, socket),
|
|
* token, std::ref(socket));
|
|
* } @endcode
|
|
*/
|
|
template <completion_signature... Signatures,
|
|
typename Implementation, typename... IoObjectsOrExecutors>
|
|
auto co_composed(Implementation&& implementation,
|
|
IoObjectsOrExecutors&&... io_objects_or_executors);
|
|
|
|
} // namespace experimental
|
|
} // namespace asio
|
|
|
|
#include "asio/detail/pop_options.hpp"
|
|
|
|
#include "asio/experimental/impl/co_composed.hpp"
|
|
|
|
#endif // ASIO_EXPERIMENTAL_CO_COMPOSED_HPP
|