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-17 18:14:47 Functions: 100.0 % 4 4

           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_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 HIT         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