Line data 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_IO_PUSH_TO_HPP
11 : #define BOOST_CAPY_IO_PUSH_TO_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/buffers.hpp>
15 : #include <boost/capy/concept/buffer_source.hpp>
16 : #include <boost/capy/concept/write_sink.hpp>
17 : #include <boost/capy/concept/write_stream.hpp>
18 : #include <boost/capy/io_result.hpp>
19 : #include <boost/capy/task.hpp>
20 :
21 : #include <cstddef>
22 : #include <span>
23 :
24 : namespace boost {
25 : namespace capy {
26 :
27 : /** Transfer data from a BufferSource to a WriteSink.
28 :
29 : This function pulls data from the source and writes it to the
30 : sink until the source is exhausted or an error occurs. When
31 : the source signals completion, `write_eof()` is called on the
32 : sink to finalize the transfer.
33 :
34 : @tparam Src The source type, must satisfy @ref BufferSource.
35 : @tparam Sink The sink type, must satisfy @ref WriteSink.
36 :
37 : @param source The source to pull data from.
38 : @param sink The sink to write data to.
39 :
40 : @return A task that yields `(std::error_code, std::size_t)`.
41 : On success, `ec` is default-constructed (no error) and `n` is
42 : the total number of bytes transferred. On error, `ec` contains
43 : the error code and `n` is the total number of bytes transferred
44 : before the error.
45 :
46 : @par Example
47 : @code
48 : task<void> transfer_body(BufferSource auto& source, WriteSink auto& sink)
49 : {
50 : auto [ec, n] = co_await push_to(source, sink);
51 : if (ec)
52 : {
53 : // Handle error
54 : }
55 : // n bytes were transferred
56 : }
57 : @endcode
58 :
59 : @see BufferSource, WriteSink
60 : */
61 : template<BufferSource Src, WriteSink Sink>
62 : task<io_result<std::size_t>>
63 140 : push_to(Src& source, Sink& sink)
64 : {
65 : const_buffer arr[detail::max_iovec_];
66 : std::size_t total = 0;
67 :
68 : for(;;)
69 : {
70 : auto [ec, bufs] = co_await source.pull(arr);
71 : if(ec)
72 : co_return {ec, total};
73 :
74 : if(bufs.empty())
75 : {
76 : auto [eof_ec] = co_await sink.write_eof();
77 : co_return {eof_ec, total};
78 : }
79 :
80 : auto [write_ec, n] = co_await sink.write(bufs);
81 : total += n;
82 : source.consume(n);
83 : if(write_ec)
84 : co_return {write_ec, total};
85 : }
86 280 : }
87 :
88 : /** Transfer data from a BufferSource to a WriteStream.
89 :
90 : This function pulls data from the source and writes it to the
91 : stream until the source is exhausted or an error occurs. The
92 : stream uses `write_some()` which may perform partial writes,
93 : so this function loops until all pulled data is consumed.
94 :
95 : Unlike the WriteSink overload, this function does not signal
96 : EOF explicitly since WriteStream does not provide a write_eof
97 : method. The transfer completes when the source is exhausted.
98 :
99 : @tparam Src The source type, must satisfy @ref BufferSource.
100 : @tparam Stream The stream type, must satisfy @ref WriteStream.
101 :
102 : @param source The source to pull data from.
103 : @param stream The stream to write data to.
104 :
105 : @return A task that yields `(std::error_code, std::size_t)`.
106 : On success, `ec` is default-constructed (no error) and `n` is
107 : the total number of bytes transferred. On error, `ec` contains
108 : the error code and `n` is the total number of bytes transferred
109 : before the error.
110 :
111 : @par Example
112 : @code
113 : task<void> transfer_body(BufferSource auto& source, WriteStream auto& stream)
114 : {
115 : auto [ec, n] = co_await push_to(source, stream);
116 : if (ec)
117 : {
118 : // Handle error
119 : }
120 : // n bytes were transferred
121 : }
122 : @endcode
123 :
124 : @see BufferSource, WriteStream, pull_from
125 : */
126 : template<BufferSource Src, WriteStream Stream>
127 : task<io_result<std::size_t>>
128 104 : push_to(Src& source, Stream& stream)
129 : {
130 : const_buffer arr[detail::max_iovec_];
131 : std::size_t total = 0;
132 :
133 : for(;;)
134 : {
135 : auto [ec, bufs] = co_await source.pull(arr);
136 : if(ec)
137 : co_return {ec, total};
138 :
139 : if(bufs.empty())
140 : co_return {{}, total};
141 :
142 : auto [write_ec, n] = co_await stream.write_some(bufs);
143 : if(write_ec)
144 : co_return {write_ec, total};
145 :
146 : total += n;
147 : source.consume(n);
148 : }
149 208 : }
150 :
151 : } // namespace capy
152 : } // namespace boost
153 :
154 : #endif
|