TLA Line data Source 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 : */
107 HIT 4 : asio_spawn_op(Executor executor, Awaitable awaitable)
108 4 : : executor_(std::move(executor)), awaitable_(std::move(awaitable))
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>
118 4 : auto operator()(Token && token)
119 : {
120 6 : return detail::initialize_asio_spawn_helper<Awaitable, Token>::init(
121 4 : std::move(executor_),
122 4 : std::move(awaitable_),
123 : std::forward<Token>(token)
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>
185 4 : auto asio_spawn(ExecutorType exec, Awaitable && awaitable)
186 : {
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
|