100.00% Lines (31/31) 100.00% Functions (11/11)
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_STREAM_DESCRIPTOR_HPP
  11 + #define BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP
  12 +
  13 + #include <boost/corosio/detail/op_base.hpp>
  14 + #include <boost/corosio/posix_stream_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_stream_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_stream_descriptor` IS-A `posix_stream_descriptor` and can be
  52 + passed to any function expecting `posix_stream_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_stream_descriptor.
  61 +
  62 + @par Example
  63 + @par !example assign_and_wait
  64 +
  65 + @see posix_stream_descriptor, epoll_t, kqueue_t
  66 + */
  67 + template<auto Backend>
  68 + class native_posix_stream_descriptor : public posix_stream_descriptor
  69 + {
  70 + using backend_type = decltype(Backend);
  71 + using impl_type = typename backend_type::stream_descriptor_type;
  72 + using service_type = typename backend_type::stream_descriptor_service_type;
  73 +
HITGNC   74 + 8 impl_type& get_impl() noexcept
  75 + {
HITGNC   76 + 8 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_stream_descriptor& self_;
  84 + MutableBufferSequence buffers_;
  85 +
HITGNC   86 + 6 native_read_awaitable(
  87 + native_posix_stream_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_stream_descriptor& self_;
  107 + ConstBufferSequence buffers_;
  108 +
HITGNC   109 + 2 native_write_awaitable(
  110 + native_posix_stream_descriptor& self,
  111 + ConstBufferSequence buffers) noexcept
HITGNC   112 + 2 : self_(self)
HITGNC   113 + 2 , buffers_(std::move(buffers))
  114 + {
HITGNC   115 + 2 }
  116 +
  117 + std::coroutine_handle<>
HITGNC   118 + 2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
  119 + {
HITGNC   120 + 6 return self_.get_impl().write_some(
HITGNC   121 + 6 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
  122 + }
  123 + };
  124 +
  125 + struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
  126 + {
  127 + native_posix_stream_descriptor& self_;
  128 + wait_type w_;
  129 +
HITGNC   130 + 4 native_wait_awaitable(
  131 + native_posix_stream_descriptor& self, wait_type w) noexcept
HITGNC   132 + 4 : self_(self)
HITGNC   133 + 4 , w_(w)
  134 + {
HITGNC   135 + 4 }
  136 +
  137 + std::coroutine_handle<>
HITGNC   138 + 2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
  139 + {
HITGNC   140 + 2 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
  141 + }
  142 + };
  143 +
  144 + public:
  145 + /** Construct a `native_posix_stream_descriptor` from an execution
  146 + context.
  147 +
  148 + @param ctx The execution context that owns this object.
  149 + */
HITGNC   150 + 14 explicit native_posix_stream_descriptor(capy::execution_context& ctx)
HITGNC   151 + 14 : io_object(handle(ctx, ctx.use_service<service_type>()))
  152 + {
HITGNC   153 + 14 }
  154 +
  155 + /** Construct a `native_posix_stream_descriptor` from an executor.
  156 +
  157 + The overload excludes `native_posix_stream_descriptor` itself so
  158 + that it cannot displace the move constructor.
  159 +
  160 + @tparam Ex A type satisfying `capy::Executor`.
  161 + @param ex The executor whose context owns this object.
  162 + */
  163 + template<class Ex>
  164 + requires(!std::same_as<
  165 + std::remove_cvref_t<Ex>,
  166 + native_posix_stream_descriptor>) &&
  167 + capy::Executor<Ex>
  168 + explicit native_posix_stream_descriptor(Ex const& ex)
  169 + : native_posix_stream_descriptor(ex.context())
  170 + {
  171 + }
  172 +
  173 + /** Transfer ownership of the descriptor from the source.
  174 +
  175 + After the move, the source is in a moved-from state and may
  176 + only be destroyed or assigned to.
  177 +
  178 + @pre No awaitables returned by the source's methods exist.
  179 + */
  180 + native_posix_stream_descriptor(native_posix_stream_descriptor&&) noexcept =
  181 + default;
  182 +
  183 + /** Close any held descriptor and transfer ownership from the source.
  184 +
  185 + After the move, the source is in a moved-from state and may
  186 + only be destroyed or assigned to.
  187 +
  188 + @return `*this`.
  189 + @pre No awaitables returned by either object's methods exist.
  190 + */
  191 + native_posix_stream_descriptor&
  192 + operator=(native_posix_stream_descriptor&&) noexcept = default;
  193 +
  194 + /// Copy construction is disabled; the handle is uniquely owned.
  195 + native_posix_stream_descriptor(native_posix_stream_descriptor const&) =
  196 + delete;
  197 + /// Copy assignment is disabled; the handle is uniquely owned.
  198 + native_posix_stream_descriptor&
  199 + operator=(native_posix_stream_descriptor const&) = delete;
  200 +
  201 + /** Asynchronously read data from the descriptor.
  202 +
  203 + Calls the backend implementation directly, bypassing virtual
  204 + dispatch. Otherwise identical to @ref io_stream::read_some.
  205 +
  206 + @param buffers The buffer sequence to read into.
  207 +
  208 + @return An awaitable yielding `(error_code, std::size_t)`.
  209 + */
  210 + template<capy::MutableBufferSequence MB>
HITGNC   211 + 6 [[nodiscard]] auto read_some(MB const& buffers)
  212 + {
HITGNC   213 + 6 return native_read_awaitable<MB>(*this, buffers);
  214 + }
  215 +
  216 + /** Asynchronously write data to the descriptor.
  217 +
  218 + Calls the backend implementation directly, bypassing virtual
  219 + dispatch. Otherwise identical to @ref io_stream::write_some.
  220 +
  221 + @param buffers The buffer sequence to write from.
  222 +
  223 + @return An awaitable yielding `(error_code, std::size_t)`.
  224 + */
  225 + template<capy::ConstBufferSequence CB>
HITGNC   226 + 2 [[nodiscard]] auto write_some(CB const& buffers)
  227 + {
HITGNC   228 + 2 return native_write_awaitable<CB>(*this, buffers);
  229 + }
  230 +
  231 + /** Wait for readiness without transferring bytes.
  232 +
  233 + Calls the backend implementation directly, bypassing virtual
  234 + dispatch. Otherwise identical to @ref posix_stream_descriptor::wait.
  235 +
  236 + @param w The direction to wait on.
  237 +
  238 + @return An awaitable yielding `io_result<>`.
  239 + */
HITGNC   240 + 4 [[nodiscard]] auto wait(wait_type w)
  241 + {
HITGNC   242 + 4 return native_wait_awaitable(*this, w);
  243 + }
  244 + };
  245 +
  246 + } // namespace boost::corosio
  247 +
  248 + #endif // BOOST_COROSIO_POSIX || BOOST_COROSIO_MRDOCS
  249 +
  250 + #endif // BOOST_COROSIO_NATIVE_NATIVE_POSIX_STREAM_DESCRIPTOR_HPP