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, count] = co_await source.pull(arr, detail::max_iovec_);
71 : if(ec)
72 : co_return {ec, total};
73 :
74 : if(count == 0)
75 : {
76 : auto [eof_ec] = co_await sink.write_eof();
77 : co_return {eof_ec, total};
78 : }
79 :
80 : std::span<const_buffer const> bufs(arr, count);
81 : auto [write_ec, n] = co_await sink.write(bufs);
82 : total += n;
83 : source.consume(n);
84 : if(write_ec)
85 : co_return {write_ec, total};
86 : }
87 280 : }
88 :
89 : /** Transfer data from a BufferSource to a WriteStream.
90 :
91 : This function pulls data from the source and writes it to the
92 : stream until the source is exhausted or an error occurs. The
93 : stream uses `write_some()` which may perform partial writes,
94 : so this function loops until all pulled data is consumed.
95 :
96 : Unlike the WriteSink overload, this function does not signal
97 : EOF explicitly since WriteStream does not provide a write_eof
98 : method. The transfer completes when the source is exhausted.
99 :
100 : @tparam Src The source type, must satisfy @ref BufferSource.
101 : @tparam Stream The stream type, must satisfy @ref WriteStream.
102 :
103 : @param source The source to pull data from.
104 : @param stream The stream to write data to.
105 :
106 : @return A task that yields `(std::error_code, std::size_t)`.
107 : On success, `ec` is default-constructed (no error) and `n` is
108 : the total number of bytes transferred. On error, `ec` contains
109 : the error code and `n` is the total number of bytes transferred
110 : before the error.
111 :
112 : @par Example
113 : @code
114 : task<void> transfer_body(BufferSource auto& source, WriteStream auto& stream)
115 : {
116 : auto [ec, n] = co_await push_to(source, stream);
117 : if (ec)
118 : {
119 : // Handle error
120 : }
121 : // n bytes were transferred
122 : }
123 : @endcode
124 :
125 : @see BufferSource, WriteStream, pull_from
126 : */
127 : template<BufferSource Src, WriteStream Stream>
128 : task<io_result<std::size_t>>
129 104 : push_to(Src& source, Stream& stream)
130 : {
131 : const_buffer arr[detail::max_iovec_];
132 : std::size_t total = 0;
133 :
134 : for(;;)
135 : {
136 : auto [ec, count] = co_await source.pull(arr, detail::max_iovec_);
137 : if(ec)
138 : co_return {ec, total};
139 :
140 : if(count == 0)
141 : co_return {{}, total};
142 :
143 : std::span<const_buffer const> bufs(arr, count);
144 : auto [write_ec, n] = co_await stream.write_some(bufs);
145 : if(write_ec)
146 : co_return {write_ec, total};
147 :
148 : total += n;
149 : source.consume(n);
150 : }
151 208 : }
152 :
153 : } // namespace capy
154 : } // namespace boost
155 :
156 : #endif
|