include/boost/capy/read.hpp

100.0% Lines (2/0/2) 100.0% List of functions (4/0/4)
read.hpp
f(x) Functions (4)
Line TLA Hits Source 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_READ_HPP
12 #define BOOST_CAPY_READ_HPP
13
14 #include <boost/capy/detail/config.hpp>
15 #include <boost/capy/cond.hpp>
16 #include <boost/capy/io_task.hpp>
17 #include <boost/capy/buffers.hpp>
18 #include <boost/capy/buffers/consuming_buffers.hpp>
19 #include <boost/capy/concept/read_stream.hpp>
20
21 #include <algorithm>
22 #include <cstddef>
23
24 namespace boost {
25 namespace capy {
26
27 /** Read data from a stream until the buffer sequence is full.
28
29 @par Await-effects
30
31 Reads data from `stream` via awaiting `stream.read_some` repeatedly
32 until:
33
34 @li either the entire buffer sequence @c buffers is filled,
35 @li or a contingency occurs on `stream.read_some`.
36
37 If `buffer_size(buffers) == 0` then no awaiting `stream.read_some`
38 is performed. This is not a contingency.
39
40 @par Await-returns
41 An object of type `io_result<std::size_t>` destructuring as `[ec, n]`.
42
43 Upon a contingency, `n` represents the number of bytes read so far,
44 inclusive of the last partial read.
45
46 Contingencies:
47
48 @li The first contingency reported from awaiting @c stream.read_some
49 while `buffers` is not yet filled. A contingency that accompanies
50 the read which fills `buffers` is not reported: a completed
51 transfer is a success.
52
53 Notable conditions:
54
55 @li @c cond::canceled — Operation was cancelled,
56 @li @c cond::eof — Stream reached end before @c buffers was filled.
57
58 @par Await-postcondition
59 If `n == buffer_size(buffers)` the transfer completed and `ec` is
60 success; otherwise `ec` is set.
61
62 @param stream The stream to read from. If the lifetime of `stream` ends
63 before the coroutine finishes, the behavior is undefined.
64
65 @param buffers The buffer sequence to fill. If the lifetime of the buffer
66 sequence represented by `buffers` ends before the coroutine finishes, the behavior is undefined.
67
68 @return A task yielding `io_result<std::size_t>` whose second element
69 is the number of bytes read.
70
71 @par Remarks
72 Supports _IoAwaitable cancellation_.
73
74
75 @par Example
76
77 @code
78 capy::task<> process_message(capy::ReadStream auto& stream)
79 {
80 std::vector<char> header(16); // known header size for some protocol
81 auto [ec, n] = co_await capy::read(stream, capy::make_buffer(header));
82 if (ec == capy::cond::eof)
83 co_return; // Connection closed
84 if (ec)
85 throw std::system_error(ec);
86
87 // at this point `header` contains exactly 16 bytes
88 }
89 @endcode
90
91 @see ReadStream, MutableBufferSequence
92 */
93 template <typename S, typename MB>
94 requires ReadStream<S> && MutableBufferSequence<MB>
95 auto
96 99x read(S& stream, MB buffers) ->
97 io_task<std::size_t>
98 {
99 consuming_buffers consuming(buffers);
100 std::size_t const total_size = buffer_size(buffers);
101 std::size_t total_read = 0;
102
103 while(total_read < total_size)
104 {
105 auto [ec, n] = co_await stream.read_some(consuming.data());
106 consuming.consume(n);
107 total_read += n;
108 // A contingency that still completed the transfer is a success:
109 // report it only when the buffer was not filled.
110 if(ec && total_read < total_size)
111 co_return {ec, total_read};
112 }
113
114 co_return {{}, total_read};
115 198x }
116
117 } // namespace capy
118 } // namespace boost
119
120 #endif
121