TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
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/corosio
8 : //
9 :
10 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_POSIX_DESCRIPTOR_HPP
11 : #define BOOST_COROSIO_NATIVE_NATIVE_POSIX_DESCRIPTOR_HPP
12 :
13 : #include <boost/corosio/detail/op_base.hpp>
14 : #include <boost/corosio/posix_descriptor.hpp>
15 : #include <boost/corosio/backend.hpp>
16 :
17 : #if BOOST_COROSIO_POSIX || defined(BOOST_COROSIO_MRDOCS)
18 :
19 : #ifndef BOOST_COROSIO_MRDOCS
20 : #if BOOST_COROSIO_HAS_EPOLL
21 : #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
22 : #endif
23 :
24 : #if BOOST_COROSIO_HAS_SELECT
25 : #include <boost/corosio/native/detail/select/select_types.hpp>
26 : #endif
27 :
28 : #if BOOST_COROSIO_HAS_KQUEUE
29 : #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
30 : #endif
31 :
32 : #if BOOST_COROSIO_HAS_URING
33 : // uring_types.hpp does not declare the descriptor: it was added
34 : // after that header, in its own pair of files.
35 : #include <boost/corosio/native/detail/uring/uring_descriptor_service.hpp>
36 : #endif
37 : #endif // !BOOST_COROSIO_MRDOCS
38 :
39 : namespace boost::corosio {
40 :
41 : /** Drives an already-open POSIX descriptor, calling the backend directly.
42 :
43 : This class template inherits from @ref posix_descriptor and
44 : shadows the async operations (`read_some`, `write_some`, `wait`)
45 : with versions that call the backend implementation directly.
46 : This lets the compiler inline through the entire call chain.
47 :
48 : Non-async operations (`assign`, `release`, `close`, `cancel`)
49 : remain unchanged and dispatch through the compiled library.
50 :
51 : A `native_posix_descriptor` IS-A `posix_descriptor` and can be
52 : passed to any function expecting `posix_descriptor&` or
53 : `io_stream&`, in which case virtual dispatch is used
54 : transparently.
55 :
56 : @tparam Backend A backend tag value (e.g., `epoll`) whose type
57 : provides the concrete implementation types.
58 :
59 : @par Thread Safety
60 : Same as @ref posix_descriptor.
61 :
62 : @par Example
63 : @par !example assign_and_wait
64 :
65 : @see posix_descriptor, epoll_t, kqueue_t
66 : */
67 : template<auto Backend>
68 : class native_posix_descriptor : public posix_descriptor
69 : {
70 : using backend_type = decltype(Backend);
71 : using impl_type = typename backend_type::descriptor_type;
72 : using service_type = typename backend_type::descriptor_service_type;
73 :
74 HIT 6 : impl_type& get_impl() noexcept
75 : {
76 6 : return *static_cast<impl_type*>(h_.get());
77 : }
78 :
79 : template<class MutableBufferSequence>
80 : struct native_read_awaitable
81 : : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>>
82 : {
83 : native_posix_descriptor& self_;
84 : MutableBufferSequence buffers_;
85 :
86 6 : native_read_awaitable(
87 : native_posix_descriptor& self,
88 : MutableBufferSequence buffers) noexcept
89 6 : : self_(self)
90 6 : , buffers_(std::move(buffers))
91 : {
92 6 : }
93 :
94 : std::coroutine_handle<>
95 4 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
96 : {
97 12 : return self_.get_impl().read_some(
98 12 : h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
99 : }
100 : };
101 :
102 : template<class ConstBufferSequence>
103 : struct native_write_awaitable
104 : : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
105 : {
106 : native_posix_descriptor& self_;
107 : ConstBufferSequence buffers_;
108 :
109 : native_write_awaitable(
110 : native_posix_descriptor& self, ConstBufferSequence buffers) noexcept
111 : : self_(self)
112 : , buffers_(std::move(buffers))
113 : {
114 : }
115 :
116 : std::coroutine_handle<>
117 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
118 : {
119 : return self_.get_impl().write_some(
120 : h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
121 : }
122 : };
123 :
124 : struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
125 : {
126 : native_posix_descriptor& self_;
127 : wait_type w_;
128 :
129 4 : native_wait_awaitable(
130 : native_posix_descriptor& self, wait_type w) noexcept
131 4 : : self_(self)
132 4 : , w_(w)
133 : {
134 4 : }
135 :
136 : std::coroutine_handle<>
137 2 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
138 : {
139 2 : return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
140 : }
141 : };
142 :
143 : public:
144 : /** Construct a native descriptor from an execution context.
145 :
146 : @param ctx The execution context that owns this object.
147 : */
148 12 : explicit native_posix_descriptor(capy::execution_context& ctx)
149 12 : : io_object(handle(ctx, ctx.use_service<service_type>()))
150 : {
151 12 : }
152 :
153 : /** Construct a native descriptor from an executor.
154 :
155 : @param ex The executor whose context owns this object.
156 : */
157 : template<class Ex>
158 : requires(!std::same_as<
159 : std::remove_cvref_t<Ex>,
160 : native_posix_descriptor>) &&
161 : capy::Executor<Ex>
162 : explicit native_posix_descriptor(Ex const& ex)
163 : : native_posix_descriptor(ex.context())
164 : {
165 : }
166 :
167 : /// Move construct.
168 : native_posix_descriptor(native_posix_descriptor&&) noexcept = default;
169 :
170 : /// Move assign.
171 : native_posix_descriptor&
172 : operator=(native_posix_descriptor&&) noexcept = default;
173 :
174 : /// Copy construction is disabled; the handle is uniquely owned.
175 : native_posix_descriptor(native_posix_descriptor const&) = delete;
176 : /// Copy assignment is disabled; the handle is uniquely owned.
177 : native_posix_descriptor&
178 : operator=(native_posix_descriptor const&) = delete;
179 :
180 : /** Asynchronously read data from the descriptor.
181 :
182 : Calls the backend implementation directly, bypassing virtual
183 : dispatch. Otherwise identical to @ref io_stream::read_some.
184 :
185 : @param buffers The buffer sequence to read into.
186 :
187 : @return An awaitable yielding `(error_code, std::size_t)`.
188 : */
189 : template<capy::MutableBufferSequence MB>
190 6 : [[nodiscard]] auto read_some(MB const& buffers)
191 : {
192 6 : return native_read_awaitable<MB>(*this, buffers);
193 : }
194 :
195 : /** Asynchronously write data to the descriptor.
196 :
197 : Calls the backend implementation directly, bypassing virtual
198 : dispatch. Otherwise identical to @ref io_stream::write_some.
199 :
200 : @param buffers The buffer sequence to write from.
201 :
202 : @return An awaitable yielding `(error_code, std::size_t)`.
203 : */
204 : template<capy::ConstBufferSequence CB>
205 : [[nodiscard]] auto write_some(CB const& buffers)
206 : {
207 : return native_write_awaitable<CB>(*this, buffers);
208 : }
209 :
210 : /** Wait for readiness without transferring bytes.
211 :
212 : Calls the backend implementation directly, bypassing virtual
213 : dispatch. Otherwise identical to @ref posix_descriptor::wait.
214 :
215 : @param w The direction to wait on.
216 :
217 : @return An awaitable yielding `io_result<>`.
218 : */
219 4 : [[nodiscard]] auto wait(wait_type w)
220 : {
221 4 : return native_wait_awaitable(*this, w);
222 : }
223 : };
224 :
225 : } // namespace boost::corosio
226 :
227 : #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS
228 :
229 : #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_DESCRIPTOR_HPP
|