100.00% Lines (33/33) 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/io_result.hpp> 14   #include <boost/capy/io_result.hpp>
14   #include <boost/capy/ex/executor_ref.hpp> 15   #include <boost/capy/ex/executor_ref.hpp>
15   #include <boost/capy/ex/io_env.hpp> 16   #include <boost/capy/ex/io_env.hpp>
16   17  
17   #include <coroutine> 18   #include <coroutine>
18   #include <cstddef> 19   #include <cstddef>
19   #include <stop_token> 20   #include <stop_token>
20   #include <system_error> 21   #include <system_error>
21   22  
22   namespace boost::corosio::detail { 23   namespace boost::corosio::detail {
23   24  
24   /* CRTP base for awaitables that return io_result<std::size_t>. 25   /* CRTP base for awaitables that return io_result<std::size_t>.
25   26  
26   Derived classes must provide: 27   Derived classes must provide:
27   28  
28   std::coroutine_handle<> dispatch( 29   std::coroutine_handle<> dispatch(
29   std::coroutine_handle<> h, 30   std::coroutine_handle<> h,
30   capy::executor_ref ex) const; 31   capy::executor_ref ex) const;
31   32  
32   which forwards to the backend implementation method, passing 33   which forwards to the backend implementation method, passing
33   token_, &ec_, and &bytes_ as the cancellation/output parameters. 34   token_, &ec_, and &bytes_ as the cancellation/output parameters.
34   */ 35   */
35   template<class Derived> 36   template<class Derived>
36   class bytes_op_base 37   class bytes_op_base
37   { 38   {
38   friend Derived; 39   friend Derived;
HITCBC 39   436012 bytes_op_base() = default; 40   425285 bytes_op_base() = default;
40   41  
41   public: 42   public:
42   std::stop_token token_; 43   std::stop_token token_;
43   mutable std::error_code ec_; 44   mutable std::error_code ec_;
44   mutable std::size_t bytes_ = 0; 45   mutable std::size_t bytes_ = 0;
45   46  
HITCBC 46   436012 bool await_ready() const noexcept 47   425285 bool await_ready() const noexcept
47   { 48   {
48   // A pre-set ec_ means the initiator failed before dispatch 49   // A pre-set ec_ means the initiator failed before dispatch
49   // (e.g. a closed object); complete immediately with that error. 50   // (e.g. a closed object); complete immediately with that error.
HITCBC 50 - 436012 return static_cast<bool>(ec_) || token_.stop_requested(); 51 + 425285 return static_cast<bool>(ec_);
51   } 52   }
52   53  
HITCBC 53   435979 [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept 54   425250 [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept
54 - if (token_.stop_requested())  
DCB 55 - 435979 return {make_error_code(std::errc::operation_canceled), 0};  
ECB 56   243 { 55   {
HITCBC 57   435736 return {ec_, bytes_}; 56   425250 return {ec_, bytes_};
58   } 57   }
59   58  
HITCBC 60   435996 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 59   425249 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
61   -> std::coroutine_handle<> 60   -> std::coroutine_handle<>
62   { 61   {
HITCBC 63   435996 token_ = env->stop_token; 62   425249 token_ = env->stop_token;
  63 + // A pre-stopped token short-circuits before dispatch so no I/O
  64 + // is performed. A stop landing after dispatch is decoded by the
  65 + // backend, and a completed transfer is reported verbatim: the
  66 + // stream contracts forbid discarding the byte count.
HITGNC   67 + 425249 if (token_.stop_requested())
  68 + {
HITGNC   69 + 73 ec_ = capy::error::canceled;
HITGNC   70 + 73 return h;
  71 + }
HITCBC 64   435996 return static_cast<Derived const*>(this)->dispatch(h, env->executor); 72   425176 return static_cast<Derived const*>(this)->dispatch(h, env->executor);
65   } 73   }
66   }; 74   };
67   75  
68   /* CRTP base for awaitables that return io_result<Value> for a 76   /* CRTP base for awaitables that return io_result<Value> for a
69   moved-out result object (e.g. the resolver's result lists). 77   moved-out result object (e.g. the resolver's result lists).
70   78  
71   Derived classes must provide: 79   Derived classes must provide:
72   80  
73   std::coroutine_handle<> dispatch( 81   std::coroutine_handle<> dispatch(
74   std::coroutine_handle<> h, 82   std::coroutine_handle<> h,
75   capy::executor_ref ex) const; 83   capy::executor_ref ex) const;
76   84  
77   which forwards to the backend implementation method, passing 85   which forwards to the backend implementation method, passing
78   token_, &ec_, and &value_ as the cancellation/output parameters. 86   token_, &ec_, and &value_ as the cancellation/output parameters.
79   */ 87   */
80   template<class Derived, class Value> 88   template<class Derived, class Value>
81   class value_op_base 89   class value_op_base
82   { 90   {
83   friend Derived; 91   friend Derived;
HITCBC 84   50 value_op_base() = default; 92   381 value_op_base() = default;
85   93  
86   public: 94   public:
87   std::stop_token token_; 95   std::stop_token token_;
88   mutable std::error_code ec_; 96   mutable std::error_code ec_;
89   mutable Value value_{}; 97   mutable Value value_{};
90   98  
HITCBC 91   50 bool await_ready() const noexcept 99   381 bool await_ready() const noexcept
92   { 100   {
93   // A pre-set ec_ means the initiator failed before dispatch; 101   // A pre-set ec_ means the initiator failed before dispatch;
94   // complete immediately with that error. 102   // complete immediately with that error.
HITCBC 95 - 50 return static_cast<bool>(ec_) || token_.stop_requested(); 103 + 381 return static_cast<bool>(ec_);
96   } 104   }
97   105  
HITCBC 98   48 [[nodiscard]] capy::io_result<Value> await_resume() const noexcept 106   373 [[nodiscard]] capy::io_result<Value> await_resume() const noexcept
99 - if (token_.stop_requested())  
DCB 100 - 48 return {make_error_code(std::errc::operation_canceled), {}};  
ECB 101   2 { 107   {
HITCBC 102   46 return {ec_, std::move(value_)}; 108   373 return {ec_, std::move(value_)};
103   } 109   }
104   110  
HITCBC 105   50 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 111   381 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
106   -> std::coroutine_handle<> 112   -> std::coroutine_handle<>
107   { 113   {
HITCBC 108   50 token_ = env->stop_token; 114   381 token_ = env->stop_token;
  115 + // A pre-stopped token short-circuits before dispatch; a stop
  116 + // landing after dispatch leaves the completed result intact.
HITGNC   117 + 381 if (token_.stop_requested())
  118 + {
HITGNC   119 + 6 ec_ = capy::error::canceled;
HITGNC   120 + 6 return h;
  121 + }
HITCBC 109   50 return static_cast<Derived const*>(this)->dispatch(h, env->executor); 122   375 return static_cast<Derived const*>(this)->dispatch(h, env->executor);
110   } 123   }
111   }; 124   };
112   125  
113   /* CRTP base for awaitables that return io_result<>. 126   /* CRTP base for awaitables that return io_result<>.
114   127  
115   Derived classes must provide: 128   Derived classes must provide:
116   129  
117   std::coroutine_handle<> dispatch( 130   std::coroutine_handle<> dispatch(
118   std::coroutine_handle<> h, 131   std::coroutine_handle<> h,
119   capy::executor_ref ex) const; 132   capy::executor_ref ex) const;
120   133  
121   which forwards to the backend implementation method, passing 134   which forwards to the backend implementation method, passing
122   token_ and &ec_ as the cancellation/output parameters. 135   token_ and &ec_ as the cancellation/output parameters.
123   */ 136   */
124   template<class Derived> 137   template<class Derived>
125   class void_op_base 138   class void_op_base
126   { 139   {
127   friend Derived; 140   friend Derived;
HITCBC 128   4634 void_op_base() = default; 141   9269 void_op_base() = default;
129   142  
130   public: 143   public:
131   std::stop_token token_; 144   std::stop_token token_;
132   mutable std::error_code ec_; 145   mutable std::error_code ec_;
133   146  
HITCBC 134   4634 bool await_ready() const noexcept 147   9269 bool await_ready() const noexcept
135   { 148   {
136   // A pre-set ec_ means the initiator failed before dispatch 149   // A pre-set ec_ means the initiator failed before dispatch
137   // (e.g. auto-open); complete immediately with that error. 150   // (e.g. auto-open); complete immediately with that error.
HITCBC 138 - 4634 return static_cast<bool>(ec_) || token_.stop_requested(); 151 + 9269 return static_cast<bool>(ec_);
139   } 152   }
140   153  
HITCBC 141   4621 [[nodiscard]] capy::io_result<> await_resume() const noexcept 154   4710 [[nodiscard]] capy::io_result<> await_resume() const noexcept
142 - if (token_.stop_requested())  
DCB 143 - 4621 return {make_error_code(std::errc::operation_canceled)};  
ECB 144   32 { 155   {
HITCBC 145   4589 return {ec_}; 156   4710 return {ec_};
146   } 157   }
147   158  
HITCBC 148   4630 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 159   9247 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
149   -> std::coroutine_handle<> 160   -> std::coroutine_handle<>
150   { 161   {
HITCBC 151   4630 token_ = env->stop_token; 162   9247 token_ = env->stop_token;
  163 + // A pre-stopped token short-circuits before dispatch; a stop
  164 + // landing after dispatch leaves the completed result intact.
HITGNC   165 + 9247 if (token_.stop_requested())
  166 + {
HITGNC   167 + 51 ec_ = capy::error::canceled;
HITGNC   168 + 51 return h;
  169 + }
HITCBC 152   4630 return static_cast<Derived const*>(this)->dispatch(h, env->executor); 170   9196 return static_cast<Derived const*>(this)->dispatch(h, env->executor);
153   } 171   }
154   }; 172   };
155   173  
156   } // namespace boost::corosio::detail 174   } // namespace boost::corosio::detail
157   175  
158   #endif // BOOST_COROSIO_DETAIL_OP_BASE_HPP 176   #endif // BOOST_COROSIO_DETAIL_OP_BASE_HPP