1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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_WRITE_HPP
10  
#ifndef BOOST_CAPY_WRITE_HPP
11  
#define BOOST_CAPY_WRITE_HPP
11  
#define BOOST_CAPY_WRITE_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/io_task.hpp>
14  
#include <boost/capy/io_task.hpp>
15  
#include <boost/capy/buffers.hpp>
15  
#include <boost/capy/buffers.hpp>
16  
#include <boost/capy/buffers/consuming_buffers.hpp>
16  
#include <boost/capy/buffers/consuming_buffers.hpp>
17  
#include <boost/capy/concept/write_stream.hpp>
17  
#include <boost/capy/concept/write_stream.hpp>
18  
#include <system_error>
18  
#include <system_error>
19  

19  

20  
#include <cstddef>
20  
#include <cstddef>
21  

21  

22  
namespace boost {
22  
namespace boost {
23  
namespace capy {
23  
namespace capy {
24  

24  

25  
/** Asynchronously write the entire buffer sequence.
25  
/** Asynchronously write the entire buffer sequence.
26  

26  

27  
    Writes data to the stream by calling `write_some` repeatedly
27  
    Writes data to the stream by calling `write_some` repeatedly
28  
    until the entire buffer sequence is written or an error occurs.
28  
    until the entire buffer sequence is written or an error occurs.
29  

29  

30  
    @li The operation completes when:
30  
    @li The operation completes when:
31  
    @li The entire buffer sequence has been written
31  
    @li The entire buffer sequence has been written
32  
    @li An error occurs
32  
    @li An error occurs
33  
    @li The operation is cancelled
33  
    @li The operation is cancelled
34  

34  

35  
    @par Cancellation
35  
    @par Cancellation
36  
    Supports cancellation via `stop_token` propagated through the
36  
    Supports cancellation via `stop_token` propagated through the
37  
    IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
37  
    IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
38  

38  

39  
    @param stream The stream to write to. The caller retains ownership.
39  
    @param stream The stream to write to. The caller retains ownership.
40  
    @param buffers The buffer sequence to write. The caller retains
40  
    @param buffers The buffer sequence to write. The caller retains
41  
        ownership and must ensure validity until the operation completes.
41  
        ownership and must ensure validity until the operation completes.
42  

42  

43  
    @return An awaitable yielding `(error_code, std::size_t)`.
43  
    @return An awaitable yielding `(error_code, std::size_t)`.
44  
        On success, `n` equals `buffer_size(buffers)`. On error,
44  
        On success, `n` equals `buffer_size(buffers)`. On error,
45  
        `n` is the number of bytes written before the error. Compare
45  
        `n` is the number of bytes written before the error. Compare
46  
        error codes to conditions:
46  
        error codes to conditions:
47  
        @li `cond::canceled` - Operation was cancelled
47  
        @li `cond::canceled` - Operation was cancelled
48  
        @li `std::errc::broken_pipe` - Peer closed connection
48  
        @li `std::errc::broken_pipe` - Peer closed connection
49  

49  

50  
    @par Example
50  
    @par Example
51  

51  

52  
    @code
52  
    @code
53  
    task<> send_response( WriteStream auto& stream, std::string_view body )
53  
    task<> send_response( WriteStream auto& stream, std::string_view body )
54  
    {
54  
    {
55  
        auto [ec, n] = co_await write( stream, make_buffer( body ) );
55  
        auto [ec, n] = co_await write( stream, make_buffer( body ) );
56  
        if( ec )
56  
        if( ec )
57  
            detail::throw_system_error( ec );
57  
            detail::throw_system_error( ec );
58  
        // All bytes written successfully
58  
        // All bytes written successfully
59  
    }
59  
    }
60  
    @endcode
60  
    @endcode
61  

61  

62  
    @see write_some, WriteStream, ConstBufferSequence
62  
    @see write_some, WriteStream, ConstBufferSequence
63  
*/
63  
*/
64  
auto
64  
auto
65  
write(
65  
write(
66  
    WriteStream auto& stream,
66  
    WriteStream auto& stream,
67  
    ConstBufferSequence auto const& buffers) ->
67  
    ConstBufferSequence auto const& buffers) ->
68  
        io_task<std::size_t>
68  
        io_task<std::size_t>
69  
{
69  
{
70  
    consuming_buffers consuming(buffers);
70  
    consuming_buffers consuming(buffers);
71  
    std::size_t const total_size = buffer_size(buffers);
71  
    std::size_t const total_size = buffer_size(buffers);
72  
    std::size_t total_written = 0;
72  
    std::size_t total_written = 0;
73  

73  

74  
    while(total_written < total_size)
74  
    while(total_written < total_size)
75  
    {
75  
    {
76  
        auto [ec, n] = co_await stream.write_some(consuming);
76  
        auto [ec, n] = co_await stream.write_some(consuming);
77  
        if(ec)
77  
        if(ec)
78  
            co_return {ec, total_written};
78  
            co_return {ec, total_written};
79  
        consuming.consume(n);
79  
        consuming.consume(n);
80  
        total_written += n;
80  
        total_written += n;
81  
    }
81  
    }
82  

82  

83  
    co_return {{}, total_written};
83  
    co_return {{}, total_written};
84  
}
84  
}
85  

85  

86  
} // namespace capy
86  
} // namespace capy
87  
} // namespace boost
87  
} // namespace boost
88  

88  

89  
#endif
89  
#endif