LCOV - code coverage report
Current view: top level - capy - read.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 6 6
Test Date: 2026-02-17 18:14:47 Functions: 100.0 % 7 7

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       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_READ_HPP
      11                 : #define BOOST_CAPY_READ_HPP
      12                 : 
      13                 : #include <boost/capy/detail/config.hpp>
      14                 : #include <boost/capy/cond.hpp>
      15                 : #include <boost/capy/io_task.hpp>
      16                 : #include <boost/capy/buffers.hpp>
      17                 : #include <boost/capy/buffers/consuming_buffers.hpp>
      18                 : #include <boost/capy/concept/dynamic_buffer.hpp>
      19                 : #include <boost/capy/concept/read_source.hpp>
      20                 : #include <boost/capy/concept/read_stream.hpp>
      21                 : #include <system_error>
      22                 : 
      23                 : #include <cstddef>
      24                 : 
      25                 : namespace boost {
      26                 : namespace capy {
      27                 : 
      28                 : /** Asynchronously read until the buffer sequence is full.
      29                 : 
      30                 :     Reads data from the stream by calling `read_some` repeatedly
      31                 :     until the entire buffer sequence is filled or an error occurs.
      32                 : 
      33                 :     @li The operation completes when:
      34                 :     @li The buffer sequence is completely filled
      35                 :     @li An error occurs (including `cond::eof`)
      36                 :     @li The operation is cancelled
      37                 : 
      38                 :     @par Cancellation
      39                 :     Supports cancellation via `stop_token` propagated through the
      40                 :     IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
      41                 : 
      42                 :     @param stream The stream to read from. The caller retains ownership.
      43                 :     @param buffers The buffer sequence to fill. The caller retains
      44                 :         ownership and must ensure validity until the operation completes.
      45                 : 
      46                 :     @return An awaitable yielding `(error_code, std::size_t)`.
      47                 :         On success, `n` equals `buffer_size(buffers)`. On error,
      48                 :         `n` is the number of bytes read before the error. Compare
      49                 :         error codes to conditions:
      50                 :         @li `cond::eof` - Stream reached end before buffer was filled
      51                 :         @li `cond::canceled` - Operation was cancelled
      52                 : 
      53                 :     @par Example
      54                 : 
      55                 :     @code
      56                 :     task<> read_message( ReadStream auto& stream )
      57                 :     {
      58                 :         char header[16];
      59                 :         auto [ec, n] = co_await read( stream, mutable_buffer( header ) );
      60                 :         if( ec == cond::eof )
      61                 :             co_return;  // Connection closed
      62                 :         if( ec )
      63                 :             detail::throw_system_error( ec );
      64                 :         // header contains exactly 16 bytes
      65                 :     }
      66                 :     @endcode
      67                 : 
      68                 :     @see read_some, ReadStream, MutableBufferSequence
      69                 : */
      70                 : auto
      71 HIT          88 : read(
      72                 :     ReadStream auto& stream,
      73                 :     MutableBufferSequence auto const& buffers) ->
      74                 :         io_task<std::size_t>
      75                 : {
      76                 :     consuming_buffers consuming(buffers);
      77                 :     std::size_t const total_size = buffer_size(buffers);
      78                 :     std::size_t total_read = 0;
      79                 : 
      80                 :     while(total_read < total_size)
      81                 :     {
      82                 :         auto [ec, n] = co_await stream.read_some(consuming);
      83                 :         if(ec)
      84                 :             co_return {ec, total_read};
      85                 :         consuming.consume(n);
      86                 :         total_read += n;
      87                 :     }
      88                 : 
      89                 :     co_return {{}, total_read};
      90             176 : }
      91                 : 
      92                 : /** Asynchronously read all data from a stream into a dynamic buffer.
      93                 : 
      94                 :     Reads data by calling `read_some` repeatedly until EOF is reached
      95                 :     or an error occurs. Data is appended using prepare/commit semantics.
      96                 :     The buffer grows with 1.5x factor when filled.
      97                 : 
      98                 :     @li The operation completes when:
      99                 :     @li End-of-stream is reached (`cond::eof`)
     100                 :     @li An error occurs
     101                 :     @li The operation is cancelled
     102                 : 
     103                 :     @par Cancellation
     104                 :     Supports cancellation via `stop_token` propagated through the
     105                 :     IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
     106                 : 
     107                 :     @param stream The stream to read from. The caller retains ownership.
     108                 :     @param buffers The dynamic buffer to append data to. Must remain
     109                 :         valid until the operation completes.
     110                 :     @param initial_amount Initial bytes to prepare (default 2048).
     111                 : 
     112                 :     @return An awaitable yielding `(error_code, std::size_t)`.
     113                 :         On success (EOF), `ec` is clear and `n` is total bytes read.
     114                 :         On error, `n` is bytes read before the error. Compare error
     115                 :         codes to conditions:
     116                 :         @li `cond::canceled` - Operation was cancelled
     117                 : 
     118                 :     @par Example
     119                 : 
     120                 :     @code
     121                 :     task<std::string> read_body( ReadStream auto& stream )
     122                 :     {
     123                 :         std::string body;
     124                 :         auto [ec, n] = co_await read( stream, string_dynamic_buffer( &body ) );
     125                 :         if( ec )
     126                 :             detail::throw_system_error( ec );
     127                 :         return body;
     128                 :     }
     129                 :     @endcode
     130                 : 
     131                 :     @see read_some, ReadStream, DynamicBufferParam
     132                 : */
     133                 : auto
     134              80 : read(
     135                 :     ReadStream auto& stream,
     136                 :     DynamicBufferParam auto&& buffers,
     137                 :     std::size_t initial_amount = 2048) ->
     138                 :         io_task<std::size_t>
     139                 : {
     140                 :     std::size_t amount = initial_amount;
     141                 :     std::size_t total_read = 0;
     142                 :     for(;;)
     143                 :     {
     144                 :         auto mb = buffers.prepare(amount);
     145                 :         auto const mb_size = buffer_size(mb);
     146                 :         auto [ec, n] = co_await stream.read_some(mb);
     147                 :         buffers.commit(n);
     148                 :         total_read += n;
     149                 :         if(ec == cond::eof)
     150                 :             co_return {{}, total_read};
     151                 :         if(ec)
     152                 :             co_return {ec, total_read};
     153                 :         if(n == mb_size)
     154                 :             amount = amount / 2 + amount;
     155                 :     }
     156             160 : }
     157                 : 
     158                 : /** Asynchronously read all data from a source into a dynamic buffer.
     159                 : 
     160                 :     Reads data by calling `source.read` repeatedly until EOF is reached
     161                 :     or an error occurs. Data is appended using prepare/commit semantics.
     162                 :     The buffer grows with 1.5x factor when filled.
     163                 : 
     164                 :     @li The operation completes when:
     165                 :     @li End-of-stream is reached (`cond::eof`)
     166                 :     @li An error occurs
     167                 :     @li The operation is cancelled
     168                 : 
     169                 :     @par Cancellation
     170                 :     Supports cancellation via `stop_token` propagated through the
     171                 :     IoAwaitable protocol. When cancelled, returns with `cond::canceled`.
     172                 : 
     173                 :     @param source The source to read from. The caller retains ownership.
     174                 :     @param buffers The dynamic buffer to append data to. Must remain
     175                 :         valid until the operation completes.
     176                 :     @param initial_amount Initial bytes to prepare (default 2048).
     177                 : 
     178                 :     @return An awaitable yielding `(error_code, std::size_t)`.
     179                 :         On success (EOF), `ec` is clear and `n` is total bytes read.
     180                 :         On error, `n` is bytes read before the error. Compare error
     181                 :         codes to conditions:
     182                 :         @li `cond::canceled` - Operation was cancelled
     183                 : 
     184                 :     @par Example
     185                 : 
     186                 :     @code
     187                 :     task<std::string> read_body( ReadSource auto& source )
     188                 :     {
     189                 :         std::string body;
     190                 :         auto [ec, n] = co_await read( source, string_dynamic_buffer( &body ) );
     191                 :         if( ec )
     192                 :             detail::throw_system_error( ec );
     193                 :         return body;
     194                 :     }
     195                 :     @endcode
     196                 : 
     197                 :     @see ReadSource, DynamicBufferParam
     198                 : */
     199                 : auto
     200              54 : read(
     201                 :     ReadSource auto& source,
     202                 :     DynamicBufferParam auto&& buffers,
     203                 :     std::size_t initial_amount = 2048) ->
     204                 :         io_task<std::size_t>
     205                 : {
     206                 :     std::size_t amount = initial_amount;
     207                 :     std::size_t total_read = 0;
     208                 :     for(;;)
     209                 :     {
     210                 :         auto mb = buffers.prepare(amount);
     211                 :         auto const mb_size = buffer_size(mb);
     212                 :         auto [ec, n] = co_await source.read(mb);
     213                 :         buffers.commit(n);
     214                 :         total_read += n;
     215                 :         if(ec == cond::eof)
     216                 :             co_return {{}, total_read};
     217                 :         if(ec)
     218                 :             co_return {ec, total_read};
     219                 :         if(n == mb_size)
     220                 :             amount = amount / 2 + amount; // 1.5x growth
     221                 :     }
     222             108 : }
     223                 : 
     224                 : } // namespace capy
     225                 : } // namespace boost
     226                 : 
     227                 : #endif
        

Generated by: LCOV version 2.3