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
|