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