include/boost/http/json/json_sink.hpp

90.0% Lines (36/40) 75.0% List of functions (9/12)
json_sink.hpp
f(x) Functions (12)
Function Calls Lines Blocks
boost::capy::immediate<boost::capy::io_result<unsigned long> > boost::http::json_sink::write_impl<boost::capy::const_buffer>(boost::capy::const_buffer const&, bool) :61 12x 93.8% 88.0% boost::capy::immediate<boost::capy::io_result<unsigned long> > boost::http::json_sink::write_impl<std::span<boost::capy::const_buffer, 18446744073709551615ul> >(std::span<boost::capy::const_buffer, 18446744073709551615ul> const&, bool) :61 0 0.0% 0.0% boost::http::json_sink::json_sink() :91 8x 100.0% 100.0% boost::http::json_sink::json_sink(boost::json::parse_options const&) :98 1x 100.0% 100.0% boost::http::json_sink::json_sink(boost::json::storage_ptr, boost::json::parse_options const&) :108 0 0.0% 0.0% boost::capy::immediate<boost::capy::io_result<unsigned long> > boost::http::json_sink::write<boost::capy::const_buffer>(boost::capy::const_buffer const&) :142 5x 100.0% 100.0% boost::capy::immediate<boost::capy::io_result<unsigned long> > boost::http::json_sink::write<std::span<boost::capy::const_buffer, 18446744073709551615ul> >(std::span<boost::capy::const_buffer, 18446744073709551615ul> const&) :142 0 0.0% 0.0% boost::capy::immediate<boost::capy::io_result<unsigned long> > boost::http::json_sink::write<boost::capy::const_buffer>(boost::capy::const_buffer const&, bool) :160 7x 100.0% 100.0% boost::http::json_sink::write_eof() :189 2x 100.0% 100.0% boost::http::json_sink::done() const :203 11x 100.0% 100.0% boost::http::json_sink::release() :218 7x 100.0% 100.0% boost::http::json_sink::reset() :228 1x 100.0% 100.0%
Line TLA Hits 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 12x write_impl(CB const& buffers, bool eof)
62 {
63 12x std::error_code ec;
64 12x std::size_t total = 0;
65 12x auto const end = capy::end(buffers);
66 23x for(auto it = capy::begin(buffers); it != end; ++it)
67 {
68 12x capy::const_buffer buf(*it);
69 24x auto n = parser_.write(
70 12x static_cast<char const*>(buf.data()),
71 buf.size(),
72 ec);
73 12x total += n;
74 12x if(ec)
75 1x return capy::ready(ec, total);
76 }
77 11x if(eof)
78 {
79 6x parser_.finish(ec);
80 6x if(ec)
81 return capy::ready(ec, total);
82 }
83 11x return capy::ready(total);
84 }
85
86 public:
87 /** Default constructor.
88
89 Constructs a sink with a default-initialized stream parser.
90 */
91 8x json_sink() = default;
92
93 /** Constructor with parse options.
94
95 @param opt Options controlling JSON parsing behavior.
96 */
97 explicit
98 1x json_sink(json::parse_options const& opt)
99 1x : parser_(json::storage_ptr(), opt)
100 {
101 1x }
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 json_sink(
109 json::storage_ptr sp,
110 json::parse_options const& opt = {})
111 : parser_(std::move(sp), opt)
112 {
113 }
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 5x write(CB const& buffers)
143 {
144 5x 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 7x write(CB const& buffers, bool eof)
161 {
162 7x 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 2x write_eof()
190 {
191 2x std::error_code ec;
192 2x parser_.finish(ec);
193 2x if(ec)
194 1x return capy::ready(ec);
195 1x 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 11x done() const noexcept
204 {
205 11x 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 7x release()
219 {
220 7x 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 1x reset()
229 {
230 1x parser_.reset();
231 1x }
232 };
233
234 } // namespace http
235 } // namespace boost
236
237 #endif
238