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_READ_HPP 11   #ifndef BOOST_CAPY_READ_HPP
12   #define BOOST_CAPY_READ_HPP 12   #define BOOST_CAPY_READ_HPP
13   13  
14   #include <boost/capy/detail/config.hpp> 14   #include <boost/capy/detail/config.hpp>
15   #include <boost/capy/cond.hpp> 15   #include <boost/capy/cond.hpp>
16   #include <boost/capy/results.hpp> 16   #include <boost/capy/results.hpp>
17   #include <boost/capy/task.hpp> 17   #include <boost/capy/task.hpp>
18   #include <boost/capy/buffers.hpp> 18   #include <boost/capy/buffers.hpp>
19   #include <boost/capy/buffers/consuming_buffers.hpp> 19   #include <boost/capy/buffers/consuming_buffers.hpp>
20   #include <boost/capy/concept/read_stream.hpp> 20   #include <boost/capy/concept/read_stream.hpp>
21   21  
22   #include <algorithm> 22   #include <algorithm>
23   #include <cstddef> 23   #include <cstddef>
24   24  
25   namespace boost { 25   namespace boost {
26   namespace capy { 26   namespace capy {
27   27  
28   /** Read data from a stream until the buffer sequence is full. 28   /** Read data from a stream until the buffer sequence is full.
29   29  
30   @par Await-effects 30   @par Await-effects
31   31  
32   Reads data from `stream` via awaiting `stream.read_some` repeatedly 32   Reads data from `stream` via awaiting `stream.read_some` repeatedly
33   until: 33   until:
34   34  
35   @li either the entire buffer sequence @c buffers is filled, 35   @li either the entire buffer sequence @c buffers is filled,
36   @li or a contingency occurs on `stream.read_some`. 36   @li or a contingency occurs on `stream.read_some`.
37   37  
38   If `buffer_size(buffers) == 0` then no awaiting `stream.read_some` 38   If `buffer_size(buffers) == 0` then no awaiting `stream.read_some`
39   is performed. This is not a contingency. 39   is performed. This is not a contingency.
40   40  
41   @par Await-returns 41   @par Await-returns
42   An object of type `results<std::size_t>` destructuring as `[ec, n]`. 42   An object of type `results<std::size_t>` destructuring as `[ec, n]`.
43   43  
44   Upon a contingency, `n` represents the number of bytes read so far, 44   Upon a contingency, `n` represents the number of bytes read so far,
45   inclusive of the last partial read. 45   inclusive of the last partial read.
46   46  
47   Contingencies: 47   Contingencies:
48   48  
49   @li The first contingency reported from awaiting @c stream.read_some 49   @li The first contingency reported from awaiting @c stream.read_some
50   while `buffers` is not yet filled. A contingency that accompanies 50   while `buffers` is not yet filled. A contingency that accompanies
51   the read which fills `buffers` is not reported: a completed 51   the read which fills `buffers` is not reported: a completed
52   transfer is a success. 52   transfer is a success.
53   53  
54   Notable conditions: 54   Notable conditions:
55   55  
56   @li @c cond::canceled — Operation was cancelled, 56   @li @c cond::canceled — Operation was cancelled,
57   @li @c cond::eof — Stream reached end before @c buffers was filled. 57   @li @c cond::eof — Stream reached end before @c buffers was filled.
58   58  
59   @par Await-postcondition 59   @par Await-postcondition
60   If `n == buffer_size(buffers)` the transfer completed and `ec` is 60   If `n == buffer_size(buffers)` the transfer completed and `ec` is
61   success; otherwise `ec` is set. 61   success; otherwise `ec` is set.
62   62  
63   @param stream The stream to read from. If the lifetime of `stream` ends 63   @param stream The stream to read from. If the lifetime of `stream` ends
64   before the coroutine finishes, the behavior is undefined. 64   before the coroutine finishes, the behavior is undefined.
65   65  
66   @param buffers The buffer sequence to fill. If the lifetime of the buffer 66   @param buffers The buffer sequence to fill. If the lifetime of the buffer
67   sequence represented by `buffers` ends before the coroutine finishes, the behavior is undefined. 67   sequence represented by `buffers` ends before the coroutine finishes, the behavior is undefined.
68   68  
69   @return A task yielding `results<std::size_t>` whose second element 69   @return A task yielding `results<std::size_t>` whose second element
70   is the number of bytes read. 70   is the number of bytes read.
71   71  
72   @par Remarks 72   @par Remarks
73   Supports _ContextAwaitable cancellation_. 73   Supports _ContextAwaitable cancellation_.
74   74  
75   75  
76   @par Example 76   @par Example
77   77  
78   @par !example example 78   @par !example example
79   79  
80   80  
81   @see ReadStream, MutableBufferSequence 81   @see ReadStream, MutableBufferSequence
82   */ 82   */
83   template <typename S, typename MB> 83   template <typename S, typename MB>
84   requires ReadStream<S> && MutableBufferSequence<MB> 84   requires ReadStream<S> && MutableBufferSequence<MB>
85   auto 85   auto
HITCBC 86   99 read(S& stream, MB buffers) -> 86   99 read(S& stream, MB buffers) ->
87   task<results<std::size_t>> 87   task<results<std::size_t>>
88   { 88   {
89   consuming_buffers consuming(buffers); 89   consuming_buffers consuming(buffers);
90   std::size_t const total_size = buffer_size(buffers); 90   std::size_t const total_size = buffer_size(buffers);
91   std::size_t total_read = 0; 91   std::size_t total_read = 0;
92   92  
93   while(total_read < total_size) 93   while(total_read < total_size)
94   { 94   {
95   auto [ec, n] = co_await stream.read_some(consuming.data()); 95   auto [ec, n] = co_await stream.read_some(consuming.data());
96   consuming.consume(n); 96   consuming.consume(n);
97   total_read += n; 97   total_read += n;
98   // A contingency that still completed the transfer is a success: 98   // A contingency that still completed the transfer is a success:
99   // report it only when the buffer was not filled. 99   // report it only when the buffer was not filled.
100   if(ec && total_read < total_size) 100   if(ec && total_read < total_size)
101   co_return {ec, total_read}; 101   co_return {ec, total_read};
102   } 102   }
103   103  
104   co_return {std::error_code(), total_read}; 104   co_return {std::error_code(), total_read};
HITCBC 105   198 } 105   198 }
106   106  
107   } // namespace capy 107   } // namespace capy
108   } // namespace boost 108   } // namespace boost
109   109  
110   #endif 110   #endif