100.00% Lines (42/42)
100.00% Functions (12/12)
| 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_DETAIL_OP_BASE_HPP | 10 | #ifndef BOOST_COROSIO_DETAIL_OP_BASE_HPP | |||||
| 11 | #define BOOST_COROSIO_DETAIL_OP_BASE_HPP | 11 | #define BOOST_COROSIO_DETAIL_OP_BASE_HPP | |||||
| 12 | 12 | |||||||
| 13 | #include <boost/capy/error.hpp> | 13 | #include <boost/capy/error.hpp> | |||||
| 14 | #include <boost/capy/continuation.hpp> | 14 | #include <boost/capy/continuation.hpp> | |||||
| 15 | #include <boost/capy/results.hpp> | 15 | #include <boost/capy/results.hpp> | |||||
| 16 | #include <boost/capy/ex/executor_ref.hpp> | 16 | #include <boost/capy/ex/executor_ref.hpp> | |||||
| 17 | #include <boost/capy/ex/await_context.hpp> | 17 | #include <boost/capy/ex/await_context.hpp> | |||||
| 18 | 18 | |||||||
| 19 | #include <coroutine> | 19 | #include <coroutine> | |||||
| 20 | #include <cstddef> | 20 | #include <cstddef> | |||||
| 21 | #include <stop_token> | 21 | #include <stop_token> | |||||
| 22 | #include <system_error> | 22 | #include <system_error> | |||||
| 23 | 23 | |||||||
| 24 | namespace boost::corosio::detail { | 24 | namespace boost::corosio::detail { | |||||
| 25 | 25 | |||||||
| 26 | /* CRTP base for awaitables that return results<std::size_t>. | 26 | /* CRTP base for awaitables that return results<std::size_t>. | |||||
| 27 | 27 | |||||||
| 28 | Derived classes must provide: | 28 | Derived classes must provide: | |||||
| 29 | 29 | |||||||
| 30 | std::coroutine_handle<> dispatch( | 30 | std::coroutine_handle<> dispatch( | |||||
| 31 | capy::continuation& cont, | 31 | capy::continuation& cont, | |||||
| 32 | capy::executor_ref ex) const; | 32 | capy::executor_ref ex) const; | |||||
| 33 | 33 | |||||||
| 34 | which forwards to the backend implementation method, passing | 34 | which forwards to the backend implementation method, passing | |||||
| 35 | token_, &ec_, and &bytes_ as the cancellation/output parameters. | 35 | token_, &ec_, and &bytes_ as the cancellation/output parameters. | |||||
| 36 | */ | 36 | */ | |||||
| 37 | template<class Derived> | 37 | template<class Derived> | |||||
| 38 | class bytes_op_base | 38 | class bytes_op_base | |||||
| 39 | { | 39 | { | |||||
| 40 | friend Derived; | 40 | friend Derived; | |||||
| HITCBC | 41 | 452658 | bytes_op_base() = default; | 41 | 476006 | bytes_op_base() = default; | ||
| 42 | 42 | |||||||
| 43 | public: | 43 | public: | |||||
| 44 | std::stop_token token_; | 44 | std::stop_token token_; | |||||
| 45 | mutable std::error_code ec_; | 45 | mutable std::error_code ec_; | |||||
| 46 | mutable std::size_t bytes_ = 0; | 46 | mutable std::size_t bytes_ = 0; | |||||
| 47 | // Lives in the awaiting frame until resumption, so a completion | 47 | // Lives in the awaiting frame until resumption, so a completion | |||||
| 48 | // posted through an executor never shares the object's state. | 48 | // posted through an executor never shares the object's state. | |||||
| 49 | mutable capy::continuation cont_; | 49 | mutable capy::continuation cont_; | |||||
| 50 | 50 | |||||||
| HITCBC | 51 | 452658 | bool await_ready() const noexcept | 51 | 476006 | bool await_ready() const noexcept | ||
| 52 | { | 52 | { | |||||
| 53 | // A pre-set ec_ means the initiator failed before dispatch | 53 | // A pre-set ec_ means the initiator failed before dispatch | |||||
| 54 | // (e.g. a closed object); complete immediately with that error. | 54 | // (e.g. a closed object); complete immediately with that error. | |||||
| HITCBC | 55 | 452658 | return static_cast<bool>(ec_); | 55 | 476006 | return static_cast<bool>(ec_); | ||
| 56 | } | 56 | } | |||||
| 57 | 57 | |||||||
| HITCBC | 58 | 452195 | [[nodiscard]] capy::results<std::size_t> await_resume() const noexcept | 58 | 475543 | [[nodiscard]] capy::results<std::size_t> await_resume() const noexcept | ||
| 59 | { | 59 | { | |||||
| HITCBC | 60 | 452195 | return {ec_, bytes_}; | 60 | 475543 | return {ec_, bytes_}; | ||
| 61 | } | 61 | } | |||||
| 62 | 62 | |||||||
| HITCBC | 63 | 452622 | auto await_suspend(std::coroutine_handle<> h, capy::await_context const* env) | 63 | 475970 | auto await_suspend(std::coroutine_handle<> h, capy::await_context const* env) | ||
| 64 | -> std::coroutine_handle<> | 64 | -> std::coroutine_handle<> | |||||
| 65 | { | 65 | { | |||||
| HITCBC | 66 | 452622 | token_ = env->stop_token; | 66 | 475970 | token_ = env->stop_token; | ||
| 67 | // A pre-stopped token short-circuits before dispatch so no I/O | 67 | // A pre-stopped token short-circuits before dispatch so no I/O | |||||
| 68 | // is performed. A stop landing after dispatch is decoded by the | 68 | // is performed. A stop landing after dispatch is decoded by the | |||||
| 69 | // backend, and a completed transfer is reported verbatim: the | 69 | // backend, and a completed transfer is reported verbatim: the | |||||
| 70 | // stream contracts forbid discarding the byte count. | 70 | // stream contracts forbid discarding the byte count. | |||||
| HITCBC | 71 | 452622 | if (token_.stop_requested()) | 71 | 475970 | if (token_.stop_requested()) | ||
| 72 | { | 72 | { | |||||
| HITCBC | 73 | 129 | ec_ = capy::error::canceled; | 73 | 119 | ec_ = capy::error::canceled; | ||
| HITCBC | 74 | 129 | return h; | 74 | 119 | return h; | ||
| 75 | } | 75 | } | |||||
| HITCBC | 76 | 452493 | cont_.h = h; | 76 | 475851 | cont_.h = h; | ||
| HITCBC | 77 | 452493 | cont_.owner = env->owner; | 77 | 475851 | cont_.owner = env->owner; | ||
| HITCBC | 78 | 452493 | return static_cast<Derived const*>(this)->dispatch( | 78 | 475851 | return static_cast<Derived const*>(this)->dispatch( | ||
| HITCBC | 79 | 452493 | cont_, env->executor); | 79 | 475851 | cont_, env->executor); | ||
| 80 | } | 80 | } | |||||
| 81 | }; | 81 | }; | |||||
| 82 | 82 | |||||||
| 83 | /* CRTP base for awaitables that return results<Value> for a | 83 | /* CRTP base for awaitables that return results<Value> for a | |||||
| 84 | moved-out result object (e.g. the resolver's result lists). | 84 | moved-out result object (e.g. the resolver's result lists). | |||||
| 85 | 85 | |||||||
| 86 | Derived classes must provide: | 86 | Derived classes must provide: | |||||
| 87 | 87 | |||||||
| 88 | std::coroutine_handle<> dispatch( | 88 | std::coroutine_handle<> dispatch( | |||||
| 89 | capy::continuation& cont, | 89 | capy::continuation& cont, | |||||
| 90 | capy::executor_ref ex) const; | 90 | capy::executor_ref ex) const; | |||||
| 91 | 91 | |||||||
| 92 | which forwards to the backend implementation method, passing | 92 | which forwards to the backend implementation method, passing | |||||
| 93 | token_, &ec_, and &value_ as the cancellation/output parameters. | 93 | token_, &ec_, and &value_ as the cancellation/output parameters. | |||||
| 94 | */ | 94 | */ | |||||
| 95 | template<class Derived, class Value> | 95 | template<class Derived, class Value> | |||||
| 96 | class value_op_base | 96 | class value_op_base | |||||
| 97 | { | 97 | { | |||||
| 98 | friend Derived; | 98 | friend Derived; | |||||
| HITCBC | 99 | 205894 | value_op_base() = default; | 99 | 206085 | value_op_base() = default; | ||
| 100 | 100 | |||||||
| 101 | public: | 101 | public: | |||||
| 102 | std::stop_token token_; | 102 | std::stop_token token_; | |||||
| 103 | mutable std::error_code ec_; | 103 | mutable std::error_code ec_; | |||||
| 104 | mutable Value value_{}; | 104 | mutable Value value_{}; | |||||
| 105 | // See bytes_op_base::cont_. | 105 | // See bytes_op_base::cont_. | |||||
| 106 | mutable capy::continuation cont_; | 106 | mutable capy::continuation cont_; | |||||
| 107 | 107 | |||||||
| HITCBC | 108 | 205894 | bool await_ready() const noexcept | 108 | 206085 | bool await_ready() const noexcept | ||
| 109 | { | 109 | { | |||||
| 110 | // A pre-set ec_ means the initiator failed before dispatch; | 110 | // A pre-set ec_ means the initiator failed before dispatch; | |||||
| 111 | // complete immediately with that error. | 111 | // complete immediately with that error. | |||||
| HITCBC | 112 | 205894 | return static_cast<bool>(ec_); | 112 | 206085 | return static_cast<bool>(ec_); | ||
| 113 | } | 113 | } | |||||
| 114 | 114 | |||||||
| HITCBC | 115 | 202670 | [[nodiscard]] capy::results<Value> await_resume() const noexcept | 115 | 202861 | [[nodiscard]] capy::results<Value> await_resume() const noexcept | ||
| 116 | { | 116 | { | |||||
| HITCBC | 117 | 202670 | return {ec_, std::move(value_)}; | 117 | 202861 | return {ec_, std::move(value_)}; | ||
| 118 | } | 118 | } | |||||
| 119 | 119 | |||||||
| HITCBC | 120 | 205894 | auto await_suspend(std::coroutine_handle<> h, capy::await_context const* env) | 120 | 206085 | auto await_suspend(std::coroutine_handle<> h, capy::await_context const* env) | ||
| 121 | -> std::coroutine_handle<> | 121 | -> std::coroutine_handle<> | |||||
| 122 | { | 122 | { | |||||
| HITCBC | 123 | 205894 | token_ = env->stop_token; | 123 | 206085 | token_ = env->stop_token; | ||
| 124 | // A pre-stopped token short-circuits before dispatch; a stop | 124 | // A pre-stopped token short-circuits before dispatch; a stop | |||||
| 125 | // landing after dispatch leaves the completed result intact. | 125 | // landing after dispatch leaves the completed result intact. | |||||
| HITCBC | 126 | 205894 | if (token_.stop_requested()) | 126 | 206085 | if (token_.stop_requested()) | ||
| 127 | { | 127 | { | |||||
| HITCBC | 128 | 30 | ec_ = capy::error::canceled; | 128 | 34 | ec_ = capy::error::canceled; | ||
| HITCBC | 129 | 30 | return h; | 129 | 34 | return h; | ||
| 130 | } | 130 | } | |||||
| HITCBC | 131 | 205864 | cont_.h = h; | 131 | 206051 | cont_.h = h; | ||
| HITCBC | 132 | 205864 | cont_.owner = env->owner; | 132 | 206051 | cont_.owner = env->owner; | ||
| HITCBC | 133 | 205864 | return static_cast<Derived const*>(this)->dispatch( | 133 | 206051 | return static_cast<Derived const*>(this)->dispatch( | ||
| HITCBC | 134 | 205864 | cont_, env->executor); | 134 | 206051 | cont_, env->executor); | ||
| 135 | } | 135 | } | |||||
| 136 | }; | 136 | }; | |||||
| 137 | 137 | |||||||
| 138 | /* CRTP base for awaitables that return results<>. | 138 | /* CRTP base for awaitables that return results<>. | |||||
| 139 | 139 | |||||||
| 140 | Derived classes must provide: | 140 | Derived classes must provide: | |||||
| 141 | 141 | |||||||
| 142 | std::coroutine_handle<> dispatch( | 142 | std::coroutine_handle<> dispatch( | |||||
| 143 | capy::continuation& cont, | 143 | capy::continuation& cont, | |||||
| 144 | capy::executor_ref ex) const; | 144 | capy::executor_ref ex) const; | |||||
| 145 | 145 | |||||||
| 146 | which forwards to the backend implementation method, passing | 146 | which forwards to the backend implementation method, passing | |||||
| 147 | token_ and &ec_ as the cancellation/output parameters. | 147 | token_ and &ec_ as the cancellation/output parameters. | |||||
| 148 | */ | 148 | */ | |||||
| 149 | template<class Derived> | 149 | template<class Derived> | |||||
| 150 | class void_op_base | 150 | class void_op_base | |||||
| 151 | { | 151 | { | |||||
| 152 | friend Derived; | 152 | friend Derived; | |||||
| HITCBC | 153 | 17242 | void_op_base() = default; | 153 | 17039 | void_op_base() = default; | ||
| 154 | 154 | |||||||
| 155 | public: | 155 | public: | |||||
| 156 | std::stop_token token_; | 156 | std::stop_token token_; | |||||
| 157 | mutable std::error_code ec_; | 157 | mutable std::error_code ec_; | |||||
| 158 | // See bytes_op_base::cont_. | 158 | // See bytes_op_base::cont_. | |||||
| 159 | mutable capy::continuation cont_; | 159 | mutable capy::continuation cont_; | |||||
| 160 | 160 | |||||||
| HITCBC | 161 | 17242 | bool await_ready() const noexcept | 161 | 17039 | bool await_ready() const noexcept | ||
| 162 | { | 162 | { | |||||
| 163 | // A pre-set ec_ means the initiator failed before dispatch | 163 | // A pre-set ec_ means the initiator failed before dispatch | |||||
| 164 | // (e.g. auto-open); complete immediately with that error. | 164 | // (e.g. auto-open); complete immediately with that error. | |||||
| HITCBC | 165 | 17242 | return static_cast<bool>(ec_); | 165 | 17039 | return static_cast<bool>(ec_); | ||
| 166 | } | 166 | } | |||||
| 167 | 167 | |||||||
| HITCBC | 168 | 9808 | [[nodiscard]] capy::results<> await_resume() const noexcept | 168 | 9487 | [[nodiscard]] capy::results<> await_resume() const noexcept | ||
| 169 | { | 169 | { | |||||
| HITCBC | 170 | 9808 | return {ec_}; | 170 | 9487 | return {ec_}; | ||
| 171 | } | 171 | } | |||||
| 172 | 172 | |||||||
| HITCBC | 173 | 17220 | auto await_suspend(std::coroutine_handle<> h, capy::await_context const* env) | 173 | 17017 | auto await_suspend(std::coroutine_handle<> h, capy::await_context const* env) | ||
| 174 | -> std::coroutine_handle<> | 174 | -> std::coroutine_handle<> | |||||
| 175 | { | 175 | { | |||||
| HITCBC | 176 | 17220 | token_ = env->stop_token; | 176 | 17017 | token_ = env->stop_token; | ||
| 177 | // A pre-stopped token short-circuits before dispatch; a stop | 177 | // A pre-stopped token short-circuits before dispatch; a stop | |||||
| 178 | // landing after dispatch leaves the completed result intact. | 178 | // landing after dispatch leaves the completed result intact. | |||||
| HITCBC | 179 | 17220 | if (token_.stop_requested()) | 179 | 17017 | if (token_.stop_requested()) | ||
| 180 | { | 180 | { | |||||
| HITCBC | 181 | 1059 | ec_ = capy::error::canceled; | 181 | 1064 | ec_ = capy::error::canceled; | ||
| HITCBC | 182 | 1059 | return h; | 182 | 1064 | return h; | ||
| 183 | } | 183 | } | |||||
| HITCBC | 184 | 16161 | cont_.h = h; | 184 | 15953 | cont_.h = h; | ||
| HITCBC | 185 | 16161 | cont_.owner = env->owner; | 185 | 15953 | cont_.owner = env->owner; | ||
| HITCBC | 186 | 16161 | return static_cast<Derived const*>(this)->dispatch( | 186 | 15953 | return static_cast<Derived const*>(this)->dispatch( | ||
| HITCBC | 187 | 16161 | cont_, env->executor); | 187 | 15953 | cont_, env->executor); | ||
| 188 | } | 188 | } | |||||
| 189 | }; | 189 | }; | |||||
| 190 | 190 | |||||||
| 191 | } // namespace boost::corosio::detail | 191 | } // namespace boost::corosio::detail | |||||
| 192 | 192 | |||||||
| 193 | #endif // BOOST_COROSIO_DETAIL_OP_BASE_HPP | 193 | #endif // BOOST_COROSIO_DETAIL_OP_BASE_HPP | |||||