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