include/boost/capy/write_at_least.hpp

100.0% Lines (2/2) 100.0% List of functions (3/3)
write_at_least.hpp
f(x) Functions (3)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
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_AT_LEAST_HPP
11 #define BOOST_CAPY_WRITE_AT_LEAST_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/consuming_buffers.hpp>
17 #include <boost/capy/concept/write_stream.hpp>
18
19 #include <cstddef>
20 #include <system_error>
21
22 namespace boost {
23 namespace capy {
24
25 /** Write at least a minimum number of bytes to a stream.
26
27 This is a straightforward extension of @ref write. While @ref write
28 transfers exactly `buffer_size(buffers)` bytes, `write_at_least`
29 transfers at least `n` bytes: the loop stops as soon as `n` bytes
30 have been written, even if `buffers` has not been fully consumed.
31 Any bytes beyond `n` that a single `stream.write_some` happens to
32 transfer are counted, but no further awaiting is performed to write
33 the remainder.
34
35 Provided for symmetry with @ref read_at_least.
36
37 @par Await-effects
38
39 If `n > buffer_size(buffers)` the request is impossible to satisfy
40 and the operation fails immediately with
41 `{std::errc::invalid_argument, 0}` without awaiting `stream.write_some`.
42
43 Otherwise writes the contents of `buffers` to `stream` via awaiting
44 `stream.write_some` with consecutive portions of data from `buffers`
45 until:
46
47 @li either at least `n` bytes have been written,
48 @li or a contingency in `stream.write_some` occurs.
49
50 If `n == 0` then no awaiting `stream.write_some` is performed. This is
51 not a contingency.
52
53 @par Await-returns
54 An object of type `io_result<std::size_t>` destructuring as `[ec, n]`.
55
56 Upon a contingency, the count represents the number of bytes written
57 so far.
58
59 Contingencies:
60
61 @li The first contingency reported from awaiting @c stream.write_some
62 while fewer than `n` bytes have been written. A contingency that
63 accompanies the write which reaches `n` is not reported: a
64 satisfied request is a success.
65
66 Notable conditions:
67
68 @li @c std::errc::invalid_argument — `n` exceeds `buffer_size(buffers)`,
69 @li @c cond::canceled — Operation was cancelled,
70 @li @c std::errc::broken_pipe — Peer closed connection.
71
72 @par Await-postcondition
73 On success the returned count is greater than or equal to `n` and
74 less than or equal to `buffer_size(buffers)`, and `ec` is success;
75 otherwise `ec` is set.
76
77 @param stream The stream to write to. If the lifetime of `stream` ends
78 before the coroutine finishes, the behavior is undefined.
79
80 @param buffers The buffer sequence to write. If the lifetime of the
81 buffer sequence represented by `buffers` ends before the coroutine
82 finishes, the behavior is undefined.
83
84 @param n The minimum number of bytes to write. Must not exceed
85 `buffer_size(buffers)`.
86
87 @par Remarks
88 Supports _IoAwaitable cancellation_.
89
90 @par Example
91
92 @code
93 capy::task<> flush_at_least(capy::WriteStream auto& stream, std::string_view data)
94 {
95 auto [ec, n] = co_await capy::write_at_least(
96 stream, capy::make_buffer(data), 8);
97 if(ec)
98 throw std::system_error(ec);
99
100 // at least 8 bytes written; n may be larger
101 }
102 @endcode
103
104 @see write, WriteStream, ConstBufferSequence
105 */
106 template <WriteStream S, ConstBufferSequence CB>
107 auto
108 33x write_at_least(S& stream, CB buffers, std::size_t n) -> io_task<std::size_t>
109 {
110 consuming_buffers consuming(buffers);
111 std::size_t const total_size = buffer_size(buffers);
112
113 if(n > total_size)
114 co_return {make_error_code(std::errc::invalid_argument), 0};
115
116 std::size_t total_written = 0;
117
118 while(total_written < n)
119 {
120 auto [ec, m] = co_await stream.write_some(consuming.data());
121 consuming.consume(m);
122 total_written += m;
123 // A contingency that still satisfied the request is a success:
124 // report it only when fewer than n bytes were written.
125 if(ec && total_written < n)
126 co_return {ec, total_written};
127 }
128
129 co_return {{}, total_written};
130 66x }
131
132 } // namespace capy
133 } // namespace boost
134
135 #endif
136