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