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