include/boost/capy/asio/detail/completion_handler.hpp

91.0% Lines (61/67) 91.7% List of functions (33/36)
completion_handler.hpp
f(x) Functions (36)
Function Calls Lines Blocks
void boost::capy::detail::asio_immediate_executor_helper::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::binder2<boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>, boost::system::error_code, unsigned long>, boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0>, void> >(boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::binder2<boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>, boost::system::error_code, unsigned long>, boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0>, void>&&) const :40 2x 58.3% 44.0% boost::capy::detail::asio_immediate_executor_helper::asio_immediate_executor_helper(boost::capy::executor_ref, boost::capy::detail::asio_immediate_executor_helper::completed_immediately_t*) :80 2x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::get_allocator() const :101 8x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot>::get_allocator() const :101 2x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::get_executor() const :104 4x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot>::get_executor() const :104 1x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::get_cancellation_slot() const :107 2x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::get_immediate_executor() const :110 2x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::asio_coroutine_completion_handler(std::__n4861::coroutine_handle<void>, std::optional<std::tuple<boost::system::error_code, unsigned long> >&, boost::capy::io_env const*, boost::asio::cancellation_slot, boost::capy::detail::asio_immediate_executor_helper::completed_immediately_t*) :115 2x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot>::asio_coroutine_completion_handler(std::__n4861::coroutine_handle<void>, std::optional<std::tuple<> >&, boost::capy::io_env const*, boost::asio::cancellation_slot, boost::capy::detail::asio_immediate_executor_helper::completed_immediately_t*) :115 1x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::asio_coroutine_completion_handler(boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>&&) :127 16x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot>::asio_coroutine_completion_handler(boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot>&&) :127 10x 100.0% 100.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot, boost::system::error_code, unsigned long>::operator()(boost::system::error_code, unsigned long) :131 2x 87.5% 90.0% boost::capy::detail::asio_coroutine_completion_handler<boost::asio::cancellation_slot>::operator()() :131 1x 87.5% 88.0% boost::capy::detail::make_async_result(std::tuple<> const&) :161 1x 100.0% 100.0% auto boost::capy::detail::make_async_result<boost::system::error_code, unsigned long>(std::tuple<boost::system::error_code, unsigned long>&&) :164 2x 100.0% 100.0% auto boost::capy::detail::make_async_result<boost::system::error_code, unsigned long>(std::tuple<boost::system::error_code, unsigned long>&&)::{lambda(auto:1&&, (auto:2&&)...)#1}::operator()<boost::system::error_code, unsigned long>(boost::system::error_code&&, unsigned long&&) const :168 2x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >::cb::cb(boost::asio::cancellation_signal&) :194 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >::cb::cb(boost::asio::cancellation_signal&) :194 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::cb::cb(boost::asio::cancellation_signal&) :194 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >::cb::operator()() :195 0 0.0% 0.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >::cb::operator()() :195 0 0.0% 0.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::cb::operator()() :195 0 0.0% 0.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >::await_ready() const :199 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >::await_ready() const :199 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::await_ready() const :199 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :201 1x 91.7% 71.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :201 1x 91.7% 71.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :201 1x 100.0% 79.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >::await_resume() :225 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >::await_resume() :225 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::await_resume() :225 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >::awaitable_t(boost::asio::basic_readable_pipe<boost::asio::any_io_executor>::initiate_async_read_some, std::tuple<boost::capy::detail::asio_buffer_range<std::span<boost::capy::mutable_buffer const, 18446744073709551615ul> > >) :231 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type, boost::system::error_code, unsigned long>::awaitable_t<boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >::awaitable_t(boost::asio::basic_writable_pipe<boost::asio::any_io_executor>::initiate_async_write_some, std::tuple<boost::capy::detail::asio_buffer_range<std::span<boost::capy::const_buffer const, 18446744073709551615ul> > >) :231 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::awaitable_t(boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, std::tuple<boost::asio::detail::empty_work_function>) :231 1x 100.0% 100.0% boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>::awaitable_t(boost::capy::detail::async_result_impl<boost::asio::cancellation_signal, boost::asio::cancellation_type>::awaitable_t<boost::asio::detail::initiate_post_with_executor<boost::capy::asio_executor_adapter<boost::capy::executor_ref, std::pmr::polymorphic_allocator<void>, 0> >, boost::asio::detail::empty_work_function>&&) :236 1x 100.0% 100.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_DETAIL_COMPLETION_HANDLER_HPP
11 #define BOOST_CAPY_ASIO_DETAIL_COMPLETION_HANDLER_HPP
12
13 #include <boost/capy/asio/detail/asio_coroutine_unique_handle.hpp>
14 #include <boost/capy/asio/executor_adapter.hpp>
15 #include <boost/capy/ex/executor_ref.hpp>
16 #include <boost/capy/ex/io_env.hpp>
17 #include <boost/capy/io_result.hpp>
18
19
20 #include <memory_resource>
21 #include <optional>
22 #include <system_error>
23 #include <tuple>
24 #include <type_traits>
25
26 namespace boost::capy::detail
27 {
28
29 struct asio_immediate_executor_helper
30 {
31 enum completed_immediately_t
32 {
33 no, maybe, yes, initiating
34 };
35
36 executor_ref exec;
37 completed_immediately_t * completed_immediately = nullptr;
38
39 template<typename Fn>
40 2x void execute(Fn && fn) const
41 {
42 // only allow it when we're still initializing
43 2x if (completed_immediately &&
44 2x ((*completed_immediately == initiating)
45 || (*completed_immediately == maybe)))
46 {
47 // only use this indicator if the fn will actually call our handler
48 // otherwise this was a single op in a composed operation
49 2x *completed_immediately = maybe;
50 2x fn();
51
52 2x if (*completed_immediately != yes)
53 *completed_immediately = initiating;
54 }
55 else
56 {
57 exec.post(
58 make_continuation(
59 std::forward<Fn>(fn),
60 std::pmr::polymorphic_allocator<void>(
61 exec.context().get_frame_allocator())));
62 }
63 2x }
64
65 friend bool operator==(const asio_immediate_executor_helper& lhs,
66 const asio_immediate_executor_helper& rhs) noexcept
67 {
68 return lhs.exec == rhs.exec;
69 }
70
71 friend bool operator!=(const asio_immediate_executor_helper& lhs,
72 const asio_immediate_executor_helper& rhs) noexcept
73 {
74 return lhs.exec != rhs.exec;
75 }
76
77 asio_immediate_executor_helper(
78 const asio_immediate_executor_helper & rhs) noexcept = default;
79
80 2x asio_immediate_executor_helper(
81 executor_ref inner,
82 completed_immediately_t * completed_immediately
83 2x ) : exec(std::move(inner)), completed_immediately(completed_immediately)
84 {
85 2x }
86 };
87
88
89 template<typename CancellationSlot, typename ... Args>
90 struct asio_coroutine_completion_handler
91 {
92 asio_coroutine_unique_handle handle;
93 std::optional<std::tuple<Args...>> & result;
94 const capy::io_env * env;
95 CancellationSlot slot;
96 using completed_immediately_t = asio_immediate_executor_helper::completed_immediately_t;
97
98 completed_immediately_t * completed_immediately = nullptr;
99
100 using allocator_type = std::pmr::polymorphic_allocator<void>;
101 10x allocator_type get_allocator() const {return env->frame_allocator;}
102
103 using executor_type = asio_executor_adapter<executor_ref>;
104 5x executor_type get_executor() const {return env->executor;}
105
106 using cancellation_slot_type = CancellationSlot;
107 2x cancellation_slot_type get_cancellation_slot() const {return slot;}
108
109 using immediate_executor_type = asio_immediate_executor_helper;
110 2x immediate_executor_type get_immediate_executor() const
111 {
112 2x return immediate_executor_type{env->executor, completed_immediately };
113 };
114
115 3x asio_coroutine_completion_handler(
116 std::coroutine_handle<void> h,
117 std::optional<std::tuple<Args...>> & result,
118 const capy::io_env * env,
119 CancellationSlot slot = {},
120 completed_immediately_t * ci = nullptr)
121 3x : handle(h)
122 3x , result(result)
123 3x , env(env)
124 3x , slot(slot), completed_immediately(ci)
125 3x {}
126
127 26x asio_coroutine_completion_handler(
128 asio_coroutine_completion_handler &&
129 ) noexcept = default;
130
131 3x void operator()(Args ... args)
132 {
133 3x result.emplace(std::forward<Args>(args)...);
134
135 3x auto h = handle.release();
136
137 3x if (completed_immediately != nullptr
138 3x && *completed_immediately == completed_immediately_t::maybe)
139 {
140 2x *completed_immediately = completed_immediately_t::yes;
141 }
142 else
143 1x h();
144 3x }
145 };
146
147 template<typename ... Ts>
148 struct async_result_impl_result_tuple
149 {
150 using type = std::tuple<Ts...>;
151 };
152
153
154 template<typename T0, typename ... Ts>
155 requires std::constructible_from<io_result<Ts...>, T0, Ts...>
156 struct async_result_impl_result_tuple<T0, Ts...>
157 {
158 using type = io_result<Ts...>;
159 };
160
161 1x inline std::tuple<> make_async_result(const std::tuple<> &) { return {}; }
162
163 template<typename E, typename ... Ts>
164 2x inline auto make_async_result(std::tuple<E, Ts...> && tup)
165 {
166 if constexpr (std::convertible_to<E, std::error_code>)
167 return std::apply(
168 2x [](auto &&e, auto &&... args)
169 {
170 2x return io_result(std::move(e), std::move(args)...);
171 },
172 4x std::move(tup));
173
174 else
175 return std::move(tup);
176 }
177
178
179 template<typename CancellationSignal, typename CancellationType, typename ... Ts>
180 struct async_result_impl
181 {
182 template<typename Initiation, typename... Args>
183 struct awaitable_t
184 {
185 using completed_immediately_t
186 = asio_immediate_executor_helper::completed_immediately_t;
187
188 CancellationSignal signal;
189 completed_immediately_t completed_immediately;
190
191 struct cb
192 {
193 CancellationSignal &signal;
194 3x cb(CancellationSignal &signal) : signal(signal) {}
195 void operator()() {signal.emit(CancellationType::terminal); }
196 };
197 std::optional<std::stop_callback<cb>> stopper;
198
199 3x bool await_ready() const {return false;}
200
201 3x bool await_suspend(std::coroutine_handle<> h, const capy::io_env * env)
202 {
203 3x completed_immediately = completed_immediately_t::initiating;
204 3x stopper.emplace(env->stop_token, signal);
205 using slot_t = std::decay_t<decltype(CancellationSignal().slot())>;
206 3x capy::detail::asio_coroutine_completion_handler<slot_t, Ts...> ch(
207 3x h, result_, env,
208 signal.slot(),
209 &completed_immediately);
210
211 3x std::apply(
212 3x [&](auto ... args)
213 {
214 std::move(init_)(
215 std::move(ch),
216 std::move(args)...);
217 },
218 3x std::move(args_));
219
220 3x if (completed_immediately == completed_immediately_t::initiating)
221 1x completed_immediately = completed_immediately_t::no;
222 3x return completed_immediately != completed_immediately_t::yes;
223 3x }
224
225 3x auto await_resume()
226 {
227 3x return make_async_result(std::move(*result_));
228 }
229
230
231 3x awaitable_t(Initiation init, std::tuple<Args...> args)
232 3x : init_(std::move(init)), args_(std::move(args))
233 {
234 3x }
235
236 1x awaitable_t(awaitable_t && rhs) noexcept
237 1x : init_(std::move(rhs.init_))
238 1x , args_(std::move(rhs.args_))
239 2x , result_(std::move(rhs.result_)) {}
240 private:
241 Initiation init_;
242 // if Args<0> == error_code this needs to be an io_result.
243 typename async_result_impl_result_tuple<Args...>::type args_;
244 std::optional<std::tuple<Ts...>> result_;
245 };
246
247 template <typename Initiation, typename RawToken, typename... Args>
248 3x static auto initiate(Initiation&& initiation,
249 RawToken&&, Args&&... args)
250 {
251 return awaitable_t<
252 std::decay_t<Initiation>,
253 std::decay_t<Args>...>(
254 2x std::forward<Initiation>(initiation),
255 5x std::make_tuple(std::forward<Args>(args)...));
256 }
257 };
258
259
260 }
261
262 #endif //BOOST_CAPY_ASIO_DETAIL_COMPLETION_HANDLER
263
264