LCOV - code coverage report
Current view: top level - capy/io - pull_from.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 4 4
Test Date: 2026-02-07 18:59:16 Functions: 100.0 % 4 4

            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_IO_PULL_FROM_HPP
      11              : #define BOOST_CAPY_IO_PULL_FROM_HPP
      12              : 
      13              : #include <boost/capy/detail/config.hpp>
      14              : #include <boost/capy/buffers.hpp>
      15              : #include <boost/capy/cond.hpp>
      16              : #include <boost/capy/concept/buffer_sink.hpp>
      17              : #include <boost/capy/concept/read_source.hpp>
      18              : #include <boost/capy/concept/read_stream.hpp>
      19              : #include <boost/capy/io_task.hpp>
      20              : 
      21              : #include <cstddef>
      22              : #include <span>
      23              : 
      24              : namespace boost {
      25              : namespace capy {
      26              : 
      27              : /** Transfer data from a ReadSource to a BufferSink.
      28              : 
      29              :     This function reads data from the source directly into the sink's
      30              :     internal buffers using the callee-owns-buffers model. The sink
      31              :     provides writable buffers via `prepare()`, the source reads into
      32              :     them, and the sink commits the data. When the source signals EOF,
      33              :     `commit_eof()` is called on the sink to finalize the transfer.
      34              : 
      35              :     @tparam Src The source type, must satisfy @ref ReadSource.
      36              :     @tparam Sink The sink type, must satisfy @ref BufferSink.
      37              : 
      38              :     @param source The source to read data from.
      39              :     @param sink The sink to write data to.
      40              : 
      41              :     @return A task that yields `(std::error_code, std::size_t)`.
      42              :         On success, `ec` is default-constructed (no error) and `n` is
      43              :         the total number of bytes transferred. On error, `ec` contains
      44              :         the error code and `n` is the total number of bytes transferred
      45              :         before the error.
      46              : 
      47              :     @par Example
      48              :     @code
      49              :     task<void> transfer_body(ReadSource auto& source, BufferSink auto& sink)
      50              :     {
      51              :         auto [ec, n] = co_await pull_from(source, sink);
      52              :         if (ec)
      53              :         {
      54              :             // Handle error
      55              :         }
      56              :         // n bytes were transferred
      57              :     }
      58              :     @endcode
      59              : 
      60              :     @see ReadSource, BufferSink, push_to
      61              : */
      62              : template<ReadSource Src, BufferSink Sink>
      63              : io_task<std::size_t>
      64          132 : pull_from(Src& source, Sink& sink)
      65              : {
      66              :     mutable_buffer dst_arr[detail::max_iovec_];
      67              :     std::size_t total = 0;
      68              : 
      69              :     for(;;)
      70              :     {
      71              :         auto dst_bufs = sink.prepare(dst_arr);
      72              :         if(dst_bufs.empty())
      73              :         {
      74              :             // No buffer space available; commit nothing to flush
      75              :             auto [flush_ec] = co_await sink.commit(0);
      76              :             if(flush_ec)
      77              :                 co_return {flush_ec, total};
      78              :             continue;
      79              :         }
      80              : 
      81              :         auto [ec, n] = co_await source.read(
      82              :             std::span<mutable_buffer const>(dst_bufs));
      83              : 
      84              :         if(n > 0)
      85              :         {
      86              :             auto [commit_ec] = co_await sink.commit(n);
      87              :             if(commit_ec)
      88              :                 co_return {commit_ec, total};
      89              :             total += n;
      90              :         }
      91              : 
      92              :         if(ec == cond::eof)
      93              :         {
      94              :             auto [eof_ec] = co_await sink.commit_eof(0);
      95              :             co_return {eof_ec, total};
      96              :         }
      97              : 
      98              :         if(ec)
      99              :             co_return {ec, total};
     100              :     }
     101          264 : }
     102              : 
     103              : /** Transfer data from a ReadStream to a BufferSink.
     104              : 
     105              :     This function reads data from the stream directly into the sink's
     106              :     internal buffers using the callee-owns-buffers model. The sink
     107              :     provides writable buffers via `prepare()`, the stream reads into
     108              :     them using `read_some()`, and the sink commits the data. When the
     109              :     stream signals EOF, `commit_eof()` is called on the sink to
     110              :     finalize the transfer.
     111              : 
     112              :     This overload handles partial reads from the stream, committing
     113              :     data incrementally as it arrives. It loops until EOF is encountered
     114              :     or an error occurs.
     115              : 
     116              :     @tparam Src The source type, must satisfy @ref ReadStream.
     117              :     @tparam Sink The sink type, must satisfy @ref BufferSink.
     118              : 
     119              :     @param source The stream to read data from.
     120              :     @param sink The sink to write data to.
     121              : 
     122              :     @return A task that yields `(std::error_code, std::size_t)`.
     123              :         On success, `ec` is default-constructed (no error) and `n` is
     124              :         the total number of bytes transferred. On error, `ec` contains
     125              :         the error code and `n` is the total number of bytes transferred
     126              :         before the error.
     127              : 
     128              :     @par Example
     129              :     @code
     130              :     task<void> transfer_body(ReadStream auto& stream, BufferSink auto& sink)
     131              :     {
     132              :         auto [ec, n] = co_await pull_from(stream, sink);
     133              :         if (ec)
     134              :         {
     135              :             // Handle error
     136              :         }
     137              :         // n bytes were transferred
     138              :     }
     139              :     @endcode
     140              : 
     141              :     @see ReadStream, BufferSink, push_to
     142              : */
     143              : template<ReadStream Src, BufferSink Sink>
     144              :     requires (!ReadSource<Src>)
     145              : io_task<std::size_t>
     146          200 : pull_from(Src& source, Sink& sink)
     147              : {
     148              :     mutable_buffer dst_arr[detail::max_iovec_];
     149              :     std::size_t total = 0;
     150              : 
     151              :     for(;;)
     152              :     {
     153              :         // Prepare destination buffers from the sink
     154              :         auto dst_bufs = sink.prepare(dst_arr);
     155              :         if(dst_bufs.empty())
     156              :         {
     157              :             // No buffer space available; commit nothing to flush
     158              :             auto [flush_ec] = co_await sink.commit(0);
     159              :             if(flush_ec)
     160              :                 co_return {flush_ec, total};
     161              :             continue;
     162              :         }
     163              : 
     164              :         // Read data from the stream into the sink's buffers
     165              :         auto [ec, n] = co_await source.read_some(
     166              :             std::span<mutable_buffer const>(dst_bufs));
     167              : 
     168              :         // Commit any data that was read
     169              :         if(n > 0)
     170              :         {
     171              :             auto [commit_ec] = co_await sink.commit(n);
     172              :             if(commit_ec)
     173              :                 co_return {commit_ec, total};
     174              :             total += n;
     175              :         }
     176              : 
     177              :         // Check for EOF condition
     178              :         if(ec == cond::eof)
     179              :         {
     180              :             auto [eof_ec] = co_await sink.commit_eof(0);
     181              :             co_return {eof_ec, total};
     182              :         }
     183              : 
     184              :         // Check for other errors
     185              :         if(ec)
     186              :             co_return {ec, total};
     187              :     }
     188          400 : }
     189              : 
     190              : } // namespace capy
     191              : } // namespace boost
     192              : 
     193              : #endif
        

Generated by: LCOV version 2.3