// // experimental/detail/partial_promise.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_PARTIAL_PROMISE_HPP #define ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP #include "asio/detail/config.hpp" #include "asio/append.hpp" #include "asio/awaitable.hpp" #include "asio/experimental/coro_traits.hpp" #if defined(ASIO_HAS_STD_COROUTINE) # include #else // defined(ASIO_HAS_STD_COROUTINE) # include #endif // defined(ASIO_HAS_STD_COROUTINE) namespace asio { namespace experimental { namespace detail { #if defined(ASIO_HAS_STD_COROUTINE) using std::coroutine_handle; using std::coroutine_traits; using std::suspend_never; using std::suspend_always; using std::noop_coroutine; #else // defined(ASIO_HAS_STD_COROUTINE) using std::experimental::coroutine_handle; using std::experimental::coroutine_traits; using std::experimental::suspend_never; using std::experimental::suspend_always; using std::experimental::noop_coroutine; #endif // defined(ASIO_HAS_STD_COROUTINE) struct partial_coro { coroutine_handle handle{nullptr}; }; template struct partial_promise_base { template void* operator new(const std::size_t size, Executor&, Token& tk, Args&...) { return allocate_coroutine(size, get_associated_allocator(tk)); } void operator delete(void* raw, const std::size_t size) { deallocate_coroutine(raw, size); } }; template <> struct partial_promise_base> { }; template struct partial_promise : partial_promise_base { auto initial_suspend() noexcept { return asio::detail::suspend_always{}; } auto final_suspend() noexcept { struct awaitable_t { partial_promise *p; constexpr bool await_ready() noexcept { return true; } auto await_suspend(asio::detail::coroutine_handle<>) noexcept { p->get_return_object().handle.destroy(); } constexpr void await_resume() noexcept {} }; return awaitable_t{this}; } void return_void() {} partial_coro get_return_object() { return partial_coro{coroutine_handle::from_promise(*this)}; } void unhandled_exception() { assert(false); } }; }; // namespace detail } // namespace experimental } // namespace asio #if defined(ASIO_HAS_STD_COROUTINE) namespace std { template struct coroutine_traits< asio::experimental::detail::partial_coro, Executor, Completion, Args...> { using promise_type = asio::experimental::detail::partial_promise< asio::associated_allocator_t>; }; } // namespace std #else // defined(ASIO_HAS_STD_COROUTINE) namespace std { namespace experimental { template struct coroutine_traits< asio::experimental::detail::partial_coro, Executor, Completion, Args...> { using promise_type = asio::experimental::detail::partial_promise< asio::associated_allocator_t>; }; }} // namespace std::experimental #endif // defined(ASIO_HAS_STD_COROUTINE) namespace asio { namespace experimental { namespace detail { template partial_coro post_coroutine(Executor exec, CompletionToken token, Args&&... args) noexcept { post(exec, asio::append(std::move(token), std::move(args)...)); co_return; } template partial_coro post_coroutine(Context& ctx, CompletionToken token, Args&&... args) noexcept { post(ctx, asio::append(std::move(token), std::move(args)...)); co_return; } template partial_coro dispatch_coroutine(Executor exec, CompletionToken token, Args&&... args) noexcept { dispatch(exec, asio::append(std::move(token), std::move(args)...)); co_return; } template partial_coro dispatch_coroutine(Context& ctx, CompletionToken token, Args &&... args) noexcept { dispatch(ctx, asio::append(std::move(token), std::move(args)...)); co_return; } } // namespace detail } // namespace experimental } // namespace asio #endif // ASIO_EXPERIMENTAL_DETAIL_PARTIAL_PROMISE_HPP