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-03-12 18:24:42 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         136 : 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                 :         auto [commit_ec] = co_await sink.commit(n);
      85                 :         total += n;
      86                 : 
      87                 :         if(commit_ec)
      88                 :             co_return {commit_ec, total};
      89                 : 
      90                 :         if(ec == cond::eof)
      91                 :         {
      92                 :             auto [eof_ec] = co_await sink.commit_eof(0);
      93                 :             co_return {eof_ec, total};
      94                 :         }
      95                 : 
      96                 :         if(ec)
      97                 :             co_return {ec, total};
      98                 :     }
      99             272 : }
     100                 : 
     101                 : /** Transfer data from a ReadStream to a BufferSink.
     102                 : 
     103                 :     This function reads data from the stream directly into the sink's
     104                 :     internal buffers using the callee-owns-buffers model. The sink
     105                 :     provides writable buffers via `prepare()`, the stream reads into
     106                 :     them using `read_some()`, and the sink commits the data. When the
     107                 :     stream signals EOF, `commit_eof()` is called on the sink to
     108                 :     finalize the transfer.
     109                 : 
     110                 :     This overload handles partial reads from the stream, committing
     111                 :     data incrementally as it arrives. It loops until EOF is encountered
     112                 :     or an error occurs.
     113                 : 
     114                 :     @tparam Src The source type, must satisfy @ref ReadStream.
     115                 :     @tparam Sink The sink type, must satisfy @ref BufferSink.
     116                 : 
     117                 :     @param source The stream to read data from.
     118                 :     @param sink The sink to write data to.
     119                 : 
     120                 :     @return A task that yields `(std::error_code, std::size_t)`.
     121                 :         On success, `ec` is default-constructed (no error) and `n` is
     122                 :         the total number of bytes transferred. On error, `ec` contains
     123                 :         the error code and `n` is the total number of bytes transferred
     124                 :         before the error.
     125                 : 
     126                 :     @par Example
     127                 :     @code
     128                 :     task<void> transfer_body(ReadStream auto& stream, BufferSink auto& sink)
     129                 :     {
     130                 :         auto [ec, n] = co_await pull_from(stream, sink);
     131                 :         if (ec)
     132                 :         {
     133                 :             // Handle error
     134                 :         }
     135                 :         // n bytes were transferred
     136                 :     }
     137                 :     @endcode
     138                 : 
     139                 :     @see ReadStream, BufferSink, push_to
     140                 : */
     141                 : template<ReadStream Src, BufferSink Sink>
     142                 :     requires (!ReadSource<Src>)
     143                 : io_task<std::size_t>
     144             226 : pull_from(Src& source, Sink& sink)
     145                 : {
     146                 :     mutable_buffer dst_arr[detail::max_iovec_];
     147                 :     std::size_t total = 0;
     148                 : 
     149                 :     for(;;)
     150                 :     {
     151                 :         // Prepare destination buffers from the sink
     152                 :         auto dst_bufs = sink.prepare(dst_arr);
     153                 :         if(dst_bufs.empty())
     154                 :         {
     155                 :             // No buffer space available; commit nothing to flush
     156                 :             auto [flush_ec] = co_await sink.commit(0);
     157                 :             if(flush_ec)
     158                 :                 co_return {flush_ec, total};
     159                 :             continue;
     160                 :         }
     161                 : 
     162                 :         // Read data from the stream into the sink's buffers
     163                 :         auto [ec, n] = co_await source.read_some(
     164                 :             std::span<mutable_buffer const>(dst_bufs));
     165                 : 
     166                 :         auto [commit_ec] = co_await sink.commit(n);
     167                 :         total += n;
     168                 : 
     169                 :         if(commit_ec)
     170                 :             co_return {commit_ec, total};
     171                 : 
     172                 :         if(ec == cond::eof)
     173                 :         {
     174                 :             auto [eof_ec] = co_await sink.commit_eof(0);
     175                 :             co_return {eof_ec, total};
     176                 :         }
     177                 : 
     178                 :         // Check for other errors
     179                 :         if(ec)
     180                 :             co_return {ec, total};
     181                 :     }
     182             452 : }
     183                 : 
     184                 : } // namespace capy
     185                 : } // namespace boost
     186                 : 
     187                 : #endif
        

Generated by: LCOV version 2.3