LCOV - code coverage report
Current view: top level - boost/http/json - json_sink.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.1 % 35 34
Test Date: 2026-02-02 17:02:49 Functions: 100.0 % 8 8

            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              : public:
      60              :     /** Default constructor.
      61              : 
      62              :         Constructs a sink with a default-initialized stream parser.
      63              :     */
      64            8 :     json_sink() = default;
      65              : 
      66              :     /** Constructor with parse options.
      67              : 
      68              :         @param opt Options controlling JSON parsing behavior.
      69              :     */
      70              :     explicit
      71            1 :     json_sink(json::parse_options const& opt)
      72            1 :         : parser_(json::storage_ptr(), opt)
      73              :     {
      74            1 :     }
      75              : 
      76              :     /** Constructor with storage and parse options.
      77              : 
      78              :         @param sp The storage to use for parsed values.
      79              :         @param opt Options controlling JSON parsing behavior.
      80              :     */
      81              :     json_sink(
      82              :         json::storage_ptr sp,
      83              :         json::parse_options const& opt = {})
      84              :         : parser_(std::move(sp), opt)
      85              :     {
      86              :     }
      87              : 
      88              :     /** Write data to the JSON parser.
      89              : 
      90              :         Writes all bytes from the buffer sequence to the stream parser.
      91              : 
      92              :         @param buffers Buffer sequence containing JSON data.
      93              : 
      94              :         @return An awaitable yielding `(error_code,std::size_t)`.
      95              :             On success, returns the total bytes written.
      96              :     */
      97              :     template<capy::ConstBufferSequence CB>
      98              :     capy::immediate<capy::io_result<std::size_t>>
      99            5 :     write(CB const& buffers)
     100              :     {
     101            5 :         return write(buffers, false);
     102              :     }
     103              : 
     104              :     /** Write data with optional end-of-stream.
     105              : 
     106              :         Writes all bytes from the buffer sequence to the stream parser.
     107              :         If @p eof is true, also finishes parsing.
     108              : 
     109              :         @param buffers Buffer sequence containing JSON data.
     110              :         @param eof If true, signals end of JSON data after writing.
     111              : 
     112              :         @return An awaitable yielding `(error_code,std::size_t)`.
     113              :             On success, returns the total bytes written.
     114              :     */
     115              :     template<capy::ConstBufferSequence CB>
     116              :     capy::immediate<capy::io_result<std::size_t>>
     117           12 :     write(CB const& buffers, bool eof)
     118              :     {
     119           12 :         system::error_code ec;
     120           12 :         std::size_t total = 0;
     121           12 :         auto const end = capy::end(buffers);
     122           23 :         for(auto it = capy::begin(buffers); it != end; ++it)
     123              :         {
     124           12 :             capy::const_buffer buf(*it);
     125           24 :             auto n = parser_.write(
     126           12 :                 static_cast<char const*>(buf.data()),
     127              :                 buf.size(),
     128              :                 ec);
     129           12 :             total += n;
     130           12 :             if(ec.failed())
     131            1 :                 return {ec, total};
     132              :         }
     133              : 
     134           11 :         if(eof)
     135              :         {
     136            6 :             parser_.finish(ec);
     137            6 :             if(ec.failed())
     138            0 :                 return {ec, total};
     139              :         }
     140              : 
     141           11 :         return capy::ready(total);
     142              :     }
     143              : 
     144              :     /** Signal end of JSON data.
     145              : 
     146              :         Finishes parsing and validates the JSON is complete.
     147              : 
     148              :         @return An awaitable yielding `(error_code)`.
     149              :     */
     150              :     capy::immediate<capy::io_result<>>
     151            2 :     write_eof()
     152              :     {
     153            2 :         system::error_code ec;
     154            2 :         parser_.finish(ec);
     155            2 :         if(ec.failed())
     156            1 :             return {ec};
     157            1 :         return {};
     158              :     }
     159              : 
     160              :     /** Check if parsing is complete.
     161              : 
     162              :         @return `true` if a complete JSON value has been parsed.
     163              :     */
     164              :     bool
     165           11 :     done() const noexcept
     166              :     {
     167           11 :         return parser_.done();
     168              :     }
     169              : 
     170              :     /** Release the parsed JSON value.
     171              : 
     172              :         Returns the parsed value and resets the parser for reuse.
     173              : 
     174              :         @par Preconditions
     175              :         `this->done() == true`
     176              : 
     177              :         @return The parsed JSON value.
     178              :     */
     179              :     json::value
     180            7 :     release()
     181              :     {
     182            7 :         return parser_.release();
     183              :     }
     184              : 
     185              :     /** Reset the parser for a new JSON value.
     186              : 
     187              :         Clears all state and prepares to parse a new value.
     188              :     */
     189              :     void
     190            1 :     reset()
     191              :     {
     192            1 :         parser_.reset();
     193            1 :     }
     194              : };
     195              : 
     196              : } // namespace http
     197              : } // namespace boost
     198              : 
     199              : #endif
        

Generated by: LCOV version 2.3