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