LCOV - code coverage report
Current view: top level - include/boost/http/json - json_sink.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 90.0 % 40 36
Test Date: 2026-02-09 01:37:05 Functions: 75.0 % 12 9

            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           12 :     write_impl(CB const& buffers, bool eof)
      62              :     {
      63           12 :         system::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.failed())
      75            1 :                 return {ec, total};
      76              :         }
      77           11 :         if(eof)
      78              :         {
      79            6 :             parser_.finish(ec);
      80            6 :             if(ec.failed())
      81            0 :                 return {ec, total};
      82              :         }
      83           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            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            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 :         system::error_code ec;
     192            2 :         parser_.finish(ec);
     193            2 :         if(ec.failed())
     194            1 :             return {ec};
     195            1 :         return {};
     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