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

Generated by: LCOV version 2.3