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