TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
12 : #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
13 :
14 : #include <boost/corosio/local_stream_socket.hpp>
15 : #include <boost/corosio/backend.hpp>
16 : #include <boost/corosio/detail/op_base.hpp>
17 :
18 : #ifndef BOOST_COROSIO_MRDOCS
19 : #if BOOST_COROSIO_HAS_EPOLL
20 : #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
21 : #endif
22 :
23 : #if BOOST_COROSIO_HAS_SELECT
24 : #include <boost/corosio/native/detail/select/select_types.hpp>
25 : #endif
26 :
27 : #if BOOST_COROSIO_HAS_KQUEUE
28 : #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
29 : #endif
30 :
31 : #if BOOST_COROSIO_HAS_URING
32 : #include <boost/corosio/native/detail/uring/uring_types.hpp>
33 : #endif
34 :
35 : #if BOOST_COROSIO_HAS_IOCP
36 : #include <boost/corosio/native/detail/iocp/win_local_stream_service.hpp>
37 : #endif
38 : #endif // !BOOST_COROSIO_MRDOCS
39 :
40 : namespace boost::corosio {
41 :
42 : /** An asynchronous Unix stream socket with devirtualized I/O operations.
43 :
44 : This class template inherits from @ref local_stream_socket and
45 : shadows the async operations (`read_some`, `write_some`,
46 : `connect`) with versions that call the backend implementation
47 : directly, allowing the compiler to inline through the entire
48 : call chain.
49 :
50 : Non-async operations (`open`, `close`, `cancel`, socket options)
51 : remain unchanged and dispatch through the compiled library.
52 :
53 : A `native_local_stream_socket` IS-A `local_stream_socket` and
54 : can be passed to any function expecting `local_stream_socket&`
55 : or `io_stream&`, in which case virtual dispatch is used
56 : transparently.
57 :
58 : @tparam Backend A backend tag value (e.g., `epoll`) whose type
59 : provides the concrete implementation types.
60 :
61 : @par Thread Safety
62 : Same as @ref local_stream_socket.
63 :
64 : @par Example
65 : @par !example connect
66 :
67 : @see local_stream_socket, epoll_t, iocp_t
68 : */
69 : template<auto Backend>
70 : class native_local_stream_socket : public local_stream_socket
71 : {
72 : using backend_type = decltype(Backend);
73 : using impl_type = typename backend_type::local_stream_socket_type;
74 : using service_type = typename backend_type::local_stream_service_type;
75 :
76 HIT 26 : impl_type& get_impl() noexcept
77 : {
78 26 : return *static_cast<impl_type*>(h_.get());
79 : }
80 :
81 : template<class MutableBufferSequence>
82 : struct native_read_awaitable
83 : : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>>
84 : {
85 : native_local_stream_socket& self_;
86 : MutableBufferSequence buffers_;
87 :
88 8 : native_read_awaitable(
89 : native_local_stream_socket& self,
90 : MutableBufferSequence buffers) noexcept
91 8 : : self_(self)
92 8 : , buffers_(std::move(buffers))
93 : {
94 8 : }
95 :
96 : std::coroutine_handle<>
97 6 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
98 : {
99 18 : return self_.get_impl().read_some(
100 18 : h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
101 : }
102 : };
103 :
104 : template<class ConstBufferSequence>
105 : struct native_write_awaitable
106 : : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
107 : {
108 : native_local_stream_socket& self_;
109 : ConstBufferSequence buffers_;
110 :
111 8 : native_write_awaitable(
112 : native_local_stream_socket& self,
113 : ConstBufferSequence buffers) noexcept
114 8 : : self_(self)
115 8 : , buffers_(std::move(buffers))
116 : {
117 8 : }
118 :
119 : std::coroutine_handle<>
120 6 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
121 : {
122 18 : return self_.get_impl().write_some(
123 18 : h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
124 : }
125 : };
126 :
127 : struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
128 : {
129 : native_local_stream_socket& self_;
130 : wait_type w_;
131 :
132 6 : native_wait_awaitable(
133 : native_local_stream_socket& self, wait_type w) noexcept
134 6 : : self_(self)
135 6 : , w_(w)
136 : {
137 6 : }
138 :
139 : std::coroutine_handle<>
140 4 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
141 : {
142 4 : return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
143 : }
144 : };
145 :
146 : struct native_connect_awaitable
147 : : detail::void_op_base<native_connect_awaitable>
148 : {
149 : native_local_stream_socket& self_;
150 : corosio::local_endpoint endpoint_;
151 :
152 12 : native_connect_awaitable(
153 : native_local_stream_socket& self,
154 : corosio::local_endpoint ep) noexcept
155 12 : : self_(self)
156 12 : , endpoint_(ep)
157 : {
158 12 : }
159 :
160 : std::coroutine_handle<>
161 10 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
162 : {
163 30 : return self_.get_impl().connect(
164 30 : h, ex, endpoint_, this->token_, &this->ec_);
165 : }
166 : };
167 :
168 : public:
169 : /** Construct a native socket from an execution context.
170 :
171 : @param ctx The execution context that will own this socket.
172 : */
173 40 : explicit native_local_stream_socket(capy::execution_context& ctx)
174 40 : : io_object(create_handle<service_type>(ctx))
175 : {
176 40 : }
177 :
178 : /** Construct a native socket from an executor.
179 :
180 : @param ex The executor whose context will own the socket.
181 : */
182 : template<class Ex>
183 : requires(!std::same_as<
184 : std::remove_cvref_t<Ex>,
185 : native_local_stream_socket>) &&
186 : capy::Executor<Ex>
187 : explicit native_local_stream_socket(Ex const& ex)
188 : : native_local_stream_socket(ex.context())
189 : {
190 : }
191 :
192 : /// Move construct.
193 6 : native_local_stream_socket(native_local_stream_socket&&) noexcept = default;
194 :
195 : /// Move assign.
196 : native_local_stream_socket&
197 : operator=(native_local_stream_socket&&) noexcept = default;
198 :
199 : native_local_stream_socket(native_local_stream_socket const&) = delete;
200 : native_local_stream_socket&
201 : operator=(native_local_stream_socket const&) = delete;
202 :
203 : /** Asynchronously read data from the socket.
204 :
205 : Calls the backend implementation directly, bypassing virtual
206 : dispatch. Otherwise identical to @ref io_stream::read_some.
207 :
208 : @param buffers The buffer sequence to read into.
209 :
210 : @return An awaitable yielding `(error_code, std::size_t)`.
211 : */
212 : template<capy::MutableBufferSequence MB>
213 8 : [[nodiscard]] auto read_some(MB const& buffers)
214 : {
215 8 : return native_read_awaitable<MB>(*this, buffers);
216 : }
217 :
218 : /** Asynchronously write data to the socket.
219 :
220 : Calls the backend implementation directly, bypassing virtual
221 : dispatch. Otherwise identical to @ref io_stream::write_some.
222 :
223 : @param buffers The buffer sequence to write from.
224 :
225 : @return An awaitable yielding `(error_code, std::size_t)`.
226 : */
227 : template<capy::ConstBufferSequence CB>
228 8 : [[nodiscard]] auto write_some(CB const& buffers)
229 : {
230 8 : return native_write_awaitable<CB>(*this, buffers);
231 : }
232 :
233 : /** Asynchronously connect to a remote endpoint.
234 :
235 : Calls the backend implementation directly, bypassing virtual
236 : dispatch. Otherwise identical to @ref local_stream_socket::connect.
237 :
238 : If the socket is not already open, it is opened automatically.
239 :
240 : @param ep The local endpoint (path) to connect to.
241 :
242 : @return An awaitable yielding `io_result<>`.
243 :
244 : If the socket needs to be opened and the open fails, the
245 : awaitable completes immediately with that error.
246 : */
247 12 : [[nodiscard]] auto connect(corosio::local_endpoint ep)
248 : {
249 12 : native_connect_awaitable aw(*this, ep);
250 12 : if (!is_open())
251 10 : aw.ec_ = open();
252 12 : return aw;
253 : }
254 :
255 : /** Asynchronously wait for the socket to be ready.
256 :
257 : Calls the backend implementation directly, bypassing virtual
258 : dispatch. Otherwise identical to @ref local_stream_socket::wait.
259 :
260 : @param w The wait direction (read, write, or error).
261 :
262 : @return An awaitable yielding `io_result<>`.
263 : */
264 6 : [[nodiscard]] auto wait(wait_type w)
265 : {
266 6 : return native_wait_awaitable(*this, w);
267 : }
268 : };
269 :
270 : } // namespace boost::corosio
271 :
272 : #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
|