LCOV - code coverage report
Current view: top level - include/boost/http/json - json_sink.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 90.0 % 40 36 4
Test Date: 2026-06-13 19:44:58 Functions: 75.0 % 12 9 3

           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/http
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_HTTP_JSON_JSON_SINK_HPP
      11                 : #define BOOST_HTTP_JSON_JSON_SINK_HPP
      12                 : 
      13                 : #include <boost/http/config.hpp>
      14                 : 
      15                 : #include <boost/capy/buffers.hpp>
      16                 : #include <boost/capy/concept/const_buffer_sequence.hpp>
      17                 : #include <boost/capy/ex/immediate.hpp>
      18                 : #include <boost/capy/io_result.hpp>
      19                 : #include <boost/json/stream_parser.hpp>
      20                 : #include <boost/json/value.hpp>
      21                 : 
      22                 : namespace boost {
      23                 : namespace http {
      24                 : 
      25                 : /** A sink for streaming JSON data to a parser.
      26                 : 
      27                 :     This class wraps a `boost::json::stream_parser` and satisfies the
      28                 :     @ref capy::WriteSink concept, enabling incremental JSON parsing
      29                 :     from any data source that produces buffer sequences.
      30                 : 
      31                 :     Since JSON parsing is synchronous, all operations return
      32                 :     @ref capy::immediate awaitables with zero suspension overhead.
      33                 : 
      34                 :     @par Example
      35                 :     @code
      36                 :     json_sink sink;
      37                 : 
      38                 :     // Write JSON data incrementally
      39                 :     auto [ec1, n1] = co_await sink.write(capy::make_buffer("{\"key\":"));
      40                 :     auto [ec2, n2] = co_await sink.write(capy::make_buffer("42}"), true);
      41                 : 
      42                 :     // Or use write_eof() separately
      43                 :     auto [ec3] = co_await sink.write_eof();
      44                 : 
      45                 :     // Retrieve the parsed value
      46                 :     json::value v = sink.release();
      47                 :     @endcode
      48                 : 
      49                 :     @par Thread Safety
      50                 :     Distinct objects: Safe.
      51                 :     Shared objects: Unsafe.
      52                 : 
      53                 :     @see capy::WriteSink, json::stream_parser
      54                 : */
      55                 : class json_sink
      56                 : {
      57                 :     json::stream_parser parser_;
      58                 : 
      59                 :     template<capy::ConstBufferSequence CB>
      60                 :     capy::immediate<capy::io_result<std::size_t>>
      61 HIT          12 :     write_impl(CB const& buffers, bool eof)
      62                 :     {
      63              12 :         std::error_code ec;
      64              12 :         std::size_t total = 0;
      65              12 :         auto const end = capy::end(buffers);
      66              23 :         for(auto it = capy::begin(buffers); it != end; ++it)
      67                 :         {
      68              12 :             capy::const_buffer buf(*it);
      69              24 :             auto n = parser_.write(
      70              12 :                 static_cast<char const*>(buf.data()),
      71                 :                 buf.size(),
      72                 :                 ec);
      73              12 :             total += n;
      74              12 :             if(ec)
      75               1 :                 return capy::ready(ec, total);
      76                 :         }
      77              11 :         if(eof)
      78                 :         {
      79               6 :             parser_.finish(ec);
      80               6 :             if(ec)
      81 MIS           0 :                 return capy::ready(ec, total);
      82                 :         }
      83 HIT          11 :         return capy::ready(total);
      84                 :     }
      85                 : 
      86                 : public:
      87                 :     /** Default constructor.
      88                 : 
      89                 :         Constructs a sink with a default-initialized stream parser.
      90                 :     */
      91               8 :     json_sink() = default;
      92                 : 
      93                 :     /** Constructor with parse options.
      94                 : 
      95                 :         @param opt Options controlling JSON parsing behavior.
      96                 :     */
      97                 :     explicit
      98               1 :     json_sink(json::parse_options const& opt)
      99               1 :         : parser_(json::storage_ptr(), opt)
     100                 :     {
     101               1 :     }
     102                 : 
     103                 :     /** Constructor with storage and parse options.
     104                 : 
     105                 :         @param sp The storage to use for parsed values.
     106                 :         @param opt Options controlling JSON parsing behavior.
     107                 :     */
     108 MIS           0 :     json_sink(
     109                 :         json::storage_ptr sp,
     110                 :         json::parse_options const& opt = {})
     111               0 :         : parser_(std::move(sp), opt)
     112                 :     {
     113               0 :     }
     114                 : 
     115                 :     /** Write some data to the JSON parser.
     116                 : 
     117                 :         Writes bytes from the buffer sequence to the stream parser.
     118                 : 
     119                 :         @param buffers Buffer sequence containing JSON data.
     120                 : 
     121                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     122                 :             On success, returns the total bytes written.
     123                 :     */
     124                 :     template<capy::ConstBufferSequence CB>
     125                 :     capy::immediate<capy::io_result<std::size_t>>
     126                 :     write_some(CB const& buffers)
     127                 :     {
     128                 :         return write_impl(buffers, false);
     129                 :     }
     130                 : 
     131                 :     /** Write data to the JSON parser.
     132                 : 
     133                 :         Writes all bytes from the buffer sequence to the stream parser.
     134                 : 
     135                 :         @param buffers Buffer sequence containing JSON data.
     136                 : 
     137                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     138                 :             On success, returns the total bytes written.
     139                 :     */
     140                 :     template<capy::ConstBufferSequence CB>
     141                 :     capy::immediate<capy::io_result<std::size_t>>
     142 HIT           5 :     write(CB const& buffers)
     143                 :     {
     144               5 :         return write_impl(buffers, false);
     145                 :     }
     146                 : 
     147                 :     /** Write data with optional end-of-stream.
     148                 : 
     149                 :         Writes all bytes from the buffer sequence to the stream parser.
     150                 :         If @p eof is true, also finishes parsing.
     151                 : 
     152                 :         @param buffers Buffer sequence containing JSON data.
     153                 :         @param eof If true, signals end of JSON data after writing.
     154                 : 
     155                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     156                 :             On success, returns the total bytes written.
     157                 :     */
     158                 :     template<capy::ConstBufferSequence CB>
     159                 :     capy::immediate<capy::io_result<std::size_t>>
     160               7 :     write(CB const& buffers, bool eof)
     161                 :     {
     162               7 :         return write_impl(buffers, eof);
     163                 :     }
     164                 : 
     165                 :     /** Write final data and signal end of JSON data.
     166                 : 
     167                 :         Writes all bytes from the buffer sequence to the stream
     168                 :         parser, then finishes parsing.
     169                 : 
     170                 :         @param buffers Buffer sequence containing JSON data.
     171                 : 
     172                 :         @return An awaitable yielding `(error_code,std::size_t)`.
     173                 :             On success, returns the total bytes written.
     174                 :     */
     175                 :     template<capy::ConstBufferSequence CB>
     176                 :     capy::immediate<capy::io_result<std::size_t>>
     177                 :     write_eof(CB const& buffers)
     178                 :     {
     179                 :         return write_impl(buffers, true);
     180                 :     }
     181                 : 
     182                 :     /** Signal end of JSON data.
     183                 : 
     184                 :         Finishes parsing and validates the JSON is complete.
     185                 : 
     186                 :         @return An awaitable yielding `(error_code)`.
     187                 :     */
     188                 :     capy::immediate<capy::io_result<>>
     189               2 :     write_eof()
     190                 :     {
     191               2 :         std::error_code ec;
     192               2 :         parser_.finish(ec);
     193               2 :         if(ec)
     194               1 :             return capy::ready(ec);
     195               1 :         return capy::ready();
     196                 :     }
     197                 : 
     198                 :     /** Check if parsing is complete.
     199                 : 
     200                 :         @return `true` if a complete JSON value has been parsed.
     201                 :     */
     202                 :     bool
     203              11 :     done() const noexcept
     204                 :     {
     205              11 :         return parser_.done();
     206                 :     }
     207                 : 
     208                 :     /** Release the parsed JSON value.
     209                 : 
     210                 :         Returns the parsed value and resets the parser for reuse.
     211                 : 
     212                 :         @par Preconditions
     213                 :         `this->done() == true`
     214                 : 
     215                 :         @return The parsed JSON value.
     216                 :     */
     217                 :     json::value
     218               7 :     release()
     219                 :     {
     220               7 :         return parser_.release();
     221                 :     }
     222                 : 
     223                 :     /** Reset the parser for a new JSON value.
     224                 : 
     225                 :         Clears all state and prepares to parse a new value.
     226                 :     */
     227                 :     void
     228               1 :     reset()
     229                 :     {
     230               1 :         parser_.reset();
     231               1 :     }
     232                 : };
     233                 : 
     234                 : } // namespace http
     235                 : } // namespace boost
     236                 : 
     237                 : #endif
        

Generated by: LCOV version 2.3