100.00% Lines (32/32) 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(capy::continuation& cont, capy::executor_ref ex) const 95   4 dispatch(capy::continuation& cont, 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 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 98   12 cont, 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(capy::continuation& cont, capy::executor_ref ex) const 118   2 dispatch(capy::continuation& cont, 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 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 121   6 cont, 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(capy::continuation& cont, capy::executor_ref ex) const 138   2 dispatch(capy::continuation& cont, capy::executor_ref ex) const
139   { 139   {
HITCBC 140   4 return self_.get_impl().wait( 140   4 return self_.get_impl().wait(
HITCBC 141   4 cont, ex, w_, this->token_, &this->ec_); 141   4 cont, ex, w_, this->token_, &this->ec_);
142   } 142   }
143   }; 143   };
144   144  
145   public: 145   public:
146   /** Construct a `native_posix_stream_descriptor` from an execution 146   /** Construct a `native_posix_stream_descriptor` from an execution
147   context. 147   context.
148   148  
149   @param ctx The execution context that owns this object. 149   @param ctx The execution context that owns this object.
150   */ 150   */
HITCBC 151   14 explicit native_posix_stream_descriptor(capy::execution_context& ctx) 151   14 explicit native_posix_stream_descriptor(capy::execution_context& ctx)
HITCBC 152   14 : io_object(handle(ctx, ctx.use_service<service_type>())) 152   14 : io_object(handle(ctx, ctx.use_service<service_type>()))
153   { 153   {
HITCBC 154   14 } 154   14 }
155   155  
156   /** Construct a `native_posix_stream_descriptor` from an executor. 156   /** Construct a `native_posix_stream_descriptor` from an executor.
157   157  
158   The overload excludes `native_posix_stream_descriptor` itself so 158   The overload excludes `native_posix_stream_descriptor` itself so
159   that it cannot displace the move constructor. 159   that it cannot displace the move constructor.
160   160  
161   @tparam Ex A type satisfying `capy::Executor`. 161   @tparam Ex A type satisfying `capy::Executor`.
162   @param ex The executor whose context owns this object. 162   @param ex The executor whose context owns this object.
163   */ 163   */
164   template<class Ex> 164   template<class Ex>
165   requires(!std::same_as< 165   requires(!std::same_as<
166   std::remove_cvref_t<Ex>, 166   std::remove_cvref_t<Ex>,
167   native_posix_stream_descriptor>) && 167   native_posix_stream_descriptor>) &&
168   capy::Executor<Ex> 168   capy::Executor<Ex>
169   explicit native_posix_stream_descriptor(Ex const& ex) 169   explicit native_posix_stream_descriptor(Ex const& ex)
170   : native_posix_stream_descriptor(ex.context()) 170   : native_posix_stream_descriptor(ex.context())
171   { 171   {
172   } 172   }
173   173  
174   /** Transfer ownership of the descriptor from the source. 174   /** Transfer ownership of the descriptor from the source.
175   175  
176   After the move, the source is in a moved-from state and may 176   After the move, the source is in a moved-from state and may
177   only be destroyed or assigned to. 177   only be destroyed or assigned to.
178   178  
179   @pre No awaitables returned by the source's methods exist. 179   @pre No awaitables returned by the source's methods exist.
180   */ 180   */
181   native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept = 181   native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept =
182   default; 182   default;
183   183  
184   /** Close any held descriptor and transfer ownership from the source. 184   /** Close any held descriptor and transfer ownership from the source.
185   185  
186   After the move, the source is in a moved-from state and may 186   After the move, the source is in a moved-from state and may
187   only be destroyed or assigned to. 187   only be destroyed or assigned to.
188   188  
189   @return `*this`. 189   @return `*this`.
190   @pre No awaitables returned by either object's methods exist. 190   @pre No awaitables returned by either object's methods exist.
191   */ 191   */
192   native_posix_stream_descriptor& 192   native_posix_stream_descriptor&
193   operator=(native_posix_stream_descriptor&&) noexcept = default; 193   operator=(native_posix_stream_descriptor&&) noexcept = default;
194   194  
195   /// Copy construction is disabled; the handle is uniquely owned. 195   /// Copy construction is disabled; the handle is uniquely owned.
196   native_posix_stream_descriptor(native_posix_stream_descriptor const&) = 196   native_posix_stream_descriptor(native_posix_stream_descriptor const&) =
197   delete; 197   delete;
198   /// Copy assignment is disabled; the handle is uniquely owned. 198   /// Copy assignment is disabled; the handle is uniquely owned.
199   native_posix_stream_descriptor& 199   native_posix_stream_descriptor&
200   operator=(native_posix_stream_descriptor const&) = delete; 200   operator=(native_posix_stream_descriptor const&) = delete;
201   201  
202   /** Asynchronously read data from the descriptor. 202   /** Asynchronously read data from the descriptor.
203   203  
204   Calls the backend implementation directly, bypassing virtual 204   Calls the backend implementation directly, bypassing virtual
205   dispatch. Otherwise identical to @ref io_stream::read_some. 205   dispatch. Otherwise identical to @ref io_stream::read_some.
206   206  
207   @param buffers The buffer sequence to read into. 207   @param buffers The buffer sequence to read into.
208   208  
209   @return An awaitable yielding `(error_code, std::size_t)`. 209   @return An awaitable yielding `(error_code, std::size_t)`.
210   */ 210   */
211   template<capy::MutableBufferSequence MB> 211   template<capy::MutableBufferSequence MB>
HITCBC 212   6 [[nodiscard]] auto read_some(MB const& buffers) 212   6 [[nodiscard]] auto read_some(MB const& buffers)
213   { 213   {
HITCBC 214   6 return native_read_awaitable<MB>(*this, buffers); 214   6 return native_read_awaitable<MB>(*this, buffers);
215   } 215   }
216   216  
217   /** Asynchronously write data to the descriptor. 217   /** Asynchronously write data to the descriptor.
218   218  
219   Calls the backend implementation directly, bypassing virtual 219   Calls the backend implementation directly, bypassing virtual
220   dispatch. Otherwise identical to @ref io_stream::write_some. 220   dispatch. Otherwise identical to @ref io_stream::write_some.
221   221  
222   @param buffers The buffer sequence to write from. 222   @param buffers The buffer sequence to write from.
223   223  
224   @return An awaitable yielding `(error_code, std::size_t)`. 224   @return An awaitable yielding `(error_code, std::size_t)`.
225   */ 225   */
226   template<capy::ConstBufferSequence CB> 226   template<capy::ConstBufferSequence CB>
HITCBC 227   2 [[nodiscard]] auto write_some(CB const& buffers) 227   2 [[nodiscard]] auto write_some(CB const& buffers)
228   { 228   {
HITCBC 229   2 return native_write_awaitable<CB>(*this, buffers); 229   2 return native_write_awaitable<CB>(*this, buffers);
230   } 230   }
231   231  
232   /** Wait for readiness without transferring bytes. 232   /** Wait for readiness without transferring bytes.
233   233  
234   Calls the backend implementation directly, bypassing virtual 234   Calls the backend implementation directly, bypassing virtual
235   dispatch. Otherwise identical to @ref posix_stream_descriptor::wait. 235   dispatch. Otherwise identical to @ref posix_stream_descriptor::wait.
236   236  
237   @param w The direction to wait on. 237   @param w The direction to wait on.
238   238  
239   @return An awaitable yielding `results<>`. 239   @return An awaitable yielding `results<>`.
240   */ 240   */
HITCBC 241   4 [[nodiscard]] auto wait(wait_type w) 241   4 [[nodiscard]] auto wait(wait_type w)
242   { 242   {
HITCBC 243   4 return native_wait_awaitable(*this, w); 243   4 return native_wait_awaitable(*this, w);
244   } 244   }
245   }; 245   };
246   246  
247   } // namespace boost::corosio 247   } // namespace boost::corosio
248   248  
249   #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS 249   #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS
250   250  
251   #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP 251   #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP