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_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_result.hpp>
14  
#include <boost/capy/io_result.hpp>
15  
#include <boost/capy/task.hpp>
15  
#include <boost/capy/task.hpp>
16  
#include <boost/capy/buffers.hpp>
16  
#include <boost/capy/buffers.hpp>
17  
#include <boost/capy/buffers/consuming_buffers.hpp>
17  
#include <boost/capy/buffers/consuming_buffers.hpp>
18  
#include <boost/capy/concept/write_stream.hpp>
18  
#include <boost/capy/concept/write_stream.hpp>
19  
#include <system_error>
19  
#include <system_error>
20  

20  

21  
#include <cstddef>
21  
#include <cstddef>
22  

22  

23  
namespace boost {
23  
namespace boost {
24  
namespace capy {
24  
namespace capy {
25  

25  

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

27  

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

30  

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

35  

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

39  

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

43  

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

50  

51  
    @par Example
51  
    @par Example
52  

52  

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

62  

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

74  

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

83  

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

86  

87  
} // namespace capy
87  
} // namespace capy
88  
} // namespace boost
88  
} // namespace boost
89  

89  

90  
#endif
90  
#endif