TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/capy
9 : //
10 :
11 : #ifndef BOOST_CAPY_WRITE_HPP
12 : #define BOOST_CAPY_WRITE_HPP
13 :
14 : #include <boost/capy/detail/config.hpp>
15 : #include <boost/capy/io_task.hpp>
16 : #include <boost/capy/buffers.hpp>
17 : #include <boost/capy/buffers/consuming_buffers.hpp>
18 : #include <boost/capy/concept/write_stream.hpp>
19 : #include <system_error>
20 :
21 : #include <cstddef>
22 :
23 : namespace boost {
24 : namespace capy {
25 :
26 : /** Write an entire buffer sequence to a stream.
27 :
28 : @par Await-effects
29 :
30 : Writes the contents of `buffers` to `stream` via awaiting
31 : `stream.write_some` with consecutive portions of data from `buffers`
32 : until:
33 :
34 : @li either the full content of @c buffers is processed,
35 : @li or a contingency in `stream.write_some` occurs.
36 :
37 : If `buffer_size(buffers) == 0` then no awaiting `stream.write_some`
38 : is performed. This is not a contingency.
39 :
40 :
41 : @par Await-returns
42 :
43 : An object of type `io_result<std::size_t>` destructuring as `[ec, n]`.
44 :
45 : Upon a contingency, `n` represents the number of bytes written
46 : so far.
47 :
48 : Otherwise `n` represents the number of bytes written.
49 :
50 : Contingencies:
51 :
52 : @li The first contingency reported from awaiting @c stream.write_some
53 : while not all bytes have been written. A contingency that accompanies
54 : the write which transfers the last bytes is not reported: a completed
55 : transfer is a success.
56 :
57 : Notable conditions:
58 :
59 : @li @c cond::canceled — Operation was cancelled,
60 : @li @c std::errc::broken_pipe — Peer closed connection.
61 :
62 :
63 : @par Await-postcondition
64 :
65 : If `n == buffer_size(buffers)` the transfer completed and `ec` is
66 : success; otherwise `ec` is set.
67 :
68 :
69 : @param stream The stream to write to. If the lifetime of `stream` ends
70 : before the coroutine finishes, the behavior is undefined.
71 :
72 : @param buffers The buffer sequence to write. If the lifetime of the buffer
73 : sequence represented by `buffers` ends
74 : before the coroutine finishes, the behavior is undefined.
75 :
76 : @return A task yielding `io_result<std::size_t>` whose second element
77 : is the number of bytes written.
78 :
79 : @par Remarks
80 :
81 : Supports _IoAwaitable cancellation_.
82 :
83 : @par Example
84 :
85 : @code
86 : capy::task<> send_response(capy::WriteStream auto& stream, std::string_view body)
87 : {
88 : auto [ec, n] = co_await capy::write(stream, capy::make_buffer(body));
89 : if (ec)
90 : throw std::system_error(ec);
91 :
92 : // All bytes written successfully
93 : }
94 : @endcode
95 :
96 : @see WriteStream, ConstBufferSequence, IoAwaitable, io_result, cond.
97 : */
98 : template <WriteStream S, ConstBufferSequence CB>
99 HIT 70 : auto write(S& stream, CB buffers) -> io_task<std::size_t>
100 : {
101 : consuming_buffers consuming(buffers);
102 : std::size_t const total_size = buffer_size(buffers);
103 : std::size_t total_written = 0;
104 :
105 : while(total_written < total_size)
106 : {
107 : auto [ec, n] = co_await stream.write_some(consuming.data());
108 : consuming.consume(n);
109 : total_written += n;
110 : // A contingency that still completed the transfer is a success:
111 : // report it only when not all bytes were written.
112 : if(ec && total_written < total_size)
113 : co_return {ec, total_written};
114 : }
115 :
116 : co_return {{}, total_written};
117 140 : }
118 :
119 : } // namespace capy
120 : } // namespace boost
121 :
122 : #endif
|