1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/capy
7  
// Official repository: https://github.com/cppalliance/capy
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_CAPY_IO_PUSH_TO_HPP
10  
#ifndef BOOST_CAPY_IO_PUSH_TO_HPP
11  
#define BOOST_CAPY_IO_PUSH_TO_HPP
11  
#define BOOST_CAPY_IO_PUSH_TO_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/buffers.hpp>
14  
#include <boost/capy/buffers.hpp>
 
15 +
#include <boost/capy/cond.hpp>
15  
#include <boost/capy/concept/buffer_source.hpp>
16  
#include <boost/capy/concept/buffer_source.hpp>
16  
#include <boost/capy/concept/write_sink.hpp>
17  
#include <boost/capy/concept/write_sink.hpp>
17  
#include <boost/capy/concept/write_stream.hpp>
18  
#include <boost/capy/concept/write_stream.hpp>
18 -
#include <boost/capy/io_result.hpp>
19 +
#include <boost/capy/io_task.hpp>
19 -
#include <boost/capy/task.hpp>
 
20  

20  

21  
#include <cstddef>
21  
#include <cstddef>
22  
#include <span>
22  
#include <span>
23  

23  

24  
namespace boost {
24  
namespace boost {
25  
namespace capy {
25  
namespace capy {
26  

26  

27  
/** Transfer data from a BufferSource to a WriteSink.
27  
/** Transfer data from a BufferSource to a WriteSink.
28  

28  

29  
    This function pulls data from the source and writes it to the
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
30  
    sink until the source is exhausted or an error occurs. When
31  
    the source signals completion, `write_eof()` is called on the
31  
    the source signals completion, `write_eof()` is called on the
32  
    sink to finalize the transfer.
32  
    sink to finalize the transfer.
33  

33  

34  
    @tparam Src The source type, must satisfy @ref BufferSource.
34  
    @tparam Src The source type, must satisfy @ref BufferSource.
35  
    @tparam Sink The sink type, must satisfy @ref WriteSink.
35  
    @tparam Sink The sink type, must satisfy @ref WriteSink.
36  

36  

37  
    @param source The source to pull data from.
37  
    @param source The source to pull data from.
38  
    @param sink The sink to write data to.
38  
    @param sink The sink to write data to.
39  

39  

40  
    @return A task that yields `(std::error_code, std::size_t)`.
40  
    @return A task that yields `(std::error_code, std::size_t)`.
41  
        On success, `ec` is default-constructed (no error) and `n` is
41  
        On success, `ec` is default-constructed (no error) and `n` is
42  
        the total number of bytes transferred. On error, `ec` contains
42  
        the total number of bytes transferred. On error, `ec` contains
43  
        the error code and `n` is the total number of bytes transferred
43  
        the error code and `n` is the total number of bytes transferred
44  
        before the error.
44  
        before the error.
45  

45  

46  
    @par Example
46  
    @par Example
47  
    @code
47  
    @code
48  
    task<void> transfer_body(BufferSource auto& source, WriteSink auto& sink)
48  
    task<void> transfer_body(BufferSource auto& source, WriteSink auto& sink)
49  
    {
49  
    {
50  
        auto [ec, n] = co_await push_to(source, sink);
50  
        auto [ec, n] = co_await push_to(source, sink);
51  
        if (ec)
51  
        if (ec)
52  
        {
52  
        {
53  
            // Handle error
53  
            // Handle error
54  
        }
54  
        }
55  
        // n bytes were transferred
55  
        // n bytes were transferred
56  
    }
56  
    }
57  
    @endcode
57  
    @endcode
58  

58  

59  
    @see BufferSource, WriteSink
59  
    @see BufferSource, WriteSink
60  
*/
60  
*/
61  
template<BufferSource Src, WriteSink Sink>
61  
template<BufferSource Src, WriteSink Sink>
62 -
task<io_result<std::size_t>>
62 +
io_task<std::size_t>
63  
push_to(Src& source, Sink& sink)
63  
push_to(Src& source, Sink& sink)
64  
{
64  
{
65  
    const_buffer arr[detail::max_iovec_];
65  
    const_buffer arr[detail::max_iovec_];
66  
    std::size_t total = 0;
66  
    std::size_t total = 0;
67  

67  

68  
    for(;;)
68  
    for(;;)
69  
    {
69  
    {
70  
        auto [ec, bufs] = co_await source.pull(arr);
70  
        auto [ec, bufs] = co_await source.pull(arr);
71 -
        if(ec)
71 +
        if(ec == cond::eof)
72 -
            co_return {ec, total};
 
73 -

 
74 -
        if(bufs.empty())
 
75  
        {
72  
        {
76  
            auto [eof_ec] = co_await sink.write_eof();
73  
            auto [eof_ec] = co_await sink.write_eof();
77  
            co_return {eof_ec, total};
74  
            co_return {eof_ec, total};
78  
        }
75  
        }
 
76 +
        if(ec)
 
77 +
            co_return {ec, total};
79  

78  

80  
        auto [write_ec, n] = co_await sink.write(bufs);
79  
        auto [write_ec, n] = co_await sink.write(bufs);
81  
        total += n;
80  
        total += n;
82  
        source.consume(n);
81  
        source.consume(n);
83  
        if(write_ec)
82  
        if(write_ec)
84  
            co_return {write_ec, total};
83  
            co_return {write_ec, total};
85  
    }
84  
    }
86  
}
85  
}
87  

86  

88  
/** Transfer data from a BufferSource to a WriteStream.
87  
/** Transfer data from a BufferSource to a WriteStream.
89  

88  

90  
    This function pulls data from the source and writes it to the
89  
    This function pulls data from the source and writes it to the
91  
    stream until the source is exhausted or an error occurs. The
90  
    stream until the source is exhausted or an error occurs. The
92  
    stream uses `write_some()` which may perform partial writes,
91  
    stream uses `write_some()` which may perform partial writes,
93  
    so this function loops until all pulled data is consumed.
92  
    so this function loops until all pulled data is consumed.
94  

93  

95  
    Unlike the WriteSink overload, this function does not signal
94  
    Unlike the WriteSink overload, this function does not signal
96  
    EOF explicitly since WriteStream does not provide a write_eof
95  
    EOF explicitly since WriteStream does not provide a write_eof
97  
    method. The transfer completes when the source is exhausted.
96  
    method. The transfer completes when the source is exhausted.
98  

97  

99  
    @tparam Src The source type, must satisfy @ref BufferSource.
98  
    @tparam Src The source type, must satisfy @ref BufferSource.
100  
    @tparam Stream The stream type, must satisfy @ref WriteStream.
99  
    @tparam Stream The stream type, must satisfy @ref WriteStream.
101  

100  

102  
    @param source The source to pull data from.
101  
    @param source The source to pull data from.
103  
    @param stream The stream to write data to.
102  
    @param stream The stream to write data to.
104  

103  

105  
    @return A task that yields `(std::error_code, std::size_t)`.
104  
    @return A task that yields `(std::error_code, std::size_t)`.
106  
        On success, `ec` is default-constructed (no error) and `n` is
105  
        On success, `ec` is default-constructed (no error) and `n` is
107  
        the total number of bytes transferred. On error, `ec` contains
106  
        the total number of bytes transferred. On error, `ec` contains
108  
        the error code and `n` is the total number of bytes transferred
107  
        the error code and `n` is the total number of bytes transferred
109  
        before the error.
108  
        before the error.
110  

109  

111  
    @par Example
110  
    @par Example
112  
    @code
111  
    @code
113  
    task<void> transfer_body(BufferSource auto& source, WriteStream auto& stream)
112  
    task<void> transfer_body(BufferSource auto& source, WriteStream auto& stream)
114  
    {
113  
    {
115  
        auto [ec, n] = co_await push_to(source, stream);
114  
        auto [ec, n] = co_await push_to(source, stream);
116  
        if (ec)
115  
        if (ec)
117  
        {
116  
        {
118  
            // Handle error
117  
            // Handle error
119  
        }
118  
        }
120  
        // n bytes were transferred
119  
        // n bytes were transferred
121  
    }
120  
    }
122  
    @endcode
121  
    @endcode
123  

122  

124  
    @see BufferSource, WriteStream, pull_from
123  
    @see BufferSource, WriteStream, pull_from
125  
*/
124  
*/
126  
template<BufferSource Src, WriteStream Stream>
125  
template<BufferSource Src, WriteStream Stream>
127 -
task<io_result<std::size_t>>
126 +
    requires (!WriteSink<Stream>)
 
127 +
io_task<std::size_t>
128  
push_to(Src& source, Stream& stream)
128  
push_to(Src& source, Stream& stream)
129  
{
129  
{
130  
    const_buffer arr[detail::max_iovec_];
130  
    const_buffer arr[detail::max_iovec_];
131  
    std::size_t total = 0;
131  
    std::size_t total = 0;
132  

132  

133  
    for(;;)
133  
    for(;;)
134  
    {
134  
    {
135  
        auto [ec, bufs] = co_await source.pull(arr);
135  
        auto [ec, bufs] = co_await source.pull(arr);
 
136 +
        if(ec == cond::eof)
 
137 +
            co_return {{}, total};
136  
        if(ec)
138  
        if(ec)
137 -

 
138 -
        if(bufs.empty())
 
139 -
            co_return {{}, total};
 
140  
            co_return {ec, total};
139  
            co_return {ec, total};
141  

140  

142  
        auto [write_ec, n] = co_await stream.write_some(bufs);
141  
        auto [write_ec, n] = co_await stream.write_some(bufs);
143  
        if(write_ec)
142  
        if(write_ec)
144  
            co_return {write_ec, total};
143  
            co_return {write_ec, total};
145  

144  

146  
        total += n;
145  
        total += n;
147  
        source.consume(n);
146  
        source.consume(n);
148  
    }
147  
    }
149  
}
148  
}
150  

149  

151  
} // namespace capy
150  
} // namespace capy
152  
} // namespace boost
151  
} // namespace boost
153  

152  

154  
#endif
153  
#endif