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