100.00% Lines (10/10) 100.00% Functions (3/3)
TLA Baseline Branch
Line Hits Code Line Hits Code
  1 + //
  2 + // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
  3 + //
  4 + // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5 + // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6 + //
  7 + // Official repository: https://github.com/cppalliance/capy
  8 + //
  9 +
  10 + #ifndef BOOST_CAPY_ASIO_SPAWN_HPP
  11 + #define BOOST_CAPY_ASIO_SPAWN_HPP
  12 +
  13 +
  14 + #include <boost/capy/asio/executor_adapter.hpp>
  15 + #include <boost/capy/asio/detail/completion_traits.hpp>
  16 + #include <boost/capy/ex/frame_allocator.hpp>
  17 + #include <boost/capy/concept/execution_context.hpp>
  18 + #include <boost/capy/concept/executor.hpp>
  19 + #include <boost/capy/concept/io_awaitable.hpp>
  20 +
  21 +
  22 + namespace boost::capy
  23 + {
  24 +
  25 + /** @addtogroup asio
  26 + * @{
  27 + */
  28 +
  29 + namespace detail
  30 + {
  31 +
  32 + /** @brief Helper for initializing spawned coroutines with Boost.Asio tokens.
  33 + * @internal
  34 + *
  35 + * Specialized in `boost.hpp` for actual Boost.Asio completion tokens.
  36 + */
  37 + template<typename Awaitable, typename Token>
  38 + struct initialize_asio_spawn_helper;
  39 +
  40 + /** @brief Concept for valid Boost.Asio spawn completion tokens.
  41 + * @internal
  42 + *
  43 + * A token satisfies this concept if `initialize_asio_spawn_helper` can
  44 + * initialize the spawn operation with it.
  45 + */
  46 + template<typename Token, typename Executor, typename Awaitable>
  47 + concept asio_spawn_token =
  48 + requires (Token && tk, Executor ex, Awaitable rn)
  49 + {
  50 + initialize_asio_spawn_helper<Awaitable, Token>::
  51 + init(std::move(ex), std::move(rn), std::forward<Token>(tk));
  52 + };
  53 +
  54 + /** @brief Helper for initializing spawned coroutines with standalone Asio tokens.
  55 + * @internal
  56 + *
  57 + * Specialized in `standalone.hpp` for actual standalone Asio completion tokens.
  58 + */
  59 + template<typename Awaitable, typename Token>
  60 + struct initialize_asio_standalone_spawn_helper;
  61 +
  62 + /** @brief Concept for valid standalone Asio spawn completion tokens.
  63 + * @internal
  64 + *
  65 + * A token satisfies this concept if `initialize_asio_standalone_spawn_helper`
  66 + * can initialize the spawn operation with it.
  67 + */
  68 + template<typename Token, typename Executor, typename Awaitable>
  69 + concept asio_standalone_spawn_token =
  70 + requires (Token && tk, Executor ex, Awaitable rn)
  71 + {
  72 + initialize_asio_standalone_spawn_helper<Awaitable, Token>::
  73 + init(std::move(ex), std::move(rn), std::forward<Token>(tk));
  74 + };
  75 +
  76 +
  77 + }
  78 +
  79 + /** @brief Deferred spawn operation that can be initiated with a completion token.
  80 + *
  81 + * This class represents a spawn operation that has captured an executor and
  82 + * awaitable but hasn't been initiated yet. Call `operator()` with a completion
  83 + * token to start the operation.
  84 + *
  85 + * @tparam Executor The executor type for running the coroutine
  86 + * @tparam Awaitable The coroutine type (must satisfy `IoAwaitable`)
  87 + *
  88 + * @par Example
  89 + * @code
  90 + * auto op = asio_spawn(executor, my_coroutine());
  91 + *
  92 + * // Initiate with different tokens:
  93 + * op(asio::detached); // Fire and forget
  94 + * op([](std::exception_ptr) { ... }); // Callback on completion
  95 + * co_await op(asio::use_awaitable); // Await in another coroutine
  96 + * @endcode
  97 + *
  98 + * @see asio_spawn Factory function to create spawn operations
  99 + */
  100 + template<Executor Executor, IoAwaitable Awaitable>
  101 + struct asio_spawn_op
  102 + {
  103 + /** @brief Constructs the spawn operation.
  104 + * @param executor The executor to run on
  105 + * @param awaitable The coroutine to spawn
  106 + */
HITGNC   107 + 4 asio_spawn_op(Executor executor, Awaitable awaitable)
HITGNC   108 + 4 : executor_(std::move(executor)), awaitable_(std::move(awaitable))
HITGNC   109 + 4 {}
  110 +
  111 + /** @brief Initiates the spawn with a Boost.Asio completion token.
  112 + *
  113 + * @tparam Token A valid Boost.Asio completion token
  114 + * @param token The completion token determining how to handle completion
  115 + * @return Depends on the token (e.g., void for callbacks, awaitable for use_awaitable)
  116 + */
  117 + template<detail::asio_spawn_token<Executor, Awaitable> Token>
HITGNC   118 + 4 auto operator()(Token && token)
  119 + {
HITGNC   120 + 6 return detail::initialize_asio_spawn_helper<Awaitable, Token>::init(
HITGNC   121 + 4 std::move(executor_),
HITGNC   122 + 4 std::move(awaitable_),
  123 + std::forward<Token>(token)
HITGNC   124 + 6 );
  125 + }
  126 +
  127 + /** @brief Initiates the spawn with a standalone Asio completion token.
  128 + *
  129 + * @tparam Token A valid standalone Asio completion token
  130 + * @param token The completion token determining how to handle completion
  131 + * @return Depends on the token
  132 + */
  133 + template<detail::asio_standalone_spawn_token<Executor, Awaitable> Token>
  134 + auto operator()(Token && token)
  135 + {
  136 + return detail::initialize_asio_standalone_spawn_helper<Awaitable, Token>::init
  137 + (
  138 + std::move(executor_),
  139 + std::move(awaitable_),
  140 + std::forward<Token>(token)
  141 + );
  142 + }
  143 +
  144 + private:
  145 + Executor executor_;
  146 + Awaitable awaitable_;
  147 + };
  148 +
  149 +
  150 + /** @brief Spawns a capy coroutine for execution with an Asio completion token.
  151 + *
  152 + * Creates a deferred spawn operation that can be initiated with any Asio
  153 + * completion token. The coroutine will run on the specified executor.
  154 + *
  155 + * @tparam ExecutorType The executor type (must satisfy `Executor`)
  156 + * @tparam Awaitable The coroutine type (must satisfy `IoAwaitable`)
  157 + * @param exec The executor to run the coroutine on
  158 + * @param awaitable The coroutine to spawn
  159 + * @return An `asio_spawn_op` that can be called with a completion token
  160 + *
  161 + * @par Completion Signature
  162 + * The completion signature depends on the coroutine's return type:
  163 + * - `void` return, noexcept: `void()`
  164 + * - `void` return, may throw: `void(std::exception_ptr)`
  165 + * - `T` return, noexcept: `void(T)`
  166 + * - `T` return, may throw: `void(std::exception_ptr, T)`
  167 + *
  168 + * @par Example
  169 + * @code
  170 + * capy::task<int> compute() { co_return 42; }
  171 + *
  172 + * // Using with Boost.Asio
  173 + * asio_spawn(executor, compute())(
  174 + * [](std::exception_ptr ep, int result) {
  175 + * if (!ep) std::cout << "Result: " << result << "\n";
  176 + * });
  177 + *
  178 + * // Using with asio::use_awaitable
  179 + * auto [ep, result] = co_await asio_spawn(executor, compute())(asio::use_awaitable);
  180 + * @endcode
  181 + *
  182 + * @see asio_spawn_op The returned operation type
  183 + */
  184 + template<Executor ExecutorType, IoAwaitable Awaitable>
HITGNC   185 + 4 auto asio_spawn(ExecutorType exec, Awaitable && awaitable)
  186 + {
HITGNC   187 + 4 return asio_spawn_op(std::move(exec), std::forward<Awaitable>(awaitable));
  188 + }
  189 +
  190 + /** @brief Spawns a capy coroutine using a context's executor.
  191 + *
  192 + * Convenience overload that extracts the executor from an execution context.
  193 + *
  194 + * @tparam Context The execution context type (must satisfy `ExecutionContext`)
  195 + * @tparam Awaitable The coroutine type (must satisfy `IoAwaitable`)
  196 + * @param ctx The execution context providing the executor
  197 + * @param awaitable The coroutine to spawn
  198 + * @return An `asio_spawn_op` that can be called with a completion token
  199 + *
  200 + * @par Example
  201 + * @code
  202 + * boost::asio::io_context io;
  203 + * asio_spawn(io, my_coroutine())(asio::detached);
  204 + * io.run();
  205 + * @endcode
  206 + */
  207 + template<ExecutionContext Context, IoAwaitable Awaitable>
  208 + auto asio_spawn(Context & ctx, Awaitable && awaitable)
  209 + {
  210 + return asio_spawn_op(ctx.get_executor(), std::forward<Awaitable>(awaitable));
  211 + }
  212 +
  213 + /** @} */ // end of asio group
  214 +
  215 + }
  216 +
  217 + #endif