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