coro_traits.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //
  2. // experimental/detail/coro_traits.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2021-2023 Klemens D. Morgenstern
  6. // (klemens dot morgenstern at gmx dot net)
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. #ifndef ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP
  12. #define ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include "asio/detail/config.hpp"
  17. #include <optional>
  18. #include <variant>
  19. #include "asio/any_io_executor.hpp"
  20. namespace asio {
  21. namespace experimental {
  22. namespace detail {
  23. template <class From, class To>
  24. concept convertible_to = std::is_convertible_v<From, To>;
  25. template <typename T>
  26. concept decays_to_executor = execution::executor<std::decay_t<T>>;
  27. template <typename T, typename Executor = any_io_executor>
  28. concept execution_context = requires (T& t)
  29. {
  30. {t.get_executor()} -> convertible_to<Executor>;
  31. };
  32. template <typename Yield, typename Return>
  33. struct coro_result
  34. {
  35. using type = std::variant<Yield, Return>;
  36. };
  37. template <typename Yield>
  38. struct coro_result<Yield, void>
  39. {
  40. using type = std::optional<Yield>;
  41. };
  42. template <typename Return>
  43. struct coro_result<void, Return>
  44. {
  45. using type = Return;
  46. };
  47. template <typename YieldReturn>
  48. struct coro_result<YieldReturn, YieldReturn>
  49. {
  50. using type = YieldReturn;
  51. };
  52. template <>
  53. struct coro_result<void, void>
  54. {
  55. using type = void;
  56. };
  57. template <typename Yield, typename Return>
  58. using coro_result_t = typename coro_result<Yield, Return>::type;
  59. template <typename Result, bool IsNoexcept>
  60. struct coro_handler;
  61. template <>
  62. struct coro_handler<void, false>
  63. {
  64. using type = void(std::exception_ptr);
  65. };
  66. template <>
  67. struct coro_handler<void, true>
  68. {
  69. using type = void();
  70. };
  71. template <typename T>
  72. struct coro_handler<T, false>
  73. {
  74. using type = void(std::exception_ptr, T);
  75. };
  76. template <typename T>
  77. struct coro_handler<T, true>
  78. {
  79. using type = void(T);
  80. };
  81. template <typename Result, bool IsNoexcept>
  82. using coro_handler_t = typename coro_handler<Result, IsNoexcept>::type;
  83. } // namespace detail
  84. #if defined(GENERATING_DOCUMENTATION)
  85. /// The traits describing the resumable coroutine behaviour.
  86. /**
  87. * Template parameter @c Yield specifies type or signature used by co_yield,
  88. * @c Return specifies the type used for co_return, and @c Executor specifies
  89. * the underlying executor type.
  90. */
  91. template <typename Yield, typename Return, typename Executor>
  92. struct coro_traits
  93. {
  94. /// The value that can be passed into a symmetrical cororoutine. @c void if
  95. /// asymmetrical.
  96. using input_type = argument_dependent;
  97. /// The type that can be passed out through a co_yield.
  98. using yield_type = argument_dependent;
  99. /// The type that can be passed out through a co_return.
  100. using return_type = argument_dependent;
  101. /// The type received by a co_await or async_resume. It's a combination of
  102. /// yield and return.
  103. using result_type = argument_dependent;
  104. /// The signature used by the async_resume.
  105. using signature_type = argument_dependent;
  106. /// Whether or not the coroutine is noexcept.
  107. constexpr static bool is_noexcept = argument_dependent;
  108. /// The error type of the coroutine. @c void for noexcept.
  109. using error_type = argument_dependent;
  110. /// Completion handler type used by async_resume.
  111. using completion_handler = argument_dependent;
  112. };
  113. #else // defined(GENERATING_DOCUMENTATION)
  114. template <typename Yield, typename Return, typename Executor>
  115. struct coro_traits
  116. {
  117. using input_type = void;
  118. using yield_type = Yield;
  119. using return_type = Return;
  120. using result_type = detail::coro_result_t<yield_type, return_type>;
  121. using signature_type = result_type();
  122. constexpr static bool is_noexcept = false;
  123. using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>;
  124. using completion_handler = detail::coro_handler_t<result_type, is_noexcept>;
  125. };
  126. template <typename T, typename Return, typename Executor>
  127. struct coro_traits<T(), Return, Executor>
  128. {
  129. using input_type = void;
  130. using yield_type = T;
  131. using return_type = Return;
  132. using result_type = detail::coro_result_t<yield_type, return_type>;
  133. using signature_type = result_type();
  134. constexpr static bool is_noexcept = false;
  135. using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>;
  136. using completion_handler = detail::coro_handler_t<result_type, is_noexcept>;
  137. };
  138. template <typename T, typename Return, typename Executor>
  139. struct coro_traits<T() noexcept, Return, Executor>
  140. {
  141. using input_type = void;
  142. using yield_type = T;
  143. using return_type = Return;
  144. using result_type = detail::coro_result_t<yield_type, return_type>;
  145. using signature_type = result_type();
  146. constexpr static bool is_noexcept = true;
  147. using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>;
  148. using completion_handler = detail::coro_handler_t<result_type, is_noexcept>;
  149. };
  150. template <typename T, typename U, typename Return, typename Executor>
  151. struct coro_traits<T(U), Return, Executor>
  152. {
  153. using input_type = U;
  154. using yield_type = T;
  155. using return_type = Return;
  156. using result_type = detail::coro_result_t<yield_type, return_type>;
  157. using signature_type = result_type(input_type);
  158. constexpr static bool is_noexcept = false;
  159. using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>;
  160. using completion_handler = detail::coro_handler_t<result_type, is_noexcept>;
  161. };
  162. template <typename T, typename U, typename Return, typename Executor>
  163. struct coro_traits<T(U) noexcept, Return, Executor>
  164. {
  165. using input_type = U;
  166. using yield_type = T;
  167. using return_type = Return;
  168. using result_type = detail::coro_result_t<yield_type, return_type>;
  169. using signature_type = result_type(input_type);
  170. constexpr static bool is_noexcept = true;
  171. using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>;
  172. using completion_handler = detail::coro_handler_t<result_type, is_noexcept>;
  173. };
  174. template <typename Executor>
  175. struct coro_traits<void() noexcept, void, Executor>
  176. {
  177. using input_type = void;
  178. using yield_type = void;
  179. using return_type = void;
  180. using result_type = detail::coro_result_t<yield_type, return_type>;
  181. using signature_type = result_type(input_type);
  182. constexpr static bool is_noexcept = true;
  183. using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>;
  184. using completion_handler = detail::coro_handler_t<result_type, is_noexcept>;
  185. };
  186. #endif // defined(GENERATING_DOCUMENTATION)
  187. } // namespace experimental
  188. } // namespace asio
  189. #endif // ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP