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   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/capy 7   // Official repository: https://github.com/cppalliance/capy
8   // 8   //
9   9  
10   #ifndef BOOST_CAPY_READ_HPP 10   #ifndef BOOST_CAPY_READ_HPP
11   #define BOOST_CAPY_READ_HPP 11   #define BOOST_CAPY_READ_HPP
12   12  
13   #include <boost/capy/detail/config.hpp> 13   #include <boost/capy/detail/config.hpp>
14   #include <boost/capy/cond.hpp> 14   #include <boost/capy/cond.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/read_stream.hpp> 18   #include <boost/capy/concept/read_stream.hpp>
19   19  
20   #include <algorithm> 20   #include <algorithm>
21   #include <cstddef> 21   #include <cstddef>
22   22  
23   namespace boost { 23   namespace boost {
24   namespace capy { 24   namespace capy {
25   25  
26   /** Read data from a stream until the buffer sequence is full. 26   /** Read data from a stream until the buffer sequence is full.
27   27  
28   @par Await-effects 28   @par Await-effects
29   29  
30   Reads data from `stream` via awaiting `stream.read_some` repeatedly 30   Reads data from `stream` via awaiting `stream.read_some` repeatedly
31   until: 31   until:
32   32  
33   @li either the entire buffer sequence @c buffers is filled, 33   @li either the entire buffer sequence @c buffers is filled,
34   @li or a contingency occurs on `stream.read_some`. 34   @li or a contingency occurs on `stream.read_some`.
35   35  
36   If `buffer_size(buffers) == 0` then no awaiting `stream.read_some` 36   If `buffer_size(buffers) == 0` then no awaiting `stream.read_some`
37   is performed. This is not a contingency. 37   is performed. This is not a contingency.
38   38  
39   @par Await-returns 39   @par Await-returns
40   An object of type `io_result<std::size_t>` destructuring as `[ec, n]`. 40   An object of type `io_result<std::size_t>` destructuring as `[ec, n]`.
41   41  
42   Upon a contingency, `n` represents the number of bytes read so far, 42   Upon a contingency, `n` represents the number of bytes read so far,
43   inclusive of the last partial read. 43   inclusive of the last partial read.
44   44  
45   Contingencies: 45   Contingencies:
46   46  
47   @li The first contingency reported from awaiting @c stream.read_some 47   @li The first contingency reported from awaiting @c stream.read_some
48   while `buffers` is not yet filled. A contingency that accompanies 48   while `buffers` is not yet filled. A contingency that accompanies
49   the read which fills `buffers` is not reported: a completed 49   the read which fills `buffers` is not reported: a completed
50   transfer is a success. 50   transfer is a success.
51   51  
52   Notable conditions: 52   Notable conditions:
53   53  
54   @li @c cond::canceled — Operation was cancelled, 54   @li @c cond::canceled — Operation was cancelled,
55   @li @c cond::eof — Stream reached end before @c buffers was filled. 55   @li @c cond::eof — Stream reached end before @c buffers was filled.
56   56  
57   @par Await-postcondition 57   @par Await-postcondition
58   If `n == buffer_size(buffers)` the transfer completed and `ec` is 58   If `n == buffer_size(buffers)` the transfer completed and `ec` is
59   success; otherwise `ec` is set. 59   success; otherwise `ec` is set.
60   60  
61   @param stream The stream to read from. If the lifetime of `stream` ends 61   @param stream The stream to read from. If the lifetime of `stream` ends
62   before the coroutine finishes, the behavior is undefined. 62   before the coroutine finishes, the behavior is undefined.
63   63  
64   @param buffers The buffer sequence to fill. If the lifetime of the buffer 64   @param buffers The buffer sequence to fill. If the lifetime of the buffer
65   sequence represented by `buffers` ends before the coroutine finishes, the behavior is undefined. 65   sequence represented by `buffers` ends before the coroutine finishes, the behavior is undefined.
66   66  
67   67  
68   @par Remarks 68   @par Remarks
69   Supports _IoAwaitable cancellation_. 69   Supports _IoAwaitable cancellation_.
70   70  
71   71  
72   @par Example 72   @par Example
73   73  
74   @code 74   @code
75   capy::task<> process_message(capy::ReadStream auto& stream) 75   capy::task<> process_message(capy::ReadStream auto& stream)
76   { 76   {
77   std::vector<char> header(16); // known header size for some protocol 77   std::vector<char> header(16); // known header size for some protocol
78   auto [ec, n] = co_await capy::read(stream, capy::make_buffer(header)); 78   auto [ec, n] = co_await capy::read(stream, capy::make_buffer(header));
79   if (ec == capy::cond::eof) 79   if (ec == capy::cond::eof)
80   co_return; // Connection closed 80   co_return; // Connection closed
81   if (ec) 81   if (ec)
82   throw std::system_error(ec); 82   throw std::system_error(ec);
83   83  
84   // at this point `header` contains exactly 16 bytes 84   // at this point `header` contains exactly 16 bytes
85   } 85   }
86   @endcode 86   @endcode
87   87  
88   @see ReadStream, MutableBufferSequence 88   @see ReadStream, MutableBufferSequence
89   */ 89   */
90   template <typename S, typename MB> 90   template <typename S, typename MB>
91   requires ReadStream<S> && MutableBufferSequence<MB> 91   requires ReadStream<S> && MutableBufferSequence<MB>
92   auto 92   auto
HITCBC 93   98 read(S& stream, MB buffers) -> 93   98 read(S& stream, MB buffers) ->
94   io_task<std::size_t> 94   io_task<std::size_t>
95   { 95   {
96   consuming_buffers consuming(buffers); 96   consuming_buffers consuming(buffers);
97   std::size_t const total_size = buffer_size(buffers); 97   std::size_t const total_size = buffer_size(buffers);
98   std::size_t total_read = 0; 98   std::size_t total_read = 0;
99   99  
100   while(total_read < total_size) 100   while(total_read < total_size)
101   { 101   {
102   auto [ec, n] = co_await stream.read_some(consuming.data()); 102   auto [ec, n] = co_await stream.read_some(consuming.data());
103   consuming.consume(n); 103   consuming.consume(n);
104   total_read += n; 104   total_read += n;
105   // A contingency that still completed the transfer is a success: 105   // A contingency that still completed the transfer is a success:
106   // report it only when the buffer was not filled. 106   // report it only when the buffer was not filled.
107   if(ec && total_read < total_size) 107   if(ec && total_read < total_size)
108   co_return {ec, total_read}; 108   co_return {ec, total_read};
109   } 109   }
110   110  
111   co_return {{}, total_read}; 111   co_return {{}, total_read};
HITCBC 112   196 } 112   196 }
113   113  
114   } // namespace capy 114   } // namespace capy
115   } // namespace boost 115   } // namespace boost
116   116  
117   #endif 117   #endif