100.00% Lines (31/31) 100.00% Functions (11/11)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Michael Vandeberg 2   // Copyright (c) 2026 Michael Vandeberg
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP
12   12  
13   #include <boost/corosio/detail/op_base.hpp> 13   #include <boost/corosio/detail/op_base.hpp>
14   #include <boost/corosio/posix_stream_descriptor.hpp> 14   #include <boost/corosio/posix_stream_descriptor.hpp>
15   #include <boost/corosio/backend.hpp> 15   #include <boost/corosio/backend.hpp>
16   16  
17   #if BOOST_COROSIO_POSIX || defined(BOOST_COROSIO_MRDOCS) 17   #if BOOST_COROSIO_POSIX || defined(BOOST_COROSIO_MRDOCS)
18   18  
19   #ifndef BOOST_COROSIO_MRDOCS 19   #ifndef BOOST_COROSIO_MRDOCS
20   #if BOOST_COROSIO_HAS_EPOLL 20   #if BOOST_COROSIO_HAS_EPOLL
21   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 21   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
22   #endif 22   #endif
23   23  
24   #if BOOST_COROSIO_HAS_SELECT 24   #if BOOST_COROSIO_HAS_SELECT
25   #include <boost/corosio/native/detail/select/select_types.hpp> 25   #include <boost/corosio/native/detail/select/select_types.hpp>
26   #endif 26   #endif
27   27  
28   #if BOOST_COROSIO_HAS_KQUEUE 28   #if BOOST_COROSIO_HAS_KQUEUE
29   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 29   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
30   #endif 30   #endif
31   31  
32   #if BOOST_COROSIO_HAS_URING 32   #if BOOST_COROSIO_HAS_URING
33   // uring_types.hpp does not declare the descriptor: it was added 33   // uring_types.hpp does not declare the descriptor: it was added
34   // after that header, in its own pair of files. 34   // after that header, in its own pair of files.
35   #include <boost/corosio/native/detail/uring/uring_descriptor_service.hpp> 35   #include <boost/corosio/native/detail/uring/uring_descriptor_service.hpp>
36   #endif 36   #endif
37   #endif // !BOOST_COROSIO_MRDOCS 37   #endif // !BOOST_COROSIO_MRDOCS
38   38  
39   namespace boost::corosio { 39   namespace boost::corosio {
40   40  
41   /** Drives an already-open POSIX descriptor, calling the backend directly. 41   /** Drives an already-open POSIX descriptor, calling the backend directly.
42   42  
43   This class template inherits from @ref posix_stream_descriptor and 43   This class template inherits from @ref posix_stream_descriptor and
44   shadows the async operations (`read_some`, `write_some`, `wait`) 44   shadows the async operations (`read_some`, `write_some`, `wait`)
45   with versions that call the backend implementation directly. 45   with versions that call the backend implementation directly.
46   This lets the compiler inline through the entire call chain. 46   This lets the compiler inline through the entire call chain.
47   47  
48   Non-async operations (`assign`, `release`, `close`, `cancel`) 48   Non-async operations (`assign`, `release`, `close`, `cancel`)
49   remain unchanged and dispatch through the compiled library. 49   remain unchanged and dispatch through the compiled library.
50   50  
51   A `native_posix_stream_descriptor` IS-A `posix_stream_descriptor` and can be 51   A `native_posix_stream_descriptor` IS-A `posix_stream_descriptor` and can be
52   passed to any function expecting `posix_stream_descriptor&` or 52   passed to any function expecting `posix_stream_descriptor&` or
53   `io_stream&`, in which case virtual dispatch is used 53   `io_stream&`, in which case virtual dispatch is used
54   transparently. 54   transparently.
55   55  
56   @tparam Backend A backend tag value (e.g., `epoll`) whose type 56   @tparam Backend A backend tag value (e.g., `epoll`) whose type
57   provides the concrete implementation types. 57   provides the concrete implementation types.
58   58  
59   @par Thread Safety 59   @par Thread Safety
60   Same as @ref posix_stream_descriptor. 60   Same as @ref posix_stream_descriptor.
61   61  
62   @par Example 62   @par Example
63   @par !example assign_and_wait 63   @par !example assign_and_wait
64   64  
65   @see posix_stream_descriptor, epoll_t, kqueue_t 65   @see posix_stream_descriptor, epoll_t, kqueue_t
66   */ 66   */
67   template<auto Backend> 67   template<auto Backend>
68   class native_posix_stream_descriptor : public posix_stream_descriptor 68   class native_posix_stream_descriptor : public posix_stream_descriptor
69   { 69   {
70   using backend_type = decltype(Backend); 70   using backend_type = decltype(Backend);
71   using impl_type = typename backend_type::stream_descriptor_type; 71   using impl_type = typename backend_type::stream_descriptor_type;
72   using service_type = typename backend_type::stream_descriptor_service_type; 72   using service_type = typename backend_type::stream_descriptor_service_type;
73   73  
HITCBC 74   8 impl_type& get_impl() noexcept 74   8 impl_type& get_impl() noexcept
75   { 75   {
HITCBC 76   8 return *static_cast<impl_type*>(h_.get()); 76   8 return *static_cast<impl_type*>(h_.get());
77   } 77   }
78   78  
79   template<class MutableBufferSequence> 79   template<class MutableBufferSequence>
80   struct native_read_awaitable 80   struct native_read_awaitable
81   : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>> 81   : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>>
82   { 82   {
83   native_posix_stream_descriptor& self_; 83   native_posix_stream_descriptor& self_;
84   MutableBufferSequence buffers_; 84   MutableBufferSequence buffers_;
85   85  
HITCBC 86   6 native_read_awaitable( 86   6 native_read_awaitable(
87   native_posix_stream_descriptor& self, 87   native_posix_stream_descriptor& self,
88   MutableBufferSequence buffers) noexcept 88   MutableBufferSequence buffers) noexcept
HITCBC 89   6 : self_(self) 89   6 : self_(self)
HITCBC 90   6 , buffers_(std::move(buffers)) 90   6 , buffers_(std::move(buffers))
91   { 91   {
HITCBC 92   6 } 92   6 }
93   93  
94   std::coroutine_handle<> 94   std::coroutine_handle<>
HITCBC 95   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 95   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
96   { 96   {
HITCBC 97   12 return self_.get_impl().read_some( 97   12 return self_.get_impl().read_some(
HITCBC 98   12 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 98   12 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
99   } 99   }
100   }; 100   };
101   101  
102   template<class ConstBufferSequence> 102   template<class ConstBufferSequence>
103   struct native_write_awaitable 103   struct native_write_awaitable
104   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>> 104   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
105   { 105   {
106   native_posix_stream_descriptor& self_; 106   native_posix_stream_descriptor& self_;
107   ConstBufferSequence buffers_; 107   ConstBufferSequence buffers_;
108   108  
HITCBC 109   2 native_write_awaitable( 109   2 native_write_awaitable(
110   native_posix_stream_descriptor& self, 110   native_posix_stream_descriptor& self,
111   ConstBufferSequence buffers) noexcept 111   ConstBufferSequence buffers) noexcept
HITCBC 112   2 : self_(self) 112   2 : self_(self)
HITCBC 113   2 , buffers_(std::move(buffers)) 113   2 , buffers_(std::move(buffers))
114   { 114   {
HITCBC 115   2 } 115   2 }
116   116  
117   std::coroutine_handle<> 117   std::coroutine_handle<>
HITCBC 118   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 118   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
119   { 119   {
HITCBC 120   6 return self_.get_impl().write_some( 120   6 return self_.get_impl().write_some(
HITCBC 121   6 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 121   6 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
122   } 122   }
123   }; 123   };
124   124  
125   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable> 125   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
126   { 126   {
127   native_posix_stream_descriptor& self_; 127   native_posix_stream_descriptor& self_;
128   wait_type w_; 128   wait_type w_;
129   129  
HITCBC 130   4 native_wait_awaitable( 130   4 native_wait_awaitable(
131   native_posix_stream_descriptor& self, wait_type w) noexcept 131   native_posix_stream_descriptor& self, wait_type w) noexcept
HITCBC 132   4 : self_(self) 132   4 : self_(self)
HITCBC 133   4 , w_(w) 133   4 , w_(w)
134   { 134   {
HITCBC 135   4 } 135   4 }
136   136  
137   std::coroutine_handle<> 137   std::coroutine_handle<>
HITCBC 138   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 138   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
139   { 139   {
HITCBC 140   2 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_); 140   2 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
141   } 141   }
142   }; 142   };
143   143  
144   public: 144   public:
145   /** Construct a `native_posix_stream_descriptor` from an execution 145   /** Construct a `native_posix_stream_descriptor` from an execution
146   context. 146   context.
147   147  
148   @param ctx The execution context that owns this object. 148   @param ctx The execution context that owns this object.
149   */ 149   */
HITCBC 150   14 explicit native_posix_stream_descriptor(capy::execution_context& ctx) 150   14 explicit native_posix_stream_descriptor(capy::execution_context& ctx)
HITCBC 151   14 : io_object(handle(ctx, ctx.use_service<service_type>())) 151   14 : io_object(handle(ctx, ctx.use_service<service_type>()))
152   { 152   {
HITCBC 153   14 } 153   14 }
154   154  
155   /** Construct a `native_posix_stream_descriptor` from an executor. 155   /** Construct a `native_posix_stream_descriptor` from an executor.
156   156  
157   The overload excludes `native_posix_stream_descriptor` itself so 157   The overload excludes `native_posix_stream_descriptor` itself so
158   that it cannot displace the move constructor. 158   that it cannot displace the move constructor.
159   159  
160   @tparam Ex A type satisfying `capy::Executor`. 160   @tparam Ex A type satisfying `capy::Executor`.
161   @param ex The executor whose context owns this object. 161   @param ex The executor whose context owns this object.
162   */ 162   */
163   template<class Ex> 163   template<class Ex>
164   requires(!std::same_as< 164   requires(!std::same_as<
165   std::remove_cvref_t<Ex>, 165   std::remove_cvref_t<Ex>,
166   native_posix_stream_descriptor>) && 166   native_posix_stream_descriptor>) &&
167   capy::Executor<Ex> 167   capy::Executor<Ex>
168   explicit native_posix_stream_descriptor(Ex const& ex) 168   explicit native_posix_stream_descriptor(Ex const& ex)
169   : native_posix_stream_descriptor(ex.context()) 169   : native_posix_stream_descriptor(ex.context())
170   { 170   {
171   } 171   }
172   172  
173   /** Transfer ownership of the descriptor from the source. 173   /** Transfer ownership of the descriptor from the source.
174   174  
175   After the move, the source is in a moved-from state and may 175   After the move, the source is in a moved-from state and may
176   only be destroyed or assigned to. 176   only be destroyed or assigned to.
177   177  
178   @pre No awaitables returned by the source's methods exist. 178   @pre No awaitables returned by the source's methods exist.
179   */ 179   */
180   native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept = 180   native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept =
181   default; 181   default;
182   182  
183   /** Close any held descriptor and transfer ownership from the source. 183   /** Close any held descriptor and transfer ownership from the source.
184   184  
185   After the move, the source is in a moved-from state and may 185   After the move, the source is in a moved-from state and may
186   only be destroyed or assigned to. 186   only be destroyed or assigned to.
187   187  
188   @return `*this`. 188   @return `*this`.
189   @pre No awaitables returned by either object's methods exist. 189   @pre No awaitables returned by either object's methods exist.
190   */ 190   */
191   native_posix_stream_descriptor& 191   native_posix_stream_descriptor&
192   operator=(native_posix_stream_descriptor&&) noexcept = default; 192   operator=(native_posix_stream_descriptor&&) noexcept = default;
193   193  
194   /// Copy construction is disabled; the handle is uniquely owned. 194   /// Copy construction is disabled; the handle is uniquely owned.
195   native_posix_stream_descriptor(native_posix_stream_descriptor const&) = 195   native_posix_stream_descriptor(native_posix_stream_descriptor const&) =
196   delete; 196   delete;
197   /// Copy assignment is disabled; the handle is uniquely owned. 197   /// Copy assignment is disabled; the handle is uniquely owned.
198   native_posix_stream_descriptor& 198   native_posix_stream_descriptor&
199   operator=(native_posix_stream_descriptor const&) = delete; 199   operator=(native_posix_stream_descriptor const&) = delete;
200   200  
201   /** Asynchronously read data from the descriptor. 201   /** Asynchronously read data from the descriptor.
202   202  
203   Calls the backend implementation directly, bypassing virtual 203   Calls the backend implementation directly, bypassing virtual
204   dispatch. Otherwise identical to @ref io_stream::read_some. 204   dispatch. Otherwise identical to @ref io_stream::read_some.
205   205  
206   @param buffers The buffer sequence to read into. 206   @param buffers The buffer sequence to read into.
207   207  
208   @return An awaitable yielding `(error_code, std::size_t)`. 208   @return An awaitable yielding `(error_code, std::size_t)`.
209   */ 209   */
210   template<capy::MutableBufferSequence MB> 210   template<capy::MutableBufferSequence MB>
HITCBC 211   6 [[nodiscard]] auto read_some(MB const& buffers) 211   6 [[nodiscard]] auto read_some(MB const& buffers)
212   { 212   {
HITCBC 213   6 return native_read_awaitable<MB>(*this, buffers); 213   6 return native_read_awaitable<MB>(*this, buffers);
214   } 214   }
215   215  
216   /** Asynchronously write data to the descriptor. 216   /** Asynchronously write data to the descriptor.
217   217  
218   Calls the backend implementation directly, bypassing virtual 218   Calls the backend implementation directly, bypassing virtual
219   dispatch. Otherwise identical to @ref io_stream::write_some. 219   dispatch. Otherwise identical to @ref io_stream::write_some.
220   220  
221   @param buffers The buffer sequence to write from. 221   @param buffers The buffer sequence to write from.
222   222  
223   @return An awaitable yielding `(error_code, std::size_t)`. 223   @return An awaitable yielding `(error_code, std::size_t)`.
224   */ 224   */
225   template<capy::ConstBufferSequence CB> 225   template<capy::ConstBufferSequence CB>
HITCBC 226   2 [[nodiscard]] auto write_some(CB const& buffers) 226   2 [[nodiscard]] auto write_some(CB const& buffers)
227   { 227   {
HITCBC 228   2 return native_write_awaitable<CB>(*this, buffers); 228   2 return native_write_awaitable<CB>(*this, buffers);
229   } 229   }
230   230  
231   /** Wait for readiness without transferring bytes. 231   /** Wait for readiness without transferring bytes.
232   232  
233   Calls the backend implementation directly, bypassing virtual 233   Calls the backend implementation directly, bypassing virtual
234   dispatch. Otherwise identical to @ref posix_stream_descriptor::wait. 234   dispatch. Otherwise identical to @ref posix_stream_descriptor::wait.
235   235  
236   @param w The direction to wait on. 236   @param w The direction to wait on.
237   237  
238   @return An awaitable yielding `io_result<>`. 238   @return An awaitable yielding `io_result<>`.
239   */ 239   */
HITCBC 240   4 [[nodiscard]] auto wait(wait_type w) 240   4 [[nodiscard]] auto wait(wait_type w)
241   { 241   {
HITCBC 242   4 return native_wait_awaitable(*this, w); 242   4 return native_wait_awaitable(*this, w);
243   } 243   }
244   }; 244   };
245   245  
246   } // namespace boost::corosio 246   } // namespace boost::corosio
247   247  
248   #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS 248   #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS
249   249  
250   #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP 250   #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP