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