libs/capy/include/boost/capy/read.hpp

100.0% Lines (6/6) 100.0% Functions (6/6) 100.0% Branches (3/3)
libs/capy/include/boost/capy/read.hpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
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/capy
8 //
9
10 #ifndef BOOST_CAPY_READ_HPP
11 #define BOOST_CAPY_READ_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/cond.hpp>
15 #include <boost/capy/io_task.hpp>
16 #include <boost/capy/buffers.hpp>
17 #include <boost/capy/buffers/consuming_buffers.hpp>
18 #include <boost/capy/concept/dynamic_buffer.hpp>
19 #include <boost/capy/concept/read_source.hpp>
20 #include <boost/capy/concept/read_stream.hpp>
21 #include <system_error>
22
23 #include <cstddef>
24
25 namespace boost {
26 namespace capy {
27
28 /** Asynchronously read until the buffer sequence is full.
29
30 Reads data from the stream by calling `read_some` repeatedly
31 until the entire buffer sequence is filled or an error occurs.
32
33 @li The operation completes when:
34 @li The buffer sequence is completely filled
35 @li An error occurs (including `cond::eof`)
36 @li The operation is cancelled
37
38 @par Cancellation
39 Supports cancellation via `stop_token` propagated through the
40 IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
41
42 @param stream The stream to read from. The caller retains ownership.
43 @param buffers The buffer sequence to fill. The caller retains
44 ownership and must ensure validity until the operation completes.
45
46 @return An awaitable yielding `(error_code, std::size_t)`.
47 On success, `n` equals `buffer_size(buffers)`. On error,
48 `n` is the number of bytes read before the error. Compare
49 error codes to conditions:
50 @li `cond::eof` - Stream reached end before buffer was filled
51 @li `cond::canceled` - Operation was cancelled
52
53 @par Example
54
55 @code
56 task<> read_message( ReadStream auto& stream )
57 {
58 char header[16];
59 auto [ec, n] = co_await read( stream, mutable_buffer( header ) );
60 if( ec == cond::eof )
61 co_return; // Connection closed
62 if( ec )
63 detail::throw_system_error( ec );
64 // header contains exactly 16 bytes
65 }
66 @endcode
67
68 @see read_some, ReadStream, MutableBufferSequence
69 */
70 auto
71
1/1
✓ Branch 1 taken 50 times.
50 read(
72 ReadStream auto& stream,
73 MutableBufferSequence auto const& buffers) ->
74 io_task<std::size_t>
75 {
76 consuming_buffers consuming(buffers);
77 std::size_t const total_size = buffer_size(buffers);
78 std::size_t total_read = 0;
79
80 while(total_read < total_size)
81 {
82 auto [ec, n] = co_await stream.read_some(consuming);
83 if(ec)
84 co_return {ec, total_read};
85 consuming.consume(n);
86 total_read += n;
87 }
88
89 co_return {{}, total_read};
90 100 }
91
92 /** Asynchronously read all data from a stream into a dynamic buffer.
93
94 Reads data by calling `read_some` repeatedly until EOF is reached
95 or an error occurs. Data is appended using prepare/commit semantics.
96 The buffer grows with 1.5x factor when filled.
97
98 @li The operation completes when:
99 @li End-of-stream is reached (`cond::eof`)
100 @li An error occurs
101 @li The operation is cancelled
102
103 @par Cancellation
104 Supports cancellation via `stop_token` propagated through the
105 IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
106
107 @param stream The stream to read from. The caller retains ownership.
108 @param buffers The dynamic buffer to append data to. Must remain
109 valid until the operation completes.
110 @param initial_amount Initial bytes to prepare (default 2048).
111
112 @return An awaitable yielding `(error_code, std::size_t)`.
113 On success (EOF), `ec` is clear and `n` is total bytes read.
114 On error, `n` is bytes read before the error. Compare error
115 codes to conditions:
116 @li `cond::canceled` - Operation was cancelled
117
118 @par Example
119
120 @code
121 task<std::string> read_body( ReadStream auto& stream )
122 {
123 std::string body;
124 auto [ec, n] = co_await read( stream, string_dynamic_buffer( &body ) );
125 if( ec )
126 detail::throw_system_error( ec );
127 return body;
128 }
129 @endcode
130
131 @see read_some, ReadStream, DynamicBufferParam
132 */
133 auto
134
1/1
✓ Branch 1 taken 80 times.
80 read(
135 ReadStream auto& stream,
136 DynamicBufferParam auto&& buffers,
137 std::size_t initial_amount = 2048) ->
138 io_task<std::size_t>
139 {
140 std::size_t amount = initial_amount;
141 std::size_t total_read = 0;
142 for(;;)
143 {
144 auto mb = buffers.prepare(amount);
145 auto const mb_size = buffer_size(mb);
146 auto [ec, n] = co_await stream.read_some(mb);
147 buffers.commit(n);
148 total_read += n;
149 if(ec == cond::eof)
150 co_return {{}, total_read};
151 if(ec)
152 co_return {ec, total_read};
153 if(n == mb_size)
154 amount = amount / 2 + amount;
155 }
156 160 }
157
158 /** Asynchronously read all data from a source into a dynamic buffer.
159
160 Reads data by calling `source.read` repeatedly until EOF is reached
161 or an error occurs. Data is appended using prepare/commit semantics.
162 The buffer grows with 1.5x factor when filled.
163
164 @li The operation completes when:
165 @li End-of-stream is reached (`cond::eof`)
166 @li An error occurs
167 @li The operation is cancelled
168
169 @par Cancellation
170 Supports cancellation via `stop_token` propagated through the
171 IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
172
173 @param source The source to read from. The caller retains ownership.
174 @param buffers The dynamic buffer to append data to. Must remain
175 valid until the operation completes.
176 @param initial_amount Initial bytes to prepare (default 2048).
177
178 @return An awaitable yielding `(error_code, std::size_t)`.
179 On success (EOF), `ec` is clear and `n` is total bytes read.
180 On error, `n` is bytes read before the error. Compare error
181 codes to conditions:
182 @li `cond::canceled` - Operation was cancelled
183
184 @par Example
185
186 @code
187 task<std::string> read_body( ReadSource auto& source )
188 {
189 std::string body;
190 auto [ec, n] = co_await read( source, string_dynamic_buffer( &body ) );
191 if( ec )
192 detail::throw_system_error( ec );
193 return body;
194 }
195 @endcode
196
197 @see ReadSource, DynamicBufferParam
198 */
199 auto
200
1/1
✓ Branch 1 taken 54 times.
54 read(
201 ReadSource auto& source,
202 DynamicBufferParam auto&& buffers,
203 std::size_t initial_amount = 2048) ->
204 io_task<std::size_t>
205 {
206 std::size_t amount = initial_amount;
207 std::size_t total_read = 0;
208 for(;;)
209 {
210 auto mb = buffers.prepare(amount);
211 auto const mb_size = buffer_size(mb);
212 auto [ec, n] = co_await source.read(mb);
213 buffers.commit(n);
214 total_read += n;
215 if(ec == cond::eof)
216 co_return {{}, total_read};
217 if(ec)
218 co_return {ec, total_read};
219 if(n == mb_size)
220 amount = amount / 2 + amount; // 1.5x growth
221 }
222 108 }
223
224 } // namespace capy
225 } // namespace boost
226
227 #endif
228