co_composed.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //
  2. // experimental/co_composed.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_EXPERIMENTAL_CO_COMPOSED_HPP
  11. #define BOOST_ASIO_EXPERIMENTAL_CO_COMPOSED_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/async_result.hpp>
  17. #include <boost/asio/detail/push_options.hpp>
  18. namespace boost {
  19. namespace asio {
  20. namespace experimental {
  21. /// Creates an initiation function object that may be used to launch a
  22. /// coroutine-based composed asynchronous operation.
  23. /**
  24. * The experimental::co_composed utility simplifies the implementation of
  25. * composed asynchronous operations by automatically adapting a coroutine to be
  26. * an initiation function object for use with @c async_initiate. When awaiting
  27. * asynchronous operations, the coroutine automatically uses a conforming
  28. * intermediate completion handler.
  29. *
  30. * @param implementation A function object that contains the coroutine-based
  31. * implementation of the composed asynchronous operation. The first argument to
  32. * the function object represents the state of the operation, and may be used
  33. * to test for cancellation. The remaining arguments are those passed to @c
  34. * async_initiate after the completion token.
  35. *
  36. * @param io_objects_or_executors Zero or more I/O objects or I/O executors for
  37. * which outstanding work must be maintained while the operation is incomplete.
  38. *
  39. * @par Per-Operation Cancellation
  40. * By default, terminal per-operation cancellation is enabled for composed
  41. * operations that use experimental::co_composed. To disable cancellation for
  42. * the composed operation, or to alter its supported cancellation types, call
  43. * the state's @c reset_cancellation_state function.
  44. *
  45. * @par Examples
  46. * The following example illustrates manual error handling and explicit checks
  47. * for cancellation. The completion handler is invoked via a @c co_yield to the
  48. * state's @c complete function, which never returns.
  49. *
  50. * @code template <typename CompletionToken>
  51. * auto async_echo(tcp::socket& socket,
  52. * CompletionToken&& token)
  53. * {
  54. * return boost::asio::async_initiate<
  55. * CompletionToken, void(boost::system::error_code)>(
  56. * boost::asio::experimental::co_composed(
  57. * [](auto state, tcp::socket& socket) -> void
  58. * {
  59. * state.reset_cancellation_state(
  60. * boost::asio::enable_terminal_cancellation());
  61. *
  62. * while (!state.cancelled())
  63. * {
  64. * char data[1024];
  65. * auto [e1, n1] =
  66. * co_await socket.async_read_some(
  67. * boost::asio::buffer(data),
  68. * boost::asio::as_tuple(boost::asio::deferred));
  69. *
  70. * if (e1)
  71. * co_yield state.complete(e1);
  72. *
  73. * if (!!state.cancelled())
  74. * co_yield state.complete(
  75. * make_error_code(boost::asio::error::operation_aborted));
  76. *
  77. * auto [e2, n2] =
  78. * co_await boost::asio::async_write(socket,
  79. * boost::asio::buffer(data, n1),
  80. * boost::asio::as_tuple(boost::asio::deferred));
  81. *
  82. * if (e2)
  83. * co_yield state.complete(e2);
  84. * }
  85. * }, socket),
  86. * token, std::ref(socket));
  87. * } @endcode
  88. *
  89. * This next example shows exception-based error handling and implicit checks
  90. * for cancellation. The completion handler is invoked after returning from the
  91. * coroutine via @c co_return. Valid @c co_return values are specified using
  92. * completion signatures passed to the @c co_composed function.
  93. *
  94. * @code template <typename CompletionToken>
  95. * auto async_echo(tcp::socket& socket,
  96. * CompletionToken&& token)
  97. * {
  98. * return boost::asio::async_initiate<
  99. * CompletionToken, void(boost::system::error_code)>(
  100. * boost::asio::experimental::co_composed<
  101. * void(boost::system::error_code)>(
  102. * [](auto state, tcp::socket& socket) -> void
  103. * {
  104. * try
  105. * {
  106. * state.throw_if_cancelled(true);
  107. * state.reset_cancellation_state(
  108. * boost::asio::enable_terminal_cancellation());
  109. *
  110. * for (;;)
  111. * {
  112. * char data[1024];
  113. * std::size_t n = co_await socket.async_read_some(
  114. * boost::asio::buffer(data), boost::asio::deferred);
  115. *
  116. * co_await boost::asio::async_write(socket,
  117. * boost::asio::buffer(data, n), boost::asio::deferred);
  118. * }
  119. * }
  120. * catch (const boost::system::system_error& e)
  121. * {
  122. * co_return {e.code()};
  123. * }
  124. * }, socket),
  125. * token, std::ref(socket));
  126. * } @endcode
  127. */
  128. template <completion_signature... Signatures,
  129. typename Implementation, typename... IoObjectsOrExecutors>
  130. auto co_composed(Implementation&& implementation,
  131. IoObjectsOrExecutors&&... io_objects_or_executors);
  132. } // namespace experimental
  133. } // namespace asio
  134. } // namespace boost
  135. #include <boost/asio/detail/pop_options.hpp>
  136. #include <boost/asio/experimental/impl/co_composed.hpp>
  137. #endif // BOOST_ASIO_EXPERIMENTAL_CO_COMPOSED_HPP