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