co_composed.hpp 5.1 KB

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