0.00% Lines (0/0)
0.00% Functions (0/0)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | - | // | ||||||
| 2 | - | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | ||||||
| 3 | - | // Copyright (c) 2026 Michael Vandeberg | ||||||
| 4 | - | // | ||||||
| 5 | - | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||||
| 6 | - | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||||
| 7 | - | // | ||||||
| 8 | - | // Official repository: https://github.com/cppalliance/capy | ||||||
| 9 | - | // | ||||||
| 10 | - | |||||||
| 11 | - | #ifndef BOOST_CAPY_TEST_WRITE_SINK_HPP | ||||||
| 12 | - | #define BOOST_CAPY_TEST_WRITE_SINK_HPP | ||||||
| 13 | - | |||||||
| 14 | - | #include <boost/capy/detail/config.hpp> | ||||||
| 15 | - | #include <boost/capy/buffers.hpp> | ||||||
| 16 | - | #include <boost/capy/buffers/buffer_copy.hpp> | ||||||
| 17 | - | #include <boost/capy/buffers/make_buffer.hpp> | ||||||
| 18 | - | #include <coroutine> | ||||||
| 19 | - | #include <boost/capy/ex/io_env.hpp> | ||||||
| 20 | - | #include <boost/capy/io_result.hpp> | ||||||
| 21 | - | #include <boost/capy/error.hpp> | ||||||
| 22 | - | #include <boost/capy/test/fuse.hpp> | ||||||
| 23 | - | |||||||
| 24 | - | #include <algorithm> | ||||||
| 25 | - | #include <string> | ||||||
| 26 | - | #include <string_view> | ||||||
| 27 | - | |||||||
| 28 | - | namespace boost { | ||||||
| 29 | - | namespace capy { | ||||||
| 30 | - | namespace test { | ||||||
| 31 | - | |||||||
| 32 | - | /** A mock sink for testing write operations. | ||||||
| 33 | - | |||||||
| 34 | - | Use this to verify code that performs complete writes without needing | ||||||
| 35 | - | real I/O. Call @ref write to write data, then @ref data to retrieve | ||||||
| 36 | - | what was written. The associated @ref fuse enables error injection | ||||||
| 37 | - | at controlled points. | ||||||
| 38 | - | |||||||
| 39 | - | This class satisfies the @ref WriteSink concept by providing partial | ||||||
| 40 | - | writes via `write_some` (satisfying @ref WriteStream), complete | ||||||
| 41 | - | writes via `write`, and EOF signaling via `write_eof`. | ||||||
| 42 | - | |||||||
| 43 | - | @par Thread Safety | ||||||
| 44 | - | Not thread-safe. | ||||||
| 45 | - | |||||||
| 46 | - | @par Example | ||||||
| 47 | - | @code | ||||||
| 48 | - | fuse f; | ||||||
| 49 | - | write_sink ws( f ); | ||||||
| 50 | - | |||||||
| 51 | - | auto r = f.armed( [&]( fuse& ) -> task<void> { | ||||||
| 52 | - | auto [ec, n] = co_await ws.write( | ||||||
| 53 | - | const_buffer( "Hello", 5 ) ); | ||||||
| 54 | - | if( ec ) | ||||||
| 55 | - | co_return; | ||||||
| 56 | - | auto [ec2] = co_await ws.write_eof(); | ||||||
| 57 | - | if( ec2 ) | ||||||
| 58 | - | co_return; | ||||||
| 59 | - | // ws.data() returns "Hello" | ||||||
| 60 | - | } ); | ||||||
| 61 | - | @endcode | ||||||
| 62 | - | |||||||
| 63 | - | @see fuse, WriteSink | ||||||
| 64 | - | */ | ||||||
| 65 | - | class write_sink | ||||||
| 66 | - | { | ||||||
| 67 | - | fuse f_; | ||||||
| 68 | - | std::string data_; | ||||||
| 69 | - | std::string expect_; | ||||||
| 70 | - | std::size_t max_write_size_; | ||||||
| 71 | - | bool eof_called_ = false; | ||||||
| 72 | - | |||||||
| 73 | - | std::error_code | ||||||
| DCB | 74 | - | 236 | consume_match_() noexcept | ||||
| 75 | - | { | ||||||
| DCB | 76 | - | 236 | if(data_.empty() || expect_.empty()) | ||||
| DCB | 77 | - | 228 | return {}; | ||||
| DCB | 78 | - | 8 | std::size_t const n = (std::min)(data_.size(), expect_.size()); | ||||
| DCB | 79 | - | 8 | if(std::string_view(data_.data(), n) != | ||||
| DCB | 80 | - | 16 | std::string_view(expect_.data(), n)) | ||||
| DCB | 81 | - | 4 | return error::test_failure; | ||||
| DCB | 82 | - | 4 | data_.erase(0, n); | ||||
| DCB | 83 | - | 4 | expect_.erase(0, n); | ||||
| DCB | 84 | - | 4 | return {}; | ||||
| 85 | - | } | ||||||
| 86 | - | |||||||
| 87 | - | public: | ||||||
| 88 | - | /** Construct a write sink. | ||||||
| 89 | - | |||||||
| 90 | - | @param f The fuse used to inject errors during writes. | ||||||
| 91 | - | |||||||
| 92 | - | @param max_write_size Maximum bytes transferred per write. | ||||||
| 93 | - | Use to simulate chunked delivery. | ||||||
| 94 | - | */ | ||||||
| DCB | 95 | - | 416 | explicit write_sink( | ||||
| 96 | - | fuse f = {}, | ||||||
| 97 | - | std::size_t max_write_size = std::size_t(-1)) noexcept | ||||||
| DCB | 98 | - | 416 | : f_(std::move(f)) | ||||
| DCB | 99 | - | 416 | , max_write_size_(max_write_size) | ||||
| 100 | - | { | ||||||
| DCB | 101 | - | 416 | } | ||||
| 102 | - | |||||||
| 103 | - | /// Return the written data as a string view. | ||||||
| 104 | - | std::string_view | ||||||
| DCB | 105 | - | 100 | data() const noexcept | ||||
| 106 | - | { | ||||||
| DCB | 107 | - | 100 | return data_; | ||||
| 108 | - | } | ||||||
| 109 | - | |||||||
| 110 | - | /** Set the expected data for subsequent writes. | ||||||
| 111 | - | |||||||
| 112 | - | Stores the expected data and immediately tries to match | ||||||
| 113 | - | against any data already written. Matched data is consumed | ||||||
| 114 | - | from both buffers. | ||||||
| 115 | - | |||||||
| 116 | - | @param sv The expected data. | ||||||
| 117 | - | |||||||
| 118 | - | @return An error if existing data does not match. | ||||||
| 119 | - | */ | ||||||
| 120 | - | std::error_code | ||||||
| DCB | 121 | - | 16 | expect(std::string_view sv) | ||||
| 122 | - | { | ||||||
| DCB | 123 | - | 16 | expect_.assign(sv); | ||||
| DCB | 124 | - | 16 | return consume_match_(); | ||||
| 125 | - | } | ||||||
| 126 | - | |||||||
| 127 | - | /// Return the number of bytes written. | ||||||
| 128 | - | std::size_t | ||||||
| DCB | 129 | - | 9 | size() const noexcept | ||||
| 130 | - | { | ||||||
| DCB | 131 | - | 9 | return data_.size(); | ||||
| 132 | - | } | ||||||
| 133 | - | |||||||
| 134 | - | /// Return whether write_eof has been called. | ||||||
| 135 | - | bool | ||||||
| DCB | 136 | - | 66 | eof_called() const noexcept | ||||
| 137 | - | { | ||||||
| DCB | 138 | - | 66 | return eof_called_; | ||||
| 139 | - | } | ||||||
| 140 | - | |||||||
| 141 | - | /// Clear all data and reset state. | ||||||
| 142 | - | void | ||||||
| DCB | 143 | - | 4 | clear() noexcept | ||||
| 144 | - | { | ||||||
| DCB | 145 | - | 4 | data_.clear(); | ||||
| DCB | 146 | - | 4 | expect_.clear(); | ||||
| DCB | 147 | - | 4 | eof_called_ = false; | ||||
| DCB | 148 | - | 4 | } | ||||
| 149 | - | |||||||
| 150 | - | /** Asynchronously write some data to the sink. | ||||||
| 151 | - | |||||||
| 152 | - | Transfers up to `buffer_size( buffers )` bytes from the provided | ||||||
| 153 | - | const buffer sequence to the internal buffer. Before every write, | ||||||
| 154 | - | the attached @ref fuse is consulted to possibly inject an error. | ||||||
| 155 | - | |||||||
| 156 | - | @param buffers The const buffer sequence containing data to write. | ||||||
| 157 | - | |||||||
| 158 | - | @return An awaitable that await-returns `(error_code,std::size_t)`. | ||||||
| 159 | - | |||||||
| 160 | - | @par Cancellation | ||||||
| 161 | - | If the environment's stop token has been requested, the write | ||||||
| 162 | - | completes immediately with `error::canceled` and transfers no | ||||||
| 163 | - | data. An empty buffer sequence is a no-op that completes | ||||||
| 164 | - | successfully regardless of the stop token. | ||||||
| 165 | - | |||||||
| 166 | - | @see fuse | ||||||
| 167 | - | */ | ||||||
| 168 | - | template<ConstBufferSequence CB> | ||||||
| 169 | - | auto | ||||||
| DCB | 170 | - | 77 | write_some(CB buffers) | ||||
| 171 | - | { | ||||||
| 172 | - | struct awaitable | ||||||
| 173 | - | { | ||||||
| 174 | - | write_sink* self_; | ||||||
| 175 | - | CB buffers_; | ||||||
| 176 | - | bool canceled_ = false; | ||||||
| 177 | - | |||||||
| DCB | 178 | - | 77 | bool await_ready() const noexcept { return false; } | ||||
| 179 | - | |||||||
| 180 | - | // The operation completes synchronously, but await_suspend is | ||||||
| 181 | - | // the only place io_env is delivered (the promise's | ||||||
| 182 | - | // transform_awaiter forwards it here). Returning false means | ||||||
| 183 | - | // the coroutine does not actually suspend; it resumes | ||||||
| 184 | - | // immediately, having observed the stop token. See io_env, | ||||||
| 185 | - | // IoAwaitable. | ||||||
| 186 | - | bool | ||||||
| DCB | 187 | - | 77 | await_suspend( | ||||
| 188 | - | std::coroutine_handle<>, | ||||||
| 189 | - | io_env const* env) noexcept | ||||||
| 190 | - | { | ||||||
| DCB | 191 | - | 77 | canceled_ = env->stop_token.stop_requested(); | ||||
| DCB | 192 | - | 77 | return false; | ||||
| 193 | - | } | ||||||
| 194 | - | |||||||
| 195 | - | io_result<std::size_t> | ||||||
| DCB | 196 | - | 77 | await_resume() | ||||
| 197 | - | { | ||||||
| DCB | 198 | - | 77 | if(buffer_empty(buffers_)) | ||||
| DCB | 199 | - | 2 | return {{}, 0}; | ||||
| 200 | - | |||||||
| DCB | 201 | - | 75 | if(canceled_) | ||||
| DCB | 202 | - | 1 | return {error::canceled, 0}; | ||||
| 203 | - | |||||||
| DCB | 204 | - | 74 | auto ec = self_->f_.maybe_fail(); | ||||
| DCB | 205 | - | 53 | if(ec) | ||||
| DCB | 206 | - | 21 | return {ec, 0}; | ||||
| 207 | - | |||||||
| DCB | 208 | - | 32 | std::size_t n = buffer_size(buffers_); | ||||
| DCB | 209 | - | 32 | n = (std::min)(n, self_->max_write_size_); | ||||
| 210 | - | |||||||
| DCB | 211 | - | 32 | std::size_t const old_size = self_->data_.size(); | ||||
| DCB | 212 | - | 32 | self_->data_.resize(old_size + n); | ||||
| DCB | 213 | - | 32 | buffer_copy(make_buffer( | ||||
| DCB | 214 | - | 32 | self_->data_.data() + old_size, n), buffers_, n); | ||||
| 215 | - | |||||||
| DCB | 216 | - | 32 | ec = self_->consume_match_(); | ||||
| DCB | 217 | - | 32 | if(ec) | ||||
| 218 | - | { | ||||||
| DUB | 219 | - | ✗ | self_->data_.resize(old_size); | ||||
| DUB | 220 | - | ✗ | return {ec, 0}; | ||||
| 221 | - | } | ||||||
| 222 | - | |||||||
| DCB | 223 | - | 32 | return {{}, n}; | ||||
| 224 | - | } | ||||||
| 225 | - | }; | ||||||
| DCB | 226 | - | 77 | return awaitable{this, buffers}; | ||||
| 227 | - | } | ||||||
| 228 | - | |||||||
| 229 | - | /** Asynchronously write data to the sink. | ||||||
| 230 | - | |||||||
| 231 | - | Transfers all bytes from the provided const buffer sequence | ||||||
| 232 | - | to the internal buffer. Unlike @ref write_some, this ignores | ||||||
| 233 | - | `max_write_size` and writes all available data, matching the | ||||||
| 234 | - | @ref WriteSink semantic contract. | ||||||
| 235 | - | |||||||
| 236 | - | @par Exception Safety | ||||||
| 237 | - | Injected I/O conditions are reported via the `error_code` | ||||||
| 238 | - | component of the result. Throws `std::system_error` only when | ||||||
| 239 | - | the attached @ref fuse is in exception mode and reaches its | ||||||
| 240 | - | failure point; no-throw otherwise. | ||||||
| 241 | - | |||||||
| 242 | - | @param buffers The const buffer sequence containing data to write. | ||||||
| 243 | - | |||||||
| 244 | - | @return An awaitable that await-returns `(error_code,std::size_t)`. | ||||||
| 245 | - | |||||||
| 246 | - | @par Cancellation | ||||||
| 247 | - | If the environment's stop token has been requested, the write | ||||||
| 248 | - | completes immediately with `error::canceled` and transfers no | ||||||
| 249 | - | data. | ||||||
| 250 | - | |||||||
| 251 | - | @throws std::system_error When the attached @ref fuse is in | ||||||
| 252 | - | exception mode and reaches its failure point. | ||||||
| 253 | - | |||||||
| 254 | - | @see fuse | ||||||
| 255 | - | */ | ||||||
| 256 | - | template<ConstBufferSequence CB> | ||||||
| 257 | - | auto | ||||||
| DCB | 258 | - | 303 | write(CB buffers) | ||||
| 259 | - | { | ||||||
| 260 | - | struct awaitable | ||||||
| 261 | - | { | ||||||
| 262 | - | write_sink* self_; | ||||||
| 263 | - | CB buffers_; | ||||||
| 264 | - | bool canceled_ = false; | ||||||
| 265 | - | |||||||
| DCB | 266 | - | 303 | bool await_ready() const noexcept { return false; } | ||||
| 267 | - | |||||||
| 268 | - | // Reads the stop token without suspending; see the comment | ||||||
| 269 | - | // on write_some() for details. | ||||||
| 270 | - | bool | ||||||
| DCB | 271 | - | 303 | await_suspend( | ||||
| 272 | - | std::coroutine_handle<>, | ||||||
| 273 | - | io_env const* env) noexcept | ||||||
| 274 | - | { | ||||||
| DCB | 275 | - | 303 | canceled_ = env->stop_token.stop_requested(); | ||||
| DCB | 276 | - | 303 | return false; | ||||
| 277 | - | } | ||||||
| 278 | - | |||||||
| 279 | - | io_result<std::size_t> | ||||||
| DCB | 280 | - | 303 | await_resume() | ||||
| 281 | - | { | ||||||
| DCB | 282 | - | 303 | if(canceled_) | ||||
| DCB | 283 | - | 1 | return {error::canceled, 0}; | ||||
| 284 | - | |||||||
| DCB | 285 | - | 302 | auto ec = self_->f_.maybe_fail(); | ||||
| DCB | 286 | - | 241 | if(ec) | ||||
| DCB | 287 | - | 61 | return {ec, 0}; | ||||
| 288 | - | |||||||
| DCB | 289 | - | 180 | std::size_t n = buffer_size(buffers_); | ||||
| DCB | 290 | - | 180 | if(n == 0) | ||||
| DCB | 291 | - | 2 | return {{}, 0}; | ||||
| 292 | - | |||||||
| DCB | 293 | - | 178 | std::size_t const old_size = self_->data_.size(); | ||||
| DCB | 294 | - | 178 | self_->data_.resize(old_size + n); | ||||
| DCB | 295 | - | 178 | buffer_copy(make_buffer( | ||||
| DCB | 296 | - | 178 | self_->data_.data() + old_size, n), buffers_); | ||||
| 297 | - | |||||||
| DCB | 298 | - | 178 | ec = self_->consume_match_(); | ||||
| DCB | 299 | - | 178 | if(ec) | ||||
| DCB | 300 | - | 2 | return {ec, n}; | ||||
| 301 | - | |||||||
| DCB | 302 | - | 176 | return {{}, n}; | ||||
| 303 | - | } | ||||||
| 304 | - | }; | ||||||
| DCB | 305 | - | 303 | return awaitable{this, buffers}; | ||||
| 306 | - | } | ||||||
| 307 | - | |||||||
| 308 | - | /** Atomically write data and signal end-of-stream. | ||||||
| 309 | - | |||||||
| 310 | - | Transfers all bytes from the provided const buffer sequence to | ||||||
| 311 | - | the internal buffer and signals end-of-stream. Before the write, | ||||||
| 312 | - | the attached @ref fuse is consulted to possibly inject an error | ||||||
| 313 | - | for testing fault scenarios. | ||||||
| 314 | - | |||||||
| 315 | - | @par Effects | ||||||
| 316 | - | On success, appends the written bytes to the internal buffer | ||||||
| 317 | - | and marks the sink as finalized. | ||||||
| 318 | - | If an error is injected by the fuse, the internal buffer remains | ||||||
| 319 | - | unchanged. | ||||||
| 320 | - | |||||||
| 321 | - | @par Exception Safety | ||||||
| 322 | - | Injected I/O conditions are reported via the `error_code` | ||||||
| 323 | - | component of the result. Throws `std::system_error` only when | ||||||
| 324 | - | the attached @ref fuse is in exception mode and reaches its | ||||||
| 325 | - | failure point; no-throw otherwise. | ||||||
| 326 | - | |||||||
| 327 | - | @par Cancellation | ||||||
| 328 | - | If the environment's stop token has been requested, the operation | ||||||
| 329 | - | completes immediately with `error::canceled`, transfers no data, | ||||||
| 330 | - | and does not signal end-of-stream. | ||||||
| 331 | - | |||||||
| 332 | - | @param buffers The const buffer sequence containing data to write. | ||||||
| 333 | - | |||||||
| 334 | - | @return An awaitable that await-returns `(error_code,std::size_t)`. | ||||||
| 335 | - | |||||||
| 336 | - | @throws std::system_error When the attached @ref fuse is in | ||||||
| 337 | - | exception mode and reaches its failure point. | ||||||
| 338 | - | |||||||
| 339 | - | @see fuse | ||||||
| 340 | - | */ | ||||||
| 341 | - | template<ConstBufferSequence CB> | ||||||
| 342 | - | auto | ||||||
| DCB | 343 | - | 35 | write_eof(CB buffers) | ||||
| 344 | - | { | ||||||
| 345 | - | struct awaitable | ||||||
| 346 | - | { | ||||||
| 347 | - | write_sink* self_; | ||||||
| 348 | - | CB buffers_; | ||||||
| 349 | - | bool canceled_ = false; | ||||||
| 350 | - | |||||||
| DCB | 351 | - | 35 | bool await_ready() const noexcept { return false; } | ||||
| 352 | - | |||||||
| 353 | - | // Reads the stop token without suspending; see the comment | ||||||
| 354 | - | // on write_some() for details. | ||||||
| 355 | - | bool | ||||||
| DCB | 356 | - | 35 | await_suspend( | ||||
| 357 | - | std::coroutine_handle<>, | ||||||
| 358 | - | io_env const* env) noexcept | ||||||
| 359 | - | { | ||||||
| DCB | 360 | - | 35 | canceled_ = env->stop_token.stop_requested(); | ||||
| DCB | 361 | - | 35 | return false; | ||||
| 362 | - | } | ||||||
| 363 | - | |||||||
| 364 | - | io_result<std::size_t> | ||||||
| DCB | 365 | - | 35 | await_resume() | ||||
| 366 | - | { | ||||||
| DCB | 367 | - | 35 | if(canceled_) | ||||
| DCB | 368 | - | 1 | return {error::canceled, 0}; | ||||
| 369 | - | |||||||
| DCB | 370 | - | 34 | auto ec = self_->f_.maybe_fail(); | ||||
| DCB | 371 | - | 23 | if(ec) | ||||
| DCB | 372 | - | 11 | return {ec, 0}; | ||||
| 373 | - | |||||||
| DCB | 374 | - | 12 | std::size_t n = buffer_size(buffers_); | ||||
| DCB | 375 | - | 12 | if(n > 0) | ||||
| 376 | - | { | ||||||
| DCB | 377 | - | 10 | std::size_t const old_size = self_->data_.size(); | ||||
| DCB | 378 | - | 10 | self_->data_.resize(old_size + n); | ||||
| DCB | 379 | - | 10 | buffer_copy(make_buffer( | ||||
| DCB | 380 | - | 10 | self_->data_.data() + old_size, n), buffers_); | ||||
| 381 | - | |||||||
| DCB | 382 | - | 10 | ec = self_->consume_match_(); | ||||
| DCB | 383 | - | 10 | if(ec) | ||||
| DUB | 384 | - | ✗ | return {ec, n}; | ||||
| 385 | - | } | ||||||
| 386 | - | |||||||
| DCB | 387 | - | 12 | self_->eof_called_ = true; | ||||
| 388 | - | |||||||
| DCB | 389 | - | 12 | return {{}, n}; | ||||
| 390 | - | } | ||||||
| 391 | - | }; | ||||||
| DCB | 392 | - | 35 | return awaitable{this, buffers}; | ||||
| 393 | - | } | ||||||
| 394 | - | |||||||
| 395 | - | /** Signal end-of-stream. | ||||||
| 396 | - | |||||||
| 397 | - | Marks the sink as finalized, indicating no more data will be | ||||||
| 398 | - | written. Before signaling, the attached @ref fuse is consulted | ||||||
| 399 | - | to possibly inject an error for testing fault scenarios. | ||||||
| 400 | - | |||||||
| 401 | - | @par Effects | ||||||
| 402 | - | On success, marks the sink as finalized. | ||||||
| 403 | - | If an error is injected by the fuse, the state remains unchanged. | ||||||
| 404 | - | |||||||
| 405 | - | @par Exception Safety | ||||||
| 406 | - | Injected I/O conditions are reported via the `error_code` | ||||||
| 407 | - | component of the result. Throws `std::system_error` only when | ||||||
| 408 | - | the attached @ref fuse is in exception mode and reaches its | ||||||
| 409 | - | failure point; no-throw otherwise. | ||||||
| 410 | - | |||||||
| 411 | - | @par Cancellation | ||||||
| 412 | - | If the environment's stop token has been requested, the operation | ||||||
| 413 | - | completes immediately with `error::canceled` and does not signal | ||||||
| 414 | - | end-of-stream. | ||||||
| 415 | - | |||||||
| 416 | - | @return An awaitable that await-returns `(error_code)`. | ||||||
| 417 | - | |||||||
| 418 | - | @throws std::system_error When the attached @ref fuse is in | ||||||
| 419 | - | exception mode and reaches its failure point. | ||||||
| 420 | - | |||||||
| 421 | - | @see fuse | ||||||
| 422 | - | */ | ||||||
| 423 | - | auto | ||||||
| DCB | 424 | - | 83 | write_eof() | ||||
| 425 | - | { | ||||||
| 426 | - | struct awaitable | ||||||
| 427 | - | { | ||||||
| 428 | - | write_sink* self_; | ||||||
| 429 | - | bool canceled_ = false; | ||||||
| 430 | - | |||||||
| DCB | 431 | - | 83 | bool await_ready() const noexcept { return false; } | ||||
| 432 | - | |||||||
| 433 | - | // Reads the stop token without suspending; see the comment | ||||||
| 434 | - | // on write_some() for details. | ||||||
| 435 | - | bool | ||||||
| DCB | 436 | - | 83 | await_suspend( | ||||
| 437 | - | std::coroutine_handle<>, | ||||||
| 438 | - | io_env const* env) noexcept | ||||||
| 439 | - | { | ||||||
| DCB | 440 | - | 83 | canceled_ = env->stop_token.stop_requested(); | ||||
| DCB | 441 | - | 83 | return false; | ||||
| 442 | - | } | ||||||
| 443 | - | |||||||
| 444 | - | io_result<> | ||||||
| DCB | 445 | - | 83 | await_resume() | ||||
| 446 | - | { | ||||||
| DCB | 447 | - | 83 | if(canceled_) | ||||
| DCB | 448 | - | 1 | return {error::canceled}; | ||||
| 449 | - | |||||||
| DCB | 450 | - | 82 | auto ec = self_->f_.maybe_fail(); | ||||
| DCB | 451 | - | 60 | if(ec) | ||||
| DCB | 452 | - | 22 | return {ec}; | ||||
| 453 | - | |||||||
| DCB | 454 | - | 38 | self_->eof_called_ = true; | ||||
| DCB | 455 | - | 38 | return {}; | ||||
| 456 | - | } | ||||||
| 457 | - | }; | ||||||
| DCB | 458 | - | 83 | return awaitable{this}; | ||||
| 459 | - | } | ||||||
| 460 | - | }; | ||||||
| 461 | - | |||||||
| 462 | - | } // test | ||||||
| 463 | - | } // capy | ||||||
| 464 | - | } // boost | ||||||
| 465 | - | |||||||
| 466 | - | #endif | ||||||