src/json.cpp

100.0% Lines (25/25) 100.0% List of functions (12/12) 100.0% Branches (9/9)
json.cpp
f(x) Functions (12)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Mohammad Nejati
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/burl
8 //
9
10 #include <boost/burl/json.hpp>
11
12 #include <boost/capy/buffers.hpp>
13 #include <boost/json/serializer.hpp>
14 #include <boost/json/stream_parser.hpp>
15
16 #include <cstddef>
17 #include <cstdint>
18 #include <optional>
19 #include <string>
20 #include <system_error>
21 #include <utility>
22
23 namespace boost
24 {
25 namespace burl
26 {
27 namespace
28 {
29
30 class json_body
31 {
32 json::value value_;
33
34 public:
35 5x explicit json_body(json::value value)
36 5x : value_(std::move(value))
37 {
38 5x }
39
40 std::optional<std::string>
41 5x content_type() const
42 {
43 5x return "application/json";
44 }
45
46 std::optional<std::uint64_t>
47 5x content_length() const noexcept
48 {
49 5x return std::nullopt;
50 }
51
52 capy::io_task<>
53
1/1
✓ Branch 1 taken 30 times.
30x write(http::any_buffer_sink& sink) const
54 {
55 json::serializer sr;
56 sr.reset(&value_);
57
58 for(;;)
59 {
60 capy::mutable_buffer arr[2];
61 auto dst = sink.prepare(arr);
62
63 std::size_t n = 0;
64 for(capy::mutable_buffer b : dst)
65 {
66 if(sr.done())
67 break;
68 n += sr.read(static_cast<char*>(b.data()), b.size()).size();
69 }
70
71 if(sr.done())
72 {
73 auto [ec] = co_await sink.commit_eof(n);
74 co_return { ec };
75 }
76
77 if(auto [ec] = co_await sink.commit(n); ec)
78 co_return { ec };
79 }
80 60x }
81 };
82
83 } // namespace
84
85 any_request_body
86 2x tag_invoke(body_from_tag<json::value>, json::value value)
87 {
88
1/1
✓ Branch 4 taken 2 times.
2x return json_body{ std::move(value) };
89 }
90
91 capy::io_task<json::value>
92
1/1
✓ Branch 1 taken 17 times.
17x tag_invoke(body_to_tag<json::value>, response& resp)
93 {
94 auto source = resp.as_buffer_source();
95 json::stream_parser parser;
96
97 for(;;)
98 {
99 capy::const_buffer arr[2];
100 auto [ec, bufs] = co_await source.pull(arr);
101 if(ec)
102 {
103 if(ec == capy::error::eof)
104 {
105 parser.finish(ec);
106 if(ec)
107 co_return { ec, {} };
108 co_return { std::error_code(), parser.release() };
109 }
110 co_return { ec, {} };
111 }
112 std::size_t n = 0;
113 for(const auto& buf : bufs)
114 {
115 n += parser.write_some(
116 { static_cast<const char*>(buf.data()), buf.size() }, ec);
117 if(ec)
118 co_return { ec, {} };
119 }
120 source.consume(n);
121 }
122 34x }
123
124 any_request_body
125 1x tag_invoke(body_from_tag<json::object>, json::object value)
126 {
127
1/1
✓ Branch 5 taken 1 time.
1x return json_body{ std::move(value) };
128 }
129
130 capy::io_task<json::object>
131
1/1
✓ Branch 1 taken 2 times.
2x tag_invoke(body_to_tag<json::object>, response& resp)
132 {
133 auto [ec, jv] = co_await tag_invoke(body_to_tag<json::value>{}, resp);
134 if(ec)
135 co_return { ec, {} };
136 auto r = jv.try_as_object();
137 if(r.has_error())
138 co_return { r.error(), {} };
139 co_return { std::error_code(), std::move(*r) };
140 4x }
141
142 any_request_body
143 1x tag_invoke(body_from_tag<json::array>, json::array value)
144 {
145
1/1
✓ Branch 5 taken 1 time.
1x return json_body{ std::move(value) };
146 }
147
148 capy::io_task<json::array>
149
1/1
✓ Branch 1 taken 2 times.
2x tag_invoke(body_to_tag<json::array>, response& resp)
150 {
151 auto [ec, jv] = co_await tag_invoke(body_to_tag<json::value>{}, resp);
152 if(ec)
153 co_return { ec, {} };
154 auto r = jv.try_as_array();
155 if(r.has_error())
156 co_return { r.error(), {} };
157 co_return { std::error_code(), std::move(*r) };
158 4x }
159
160 any_request_body
161 1x tag_invoke(body_from_tag<json::string>, json::string value)
162 {
163
1/1
✓ Branch 5 taken 1 time.
1x return json_body{ std::move(value) };
164 }
165
166 capy::io_task<json::string>
167
1/1
✓ Branch 1 taken 2 times.
2x tag_invoke(body_to_tag<json::string>, response& resp)
168 {
169 auto [ec, jv] = co_await tag_invoke(body_to_tag<json::value>{}, resp);
170 if(ec)
171 co_return { ec, {} };
172 auto r = jv.try_as_string();
173 if(r.has_error())
174 co_return { r.error(), {} };
175 co_return { std::error_code(), std::move(*r) };
176 4x }
177
178 } // namespace burl
179 } // namespace boost
180