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_STREAM_DESCRIPTOR_HPP
11 : #define BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP
12 :
13 : #include <boost/corosio/detail/op_base.hpp>
14 : #include <boost/corosio/posix_stream_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_stream_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_stream_descriptor` IS-A `posix_stream_descriptor` and can be
52 : passed to any function expecting `posix_stream_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_stream_descriptor.
61 :
62 : @par Example
63 : @par !example assign_and_wait
64 :
65 : @see posix_stream_descriptor, epoll_t, kqueue_t
66 : */
67 : template<auto Backend>
68 : class native_posix_stream_descriptor : public posix_stream_descriptor
69 : {
70 : using backend_type = decltype(Backend);
71 : using impl_type = typename backend_type::stream_descriptor_type;
72 : using service_type = typename backend_type::stream_descriptor_service_type;
73 :
74 HIT 8 : impl_type& get_impl() noexcept
75 : {
76 8 : 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_stream_descriptor& self_;
84 : MutableBufferSequence buffers_;
85 :
86 6 : native_read_awaitable(
87 : native_posix_stream_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_stream_descriptor& self_;
107 : ConstBufferSequence buffers_;
108 :
109 2 : native_write_awaitable(
110 : native_posix_stream_descriptor& self,
111 : ConstBufferSequence buffers) noexcept
112 2 : : self_(self)
113 2 : , buffers_(std::move(buffers))
114 : {
115 2 : }
116 :
117 : std::coroutine_handle<>
118 2 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
119 : {
120 6 : return self_.get_impl().write_some(
121 6 : h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
122 : }
123 : };
124 :
125 : struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
126 : {
127 : native_posix_stream_descriptor& self_;
128 : wait_type w_;
129 :
130 4 : native_wait_awaitable(
131 : native_posix_stream_descriptor& self, wait_type w) noexcept
132 4 : : self_(self)
133 4 : , w_(w)
134 : {
135 4 : }
136 :
137 : std::coroutine_handle<>
138 2 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
139 : {
140 2 : return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
141 : }
142 : };
143 :
144 : public:
145 : /** Construct a `native_posix_stream_descriptor` from an execution
146 : context.
147 :
148 : @param ctx The execution context that owns this object.
149 : */
150 14 : explicit native_posix_stream_descriptor(capy::execution_context& ctx)
151 14 : : io_object(handle(ctx, ctx.use_service<service_type>()))
152 : {
153 14 : }
154 :
155 : /** Construct a `native_posix_stream_descriptor` from an executor.
156 :
157 : The overload excludes `native_posix_stream_descriptor` itself so
158 : that it cannot displace the move constructor.
159 :
160 : @tparam Ex A type satisfying `capy::Executor`.
161 : @param ex The executor whose context owns this object.
162 : */
163 : template<class Ex>
164 : requires(!std::same_as<
165 : std::remove_cvref_t<Ex>,
166 : native_posix_stream_descriptor>) &&
167 : capy::Executor<Ex>
168 : explicit native_posix_stream_descriptor(Ex const& ex)
169 : : native_posix_stream_descriptor(ex.context())
170 : {
171 : }
172 :
173 : /** Transfer ownership of the descriptor from the source.
174 :
175 : After the move, the source is in a moved-from state and may
176 : only be destroyed or assigned to.
177 :
178 : @pre No awaitables returned by the source's methods exist.
179 : */
180 : native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept =
181 : default;
182 :
183 : /** Close any held descriptor and transfer ownership from the source.
184 :
185 : After the move, the source is in a moved-from state and may
186 : only be destroyed or assigned to.
187 :
188 : @return `*this`.
189 : @pre No awaitables returned by either object's methods exist.
190 : */
191 : native_posix_stream_descriptor&
192 : operator=(native_posix_stream_descriptor&&) noexcept = default;
193 :
194 : /// Copy construction is disabled; the handle is uniquely owned.
195 : native_posix_stream_descriptor(native_posix_stream_descriptor const&) =
196 : delete;
197 : /// Copy assignment is disabled; the handle is uniquely owned.
198 : native_posix_stream_descriptor&
199 : operator=(native_posix_stream_descriptor const&) = delete;
200 :
201 : /** Asynchronously read data from the descriptor.
202 :
203 : Calls the backend implementation directly, bypassing virtual
204 : dispatch. Otherwise identical to @ref io_stream::read_some.
205 :
206 : @param buffers The buffer sequence to read into.
207 :
208 : @return An awaitable yielding `(error_code, std::size_t)`.
209 : */
210 : template<capy::MutableBufferSequence MB>
211 6 : [[nodiscard]] auto read_some(MB const& buffers)
212 : {
213 6 : return native_read_awaitable<MB>(*this, buffers);
214 : }
215 :
216 : /** Asynchronously write data to the descriptor.
217 :
218 : Calls the backend implementation directly, bypassing virtual
219 : dispatch. Otherwise identical to @ref io_stream::write_some.
220 :
221 : @param buffers The buffer sequence to write from.
222 :
223 : @return An awaitable yielding `(error_code, std::size_t)`.
224 : */
225 : template<capy::ConstBufferSequence CB>
226 2 : [[nodiscard]] auto write_some(CB const& buffers)
227 : {
228 2 : return native_write_awaitable<CB>(*this, buffers);
229 : }
230 :
231 : /** Wait for readiness without transferring bytes.
232 :
233 : Calls the backend implementation directly, bypassing virtual
234 : dispatch. Otherwise identical to @ref posix_stream_descriptor::wait.
235 :
236 : @param w The direction to wait on.
237 :
238 : @return An awaitable yielding `io_result<>`.
239 : */
240 4 : [[nodiscard]] auto wait(wait_type w)
241 : {
242 4 : return native_wait_awaitable(*this, w);
243 : }
244 : };
245 :
246 : } // namespace boost::corosio
247 :
248 : #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS
249 :
250 : #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP
|