Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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_RUN_ON_HPP
11 : #define BOOST_CAPY_RUN_ON_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/concept/executor.hpp>
15 : #include <boost/capy/io_awaitable.hpp>
16 : #include <boost/capy/ex/executor_ref.hpp>
17 :
18 : #include <stop_token>
19 : #include <utility>
20 :
21 : namespace boost {
22 : namespace capy {
23 : namespace detail {
24 :
25 : /** Awaitable that binds an IoAwaitableTask to a specific executor.
26 :
27 : Stores the executor and inner task by value. When co_awaited, the
28 : co_await expression's lifetime extension keeps both alive for the
29 : duration of the operation.
30 :
31 : @tparam Task The IoAwaitableTask type
32 : @tparam Ex The executor type
33 : */
34 : template<IoLaunchableTask Task, Executor Ex>
35 : struct [[nodiscard]]
36 : run_on_awaitable
37 : {
38 : Ex ex_;
39 : Task inner_;
40 :
41 2 : run_on_awaitable(Ex ex, Task inner)
42 2 : : ex_(std::move(ex))
43 2 : , inner_(std::move(inner))
44 : {
45 2 : }
46 :
47 2 : bool await_ready() const noexcept
48 : {
49 2 : return inner_.await_ready();
50 : }
51 :
52 2 : auto await_resume()
53 : {
54 2 : return inner_.await_resume();
55 : }
56 :
57 : // IoAwaitable: receives caller's executor and stop_token for completion dispatch
58 : template<typename Caller>
59 2 : coro await_suspend(coro cont, Caller const& caller_ex, std::stop_token token)
60 : {
61 2 : auto h = inner_.handle();
62 2 : auto& p = h.promise();
63 2 : p.set_executor(ex_);
64 2 : p.set_continuation(cont, caller_ex);
65 2 : p.set_stop_token(token);
66 2 : return h;
67 : }
68 :
69 : // Non-copyable
70 : run_on_awaitable(run_on_awaitable const&) = delete;
71 : run_on_awaitable& operator=(run_on_awaitable const&) = delete;
72 :
73 : // Movable
74 2 : run_on_awaitable(run_on_awaitable&& other) noexcept
75 2 : : ex_(std::move(other.ex_))
76 2 : , inner_(std::move(other.inner_))
77 : {
78 2 : }
79 :
80 : run_on_awaitable& operator=(run_on_awaitable&& other) noexcept
81 : {
82 : if(this != &other)
83 : {
84 : ex_ = std::move(other.ex_);
85 : inner_ = std::move(other.inner_);
86 : }
87 : return *this;
88 : }
89 : };
90 :
91 : } // namespace detail
92 :
93 : /** Binds a task to execute on a specific executor.
94 :
95 : The executor is stored by value in the returned awaitable.
96 : When co_awaited, the inner task receives this executor through
97 : direct promise configuration.
98 :
99 : @param ex The executor on which the task should run (copied by value).
100 : @param t The IoAwaitableTask to bind to the executor.
101 :
102 : @return An awaitable that runs t on the specified executor.
103 : */
104 : template<Executor Ex, IoLaunchableTask Task>
105 2 : [[nodiscard]] auto run_on(Ex ex, Task t)
106 : {
107 : return detail::run_on_awaitable<Task, Ex>{
108 2 : std::move(ex), std::move(t)};
109 : }
110 :
111 : } // namespace capy
112 : } // namespace boost
113 :
114 : #endif
|