include/boost/capy/io/pull_from.hpp

100.0% Lines (8/8) 100.0% List of functions (4/4) 100.0% Branches (4/4)
f(x) Functions (4)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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_IO_PULL_FROM_HPP
11 #define BOOST_CAPY_IO_PULL_FROM_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/buffers.hpp>
15 #include <boost/capy/cond.hpp>
16 #include <boost/capy/concept/buffer_sink.hpp>
17 #include <boost/capy/concept/read_source.hpp>
18 #include <boost/capy/concept/read_stream.hpp>
19 #include <boost/capy/io_task.hpp>
20
21 #include <cstddef>
22 #include <span>
23
24 namespace boost {
25 namespace capy {
26
27 /** Transfer data from a ReadSource to a BufferSink.
28
29 This function reads data from the source directly into the sink's
30 internal buffers using the callee-owns-buffers model. The sink
31 provides writable buffers via `prepare()`, the source reads into
32 them, and the sink commits the data. When the source signals EOF,
33 `commit_eof()` is called on the sink to finalize the transfer.
34
35 @tparam Src The source type, must satisfy @ref ReadSource.
36 @tparam Sink The sink type, must satisfy @ref BufferSink.
37
38 @param source The source to read data from.
39 @param sink The sink to write data to.
40
41 @return A task that yields `(std::error_code, std::size_t)`.
42 On success, `ec` is default-constructed (no error) and `n` is
43 the total number of bytes transferred. On error, `ec` contains
44 the error code and `n` is the total number of bytes transferred
45 before the error.
46
47 @par Example
48 @code
49 task<void> transfer_body(ReadSource auto& source, BufferSink auto& sink)
50 {
51 auto [ec, n] = co_await pull_from(source, sink);
52 if (ec)
53 {
54 // Handle error
55 }
56 // n bytes were transferred
57 }
58 @endcode
59
60 @see ReadSource, BufferSink, push_to
61 */
62 template<ReadSource Src, BufferSink Sink>
63 io_task<std::size_t>
64
2/2
boost::capy::task<boost::capy::io_result<unsigned long> > boost::capy::pull_from<boost::capy::test::read_source, boost::capy::any_buffer_sink>(boost::capy::test::read_source&, boost::capy::any_buffer_sink&):
✓ Branch 1 taken 10 times.
boost::capy::task<boost::capy::io_result<unsigned long> > boost::capy::pull_from<boost::capy::test::read_source, boost::capy::test::buffer_sink>(boost::capy::test::read_source&, boost::capy::test::buffer_sink&):
✓ Branch 1 taken 126 times.
136x pull_from(Src& source, Sink& sink)
65 {
66 mutable_buffer dst_arr[detail::max_iovec_];
67 std::size_t total = 0;
68
69 for(;;)
70 {
71 auto dst_bufs = sink.prepare(dst_arr);
72 if(dst_bufs.empty())
73 {
74 // No buffer space available; commit nothing to flush
75 auto [flush_ec] = co_await sink.commit(0);
76 if(flush_ec)
77 co_return {flush_ec, total};
78 continue;
79 }
80
81 auto [ec, n] = co_await source.read(
82 std::span<mutable_buffer const>(dst_bufs));
83
84 auto [commit_ec] = co_await sink.commit(n);
85 total += n;
86
87 if(commit_ec)
88 co_return {commit_ec, total};
89
90 if(ec == cond::eof)
91 {
92 auto [eof_ec] = co_await sink.commit_eof(0);
93 co_return {eof_ec, total};
94 }
95
96 if(ec)
97 co_return {ec, total};
98 }
99 272x }
100
101 /** Transfer data from a ReadStream to a BufferSink.
102
103 This function reads data from the stream directly into the sink's
104 internal buffers using the callee-owns-buffers model. The sink
105 provides writable buffers via `prepare()`, the stream reads into
106 them using `read_some()`, and the sink commits the data. When the
107 stream signals EOF, `commit_eof()` is called on the sink to
108 finalize the transfer.
109
110 This overload handles partial reads from the stream, committing
111 data incrementally as it arrives. It loops until EOF is encountered
112 or an error occurs.
113
114 @tparam Src The source type, must satisfy @ref ReadStream.
115 @tparam Sink The sink type, must satisfy @ref BufferSink.
116
117 @param source The stream to read data from.
118 @param sink The sink to write data to.
119
120 @return A task that yields `(std::error_code, std::size_t)`.
121 On success, `ec` is default-constructed (no error) and `n` is
122 the total number of bytes transferred. On error, `ec` contains
123 the error code and `n` is the total number of bytes transferred
124 before the error.
125
126 @par Example
127 @code
128 task<void> transfer_body(ReadStream auto& stream, BufferSink auto& sink)
129 {
130 auto [ec, n] = co_await pull_from(stream, sink);
131 if (ec)
132 {
133 // Handle error
134 }
135 // n bytes were transferred
136 }
137 @endcode
138
139 @see ReadStream, BufferSink, push_to
140 */
141 template<ReadStream Src, BufferSink Sink>
142 requires (!ReadSource<Src>)
143 io_task<std::size_t>
144
2/2
boost::capy::task<boost::capy::io_result<unsigned long> > boost::capy::pull_from<boost::capy::test::read_stream, boost::capy::any_buffer_sink>(boost::capy::test::read_stream&, boost::capy::any_buffer_sink&):
✓ Branch 1 taken 14 times.
boost::capy::task<boost::capy::io_result<unsigned long> > boost::capy::pull_from<boost::capy::test::read_stream, boost::capy::test::buffer_sink>(boost::capy::test::read_stream&, boost::capy::test::buffer_sink&):
✓ Branch 1 taken 212 times.
226x pull_from(Src& source, Sink& sink)
145 {
146 mutable_buffer dst_arr[detail::max_iovec_];
147 std::size_t total = 0;
148
149 for(;;)
150 {
151 // Prepare destination buffers from the sink
152 auto dst_bufs = sink.prepare(dst_arr);
153 if(dst_bufs.empty())
154 {
155 // No buffer space available; commit nothing to flush
156 auto [flush_ec] = co_await sink.commit(0);
157 if(flush_ec)
158 co_return {flush_ec, total};
159 continue;
160 }
161
162 // Read data from the stream into the sink's buffers
163 auto [ec, n] = co_await source.read_some(
164 std::span<mutable_buffer const>(dst_bufs));
165
166 auto [commit_ec] = co_await sink.commit(n);
167 total += n;
168
169 if(commit_ec)
170 co_return {commit_ec, total};
171
172 if(ec == cond::eof)
173 {
174 auto [eof_ec] = co_await sink.commit_eof(0);
175 co_return {eof_ec, total};
176 }
177
178 // Check for other errors
179 if(ec)
180 co_return {ec, total};
181 }
182 452x }
183
184 } // namespace capy
185 } // namespace boost
186
187 #endif
188