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(capy::continuation& cont, capy::executor_ref ex) const
96 : {
97 12 : return self_.get_impl().read_some(
98 12 : cont, 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(capy::continuation& cont, capy::executor_ref ex) const
119 : {
120 6 : return self_.get_impl().write_some(
121 6 : cont, 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(capy::continuation& cont, capy::executor_ref ex) const
139 : {
140 4 : return self_.get_impl().wait(
141 4 : cont, ex, w_, this->token_, &this->ec_);
142 : }
143 : };
144 :
145 : public:
146 : /** Construct a `native_posix_stream_descriptor` from an execution
147 : context.
148 :
149 : @param ctx The execution context that owns this object.
150 : */
151 14 : explicit native_posix_stream_descriptor(capy::execution_context& ctx)
152 14 : : io_object(handle(ctx, ctx.use_service<service_type>()))
153 : {
154 14 : }
155 :
156 : /** Construct a `native_posix_stream_descriptor` from an executor.
157 :
158 : The overload excludes `native_posix_stream_descriptor` itself so
159 : that it cannot displace the move constructor.
160 :
161 : @tparam Ex A type satisfying `capy::Executor`.
162 : @param ex The executor whose context owns this object.
163 : */
164 : template<class Ex>
165 : requires(!std::same_as<
166 : std::remove_cvref_t<Ex>,
167 : native_posix_stream_descriptor>) &&
168 : capy::Executor<Ex>
169 : explicit native_posix_stream_descriptor(Ex const& ex)
170 : : native_posix_stream_descriptor(ex.context())
171 : {
172 : }
173 :
174 : /** Transfer ownership of the descriptor from the source.
175 :
176 : After the move, the source is in a moved-from state and may
177 : only be destroyed or assigned to.
178 :
179 : @pre No awaitables returned by the source's methods exist.
180 : */
181 : native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept =
182 : default;
183 :
184 : /** Close any held descriptor and transfer ownership from the source.
185 :
186 : After the move, the source is in a moved-from state and may
187 : only be destroyed or assigned to.
188 :
189 : @return `*this`.
190 : @pre No awaitables returned by either object's methods exist.
191 : */
192 : native_posix_stream_descriptor&
193 : operator=(native_posix_stream_descriptor&&) noexcept = default;
194 :
195 : /// Copy construction is disabled; the handle is uniquely owned.
196 : native_posix_stream_descriptor(native_posix_stream_descriptor const&) =
197 : delete;
198 : /// Copy assignment is disabled; the handle is uniquely owned.
199 : native_posix_stream_descriptor&
200 : operator=(native_posix_stream_descriptor const&) = delete;
201 :
202 : /** Asynchronously read data from the descriptor.
203 :
204 : Calls the backend implementation directly, bypassing virtual
205 : dispatch. Otherwise identical to @ref io_stream::read_some.
206 :
207 : @param buffers The buffer sequence to read into.
208 :
209 : @return An awaitable yielding `(error_code, std::size_t)`.
210 : */
211 : template<capy::MutableBufferSequence MB>
212 6 : [[nodiscard]] auto read_some(MB const& buffers)
213 : {
214 6 : return native_read_awaitable<MB>(*this, buffers);
215 : }
216 :
217 : /** Asynchronously write data to the descriptor.
218 :
219 : Calls the backend implementation directly, bypassing virtual
220 : dispatch. Otherwise identical to @ref io_stream::write_some.
221 :
222 : @param buffers The buffer sequence to write from.
223 :
224 : @return An awaitable yielding `(error_code, std::size_t)`.
225 : */
226 : template<capy::ConstBufferSequence CB>
227 2 : [[nodiscard]] auto write_some(CB const& buffers)
228 : {
229 2 : return native_write_awaitable<CB>(*this, buffers);
230 : }
231 :
232 : /** Wait for readiness without transferring bytes.
233 :
234 : Calls the backend implementation directly, bypassing virtual
235 : dispatch. Otherwise identical to @ref posix_stream_descriptor::wait.
236 :
237 : @param w The direction to wait on.
238 :
239 : @return An awaitable yielding `results<>`.
240 : */
241 4 : [[nodiscard]] auto wait(wait_type w)
242 : {
243 4 : return native_wait_awaitable(*this, w);
244 : }
245 : };
246 :
247 : } // namespace boost::corosio
248 :
249 : #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS
250 :
251 : #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP
|