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-07 18:59:16 Functions: 100.0 % 6 6

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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           50 : 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          100 : }
      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