229 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			229 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //
 | ||
|  | // experimental/detail/coro_traits.hpp
 | ||
|  | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
|  | //
 | ||
|  | // Copyright (c) 2021-2023 Klemens D. Morgenstern
 | ||
|  | //                         (klemens dot morgenstern at gmx dot net)
 | ||
|  | //
 | ||
|  | // 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_DETAIL_CORO_TRAITS_HPP
 | ||
|  | #define ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP
 | ||
|  | 
 | ||
|  | #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 | ||
|  | # pragma once
 | ||
|  | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 | ||
|  | 
 | ||
|  | #include "asio/detail/config.hpp"
 | ||
|  | #include <optional>
 | ||
|  | #include <variant>
 | ||
|  | #include "asio/any_io_executor.hpp"
 | ||
|  | 
 | ||
|  | namespace asio { | ||
|  | namespace experimental { | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | template <class From, class To> | ||
|  | concept convertible_to = std::is_convertible_v<From, To>; | ||
|  | 
 | ||
|  | template <typename T> | ||
|  | concept decays_to_executor = execution::executor<std::decay_t<T>>; | ||
|  | 
 | ||
|  | template <typename T, typename Executor = any_io_executor> | ||
|  | concept execution_context = requires (T& t) | ||
|  | { | ||
|  |   {t.get_executor()} -> convertible_to<Executor>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Yield, typename Return> | ||
|  | struct coro_result | ||
|  | { | ||
|  |   using type = std::variant<Yield, Return>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Yield> | ||
|  | struct coro_result<Yield, void> | ||
|  | { | ||
|  |   using type = std::optional<Yield>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Return> | ||
|  | struct coro_result<void, Return> | ||
|  | { | ||
|  |   using type = Return; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename YieldReturn> | ||
|  | struct coro_result<YieldReturn, YieldReturn> | ||
|  | { | ||
|  |   using type = YieldReturn; | ||
|  | }; | ||
|  | 
 | ||
|  | template <> | ||
|  | struct coro_result<void, void> | ||
|  | { | ||
|  |   using type = void; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Yield, typename Return> | ||
|  | using coro_result_t = typename coro_result<Yield, Return>::type; | ||
|  | 
 | ||
|  | template <typename Result, bool IsNoexcept> | ||
|  | struct coro_handler; | ||
|  | 
 | ||
|  | template <> | ||
|  | struct coro_handler<void, false> | ||
|  | { | ||
|  |   using type = void(std::exception_ptr); | ||
|  | }; | ||
|  | 
 | ||
|  | template <> | ||
|  | struct coro_handler<void, true> | ||
|  | { | ||
|  |   using type = void(); | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename T> | ||
|  | struct coro_handler<T, false> | ||
|  | { | ||
|  |   using type = void(std::exception_ptr, T); | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename T> | ||
|  | struct coro_handler<T, true> | ||
|  | { | ||
|  |   using type = void(T); | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Result, bool IsNoexcept> | ||
|  | using coro_handler_t = typename coro_handler<Result, IsNoexcept>::type; | ||
|  | 
 | ||
|  | } // namespace detail
 | ||
|  | 
 | ||
|  | #if defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | /// The traits describing the resumable coroutine behaviour.
 | ||
|  | /**
 | ||
|  |  * Template parameter @c Yield specifies type or signature used by co_yield, | ||
|  |  * @c Return specifies the type used for co_return, and @c Executor specifies | ||
|  |  * the underlying executor type. | ||
|  |  */ | ||
|  | template <typename Yield, typename Return, typename Executor> | ||
|  | struct coro_traits | ||
|  | { | ||
|  |   /// The value that can be passed into a symmetrical cororoutine. @c void if
 | ||
|  |   /// asymmetrical.
 | ||
|  |   using input_type = argument_dependent; | ||
|  | 
 | ||
|  |   /// The type that can be passed out through a co_yield.
 | ||
|  |   using yield_type = argument_dependent; | ||
|  | 
 | ||
|  |   /// The type that can be passed out through a co_return.
 | ||
|  |   using return_type = argument_dependent; | ||
|  | 
 | ||
|  |   /// The type received by a co_await or async_resume. It's a combination of
 | ||
|  |   /// yield and return.
 | ||
|  |   using result_type = argument_dependent; | ||
|  | 
 | ||
|  |   /// The signature used by the async_resume.
 | ||
|  |   using signature_type = argument_dependent; | ||
|  | 
 | ||
|  |   /// Whether or not the coroutine is noexcept.
 | ||
|  |   constexpr static bool is_noexcept = argument_dependent; | ||
|  | 
 | ||
|  |   /// The error type of the coroutine. @c void for noexcept.
 | ||
|  |   using error_type = argument_dependent; | ||
|  | 
 | ||
|  |   /// Completion handler type used by async_resume.
 | ||
|  |   using completion_handler = argument_dependent; | ||
|  | }; | ||
|  | 
 | ||
|  | #else // defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | template <typename Yield, typename Return, typename Executor> | ||
|  | struct coro_traits | ||
|  | { | ||
|  |   using input_type  = void; | ||
|  |   using yield_type  = Yield; | ||
|  |   using return_type = Return; | ||
|  |   using result_type = detail::coro_result_t<yield_type, return_type>; | ||
|  |   using signature_type = result_type(); | ||
|  |   constexpr static bool is_noexcept = false; | ||
|  |   using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; | ||
|  |   using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename T, typename Return, typename Executor> | ||
|  | struct coro_traits<T(), Return, Executor> | ||
|  | { | ||
|  |   using input_type = void; | ||
|  |   using yield_type = T; | ||
|  |   using return_type = Return; | ||
|  |   using result_type = detail::coro_result_t<yield_type, return_type>; | ||
|  |   using signature_type = result_type(); | ||
|  |   constexpr static bool is_noexcept = false; | ||
|  |   using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; | ||
|  |   using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename T, typename Return, typename Executor> | ||
|  | struct coro_traits<T() noexcept, Return, Executor> | ||
|  | { | ||
|  |   using input_type = void; | ||
|  |   using yield_type = T; | ||
|  |   using return_type = Return; | ||
|  |   using result_type = detail::coro_result_t<yield_type, return_type>; | ||
|  |   using signature_type = result_type(); | ||
|  |   constexpr static bool is_noexcept = true; | ||
|  |   using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; | ||
|  |   using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename T, typename U, typename Return, typename Executor> | ||
|  | struct coro_traits<T(U), Return, Executor> | ||
|  | { | ||
|  |   using input_type = U; | ||
|  |   using yield_type = T; | ||
|  |   using return_type = Return; | ||
|  |   using result_type = detail::coro_result_t<yield_type, return_type>; | ||
|  |   using signature_type = result_type(input_type); | ||
|  |   constexpr static bool is_noexcept = false; | ||
|  |   using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; | ||
|  |   using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename T, typename U, typename Return, typename Executor> | ||
|  | struct coro_traits<T(U) noexcept, Return, Executor> | ||
|  | { | ||
|  |   using input_type = U; | ||
|  |   using yield_type = T; | ||
|  |   using return_type = Return; | ||
|  |   using result_type = detail::coro_result_t<yield_type, return_type>; | ||
|  |   using signature_type = result_type(input_type); | ||
|  |   constexpr static bool is_noexcept = true; | ||
|  |   using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; | ||
|  |   using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor> | ||
|  | struct coro_traits<void() noexcept, void, Executor> | ||
|  | { | ||
|  |   using input_type = void; | ||
|  |   using yield_type = void; | ||
|  |   using return_type = void; | ||
|  |   using result_type = detail::coro_result_t<yield_type, return_type>; | ||
|  |   using signature_type = result_type(input_type); | ||
|  |   constexpr static bool is_noexcept = true; | ||
|  |   using error_type = std::conditional_t<is_noexcept, void, std::exception_ptr>; | ||
|  |   using completion_handler = detail::coro_handler_t<result_type, is_noexcept>; | ||
|  | }; | ||
|  | 
 | ||
|  | #endif // defined(GENERATING_DOCUMENTATION)
 | ||
|  | 
 | ||
|  | } // namespace experimental
 | ||
|  | } // namespace asio
 | ||
|  | 
 | ||
|  | #endif // ASIO_EXPERIMENTAL_DETAIL_CORO_TRAITS_HPP
 |