include/boost/capy/asio/executor_from_asio.hpp

94.1% Lines (32/34) 88.9% List of functions (8/9)
executor_from_asio.hpp
f(x) Functions (9)
Function Calls Lines Blocks
boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::asio_net_ts_executor(boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>) :113 2x 100.0% 100.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::asio_net_ts_executor(boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >&&) :120 10x 100.0% 100.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::asio_net_ts_executor(boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> > const&) :127 1x 100.0% 100.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::context() const :140 6x 100.0% 100.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::on_work_started() const :153 10x 100.0% 100.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::on_work_finished() const :162 12x 100.0% 100.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::dispatch(boost::capy::continuation&) const :174 5x 100.0% 77.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::post(boost::capy::continuation&) const :190 2x 100.0% 70.0% boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::operator==(boost::capy::asio_net_ts_executor<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> > const&) const :199 0 66.7% 0.0%
Line TLA Hits 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_EXECUTOR_FROM_ASIO_HPP
11 #define BOOST_CAPY_ASIO_EXECUTOR_FROM_ASIO_HPP
12
13 #include <boost/capy/asio/detail/asio_context_service.hpp>
14 #include <boost/capy/asio/detail/asio_coroutine_unique_handle.hpp>
15 #include <boost/capy/asio/detail/fwd.hpp>
16 #include <boost/capy/ex/frame_allocator.hpp>
17
18
19 #include <memory_resource>
20 #include <type_traits>
21
22 namespace boost {
23 namespace capy {
24
25 /** @addtogroup asio
26 * @{
27 */
28
29 namespace detail
30 {
31
32 /** @brief Concept for legacy Networking TS style Asio executors.
33 * @internal
34 *
35 * Matches executors that provide the original Networking TS executor interface
36 * with explicit work counting (`on_work_started`/`on_work_finished`) and
37 * `dispatch`/`post` methods that take a handler and allocator.
38 *
39 * @tparam Executor The type to check
40 */
41 template<typename Executor>
42 concept AsioNetTsExecutor = requires (Executor exec,
43 std::coroutine_handle<> h,
44 std::pmr::polymorphic_allocator<void> a)
45 {
46 exec.on_work_started();
47 exec.on_work_finished();
48 exec.dispatch(h, a);
49 exec.post(h, a);
50 exec.context();
51 } ;
52
53 /** @brief Concept for Boost.Asio standard executors.
54 * @internal
55 *
56 * Matches executors compatible with the P0443/P2300 executor model as
57 * implemented in Boost.Asio. These executors use the property query/require
58 * mechanism and return `boost::asio::execution_context&` from context queries.
59 *
60 * @tparam Executor The type to check
61 */
62 template<typename Executor>
63 concept AsioBoostStandardExecutor = std::same_as<
64 typename boost::asio::query_result<
65 Executor,
66 boost::asio::execution::detail::context_t<0>>::type,
67 boost::asio::execution_context&>;
68
69 /** @brief Concept for standalone Asio standard executors.
70 * @internal
71 *
72 * Matches executors compatible with the P0443/P2300 executor model as
73 * implemented in standalone Asio. These executors return
74 * `::asio::execution_context&` from context queries.
75 *
76 * @tparam Executor The type to check
77 */
78 template<typename Executor>
79 concept AsioStandaloneStandardExecutor = std::same_as<
80 typename ::asio::query_result<
81 Executor,
82 ::asio::execution::detail::context_t<0>>::type,
83 ::asio::execution_context&>;
84
85 }
86
87
88 /** @brief Wraps a legacy Networking TS executor for use with capy.
89 *
90 * This class adapts Asio executors that follow the original Networking TS
91 * executor model (with `on_work_started`/`on_work_finished` and
92 * `dispatch`/`post` methods) to be usable as capy executors.
93 *
94 * @tparam Executor An executor type satisfying `AsioNetTsExecutor`
95 *
96 * @par Example
97 * @code
98 * boost::asio::io_context io;
99 * auto wrapped = asio_net_ts_executor(io.get_executor());
100 *
101 * // Use with capy coroutines
102 * capy::run(wrapped, my_coroutine());
103 * @endcode
104 *
105 * @see wrap_asio_executor For automatic executor type detection
106 */
107 template<detail::AsioNetTsExecutor Executor>
108 struct asio_net_ts_executor
109 {
110 /** @brief Constructs from an Asio Net.TS executor.
111 * @param executor The Asio executor to wrap
112 */
113 2x asio_net_ts_executor(Executor executor)
114 noexcept(std::is_nothrow_move_constructible_v<Executor>)
115 2x : executor_(std::move(executor))
116 {
117 2x }
118
119 /** @brief Move constructor. */
120 10x asio_net_ts_executor(asio_net_ts_executor && rhs)
121 noexcept(std::is_nothrow_move_constructible_v<Executor>)
122 10x : executor_(std::move(rhs.executor_))
123 {
124 10x }
125
126 /** @brief Copy constructor. */
127 1x asio_net_ts_executor(const asio_net_ts_executor & rhs)
128 noexcept(std::is_nothrow_copy_constructible_v<Executor>)
129 1x : executor_(rhs.executor_)
130 {
131 1x }
132
133 /** @brief Returns the associated capy execution context.
134 *
135 * The context is obtained via an `asio_context_service` registered
136 * with the underlying Asio execution context.
137 *
138 * @return Reference to the capy execution_context
139 */
140 6x execution_context& context() const noexcept
141 {
142 using ex_t = std::remove_reference_t<decltype(executor_.context())>;
143 return use_service<detail::asio_context_service<ex_t>>
144 6x (
145 executor_.context()
146 6x );
147 }
148
149 /** @brief Notifies that work has started.
150 *
151 * Forwards to the underlying executor's `on_work_started()`.
152 */
153 10x void on_work_started() const noexcept
154 {
155 10x executor_.on_work_started();
156 10x }
157
158 /** @brief Notifies that work has finished.
159 *
160 * Forwards to the underlying executor's `on_work_finished()`.
161 */
162 12x void on_work_finished() const noexcept
163 {
164 12x executor_.on_work_finished();
165 12x }
166
167 /** @brief Dispatches a continuation for execution.
168 *
169 * May execute inline if allowed by the executor, otherwise posts.
170 *
171 * @param c The continuation to dispatch
172 * @return A noop coroutine handle (execution is delegated to Asio)
173 */
174 5x std::coroutine_handle<> dispatch(continuation & c) const
175 {
176 5x executor_.dispatch(
177 10x detail::asio_coroutine_unique_handle(c.h),
178 5x std::pmr::polymorphic_allocator<void>(
179 boost::capy::get_current_frame_allocator()));
180
181 5x return std::noop_coroutine();
182 }
183
184 /** @brief Posts a continuation for deferred execution.
185 *
186 * The continuation will never be executed inline.
187 *
188 * @param c The continuation to post
189 */
190 2x void post(continuation & c) const
191 {
192 2x executor_.post(
193 4x detail::asio_coroutine_unique_handle(c.h),
194 2x std::pmr::polymorphic_allocator<void>(
195 boost::capy::get_current_frame_allocator()));
196 2x }
197
198 /** @brief Equality comparison. */
199 bool operator==(const asio_net_ts_executor & rhs) const noexcept
200 {
201 return executor_ == rhs.executor_;
202 }
203
204 /** @brief Inequality comparison. */
205 bool operator!=(const asio_net_ts_executor & rhs) const noexcept
206 {
207 return executor_ != rhs.executor_;
208 }
209
210 private:
211 Executor executor_;
212 };
213
214
215 /** @brief Wraps a Boost.Asio standard executor for use with capy.
216 *
217 * Forward declaration; defined in `boost.hpp`.
218 *
219 * @tparam Executor An executor type satisfying `AsioBoostStandardExecutor`
220 * @see asio_net_ts_executor For legacy executor wrapping
221 */
222 template<detail::AsioBoostStandardExecutor Executor>
223 struct asio_boost_standard_executor;
224
225 /** @brief Wraps a standalone Asio standard executor for use with capy.
226 *
227 * Forward declaration; defined in `standalone.hpp`.
228 *
229 * @tparam Executor An executor type satisfying `AsioStandaloneStandardExecutor`
230 * @see asio_net_ts_executor For legacy executor wrapping
231 */
232 template<detail::AsioStandaloneStandardExecutor Executor>
233 struct asio_standalone_standard_executor;
234
235
236 /** @brief Automatically wraps any Asio executor for use with capy.
237 *
238 * This function detects the type of Asio executor and returns the appropriate
239 * capy-compatible wrapper:
240 * - Legacy Net.TS executors -> `asio_net_ts_executor`
241 * - Boost.Asio standard executors -> `asio_boost_standard_executor`
242 * - Standalone Asio standard executors -> `asio_standalone_standard_executor`
243 *
244 * @tparam Executor The Asio executor type (deduced)
245 * @param exec The Asio executor to wrap
246 * @return A capy-compatible executor wrapping the input
247 *
248 * @par Example
249 * @code
250 * boost::asio::io_context io;
251 * auto capy_exec = wrap_asio_executor(io.get_executor());
252 *
253 * // Now use with capy
254 * capy::run(capy_exec, my_io_task());
255 * @endcode
256 *
257 * @note Fails to compile with a static_assert if the executor type is not recognized.
258 */
259 template<typename Executor>
260 3x auto wrap_asio_executor(Executor && exec)
261 {
262 using executor_t = std::decay_t<Executor>;
263 if constexpr (detail::AsioNetTsExecutor<executor_t>)
264 return asio_net_ts_executor<executor_t>(
265 std::forward<Executor>(exec)
266 2x );
267 else if constexpr (detail::AsioBoostStandardExecutor<executor_t>)
268 return asio_boost_standard_executor<executor_t>(
269 1x std::forward<Executor>(exec)
270 1x );
271 else if constexpr (detail::AsioStandaloneStandardExecutor<executor_t>)
272 return asio_standalone_standard_executor<executor_t>(
273 std::forward<Executor>(exec)
274 );
275 else
276 static_assert(sizeof(Executor) == 0, "Unknown executor type");
277 };
278
279
280 /** @brief Type alias for the result of `wrap_asio_executor`.
281 *
282 * Given an Asio executor type, this alias yields the corresponding
283 * capy wrapper type.
284 *
285 * @tparam Executor The Asio executor type
286 */
287 template<typename Executor>
288 using wrap_asio_executor_t
289 = decltype(wrap_asio_executor(std::declval<const Executor &>()));
290
291 /** @} */ // end of asio group
292
293
294
295 }
296 }
297
298
299 #endif //BOOST_CAPY_ASIO_EXECUTOR_ADAPTER_HPP
300