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