src/json.cpp

68.0% Lines (17/25) 66.7% List of functions (8/12) 55.6% Branches (5/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 // TODO: determine the length for small JSON values that fit in place.
50 // The serialized size is not known without serializing.
51 5x return std::nullopt;
52 }
53
54 capy::io_task<>
55
1/1
✓ Branch 1 taken 30 times.
30x write(capy::any_buffer_sink& sink) const
56 {
57 json::serializer sr;
58 sr.reset(&value_);
59
60 while(!sr.done())
61 {
62 capy::mutable_buffer arr[2];
63 auto dst = sink.prepare(arr);
64
65 std::size_t n = 0;
66 for(capy::mutable_buffer b : dst)
67 {
68 if(sr.done())
69 break;
70 n += sr.read(static_cast<char*>(b.data()), b.size()).size();
71 }
72
73 if(auto [ec] = co_await sink.commit(n); ec)
74 co_return { ec };
75 }
76
77 co_return {};
78 60x }
79 };
80
81 } // namespace
82
83 any_request_body
84 2x tag_invoke(body_from_tag<json::value>, json::value value)
85 {
86
1/1
✓ Branch 4 taken 2 times.
2x return json_body{ std::move(value) };
87 }
88
89 capy::io_task<json::value>
90 tag_invoke(body_to_tag<json::value>, response& resp)
91 {
92 auto source = resp.as_buffer_source();
93 json::stream_parser parser;
94
95 for(;;)
96 {
97 capy::const_buffer arr[2];
98 auto [ec, bufs] = co_await source.pull(arr);
99 if(ec)
100 {
101 if(ec == capy::error::eof)
102 {
103 parser.finish(ec);
104 if(ec)
105 co_return { ec, {} };
106 co_return { {}, parser.release() };
107 }
108 co_return { ec, {} };
109 }
110 std::size_t n = 0;
111 for(const auto& buf : bufs)
112 {
113 n += parser.write_some(
114 { static_cast<const char*>(buf.data()), buf.size() }, ec);
115 if(ec)
116 co_return { ec, {} };
117 }
118 source.consume(n);
119 }
120 }
121
122 any_request_body
123 1x tag_invoke(body_from_tag<json::object>, json::object value)
124 {
125
1/1
✓ Branch 5 taken 1 time.
1x return json_body{ std::move(value) };
126 }
127
128 capy::io_task<json::object>
129 tag_invoke(body_to_tag<json::object>, response& resp)
130 {
131 auto [ec, jv] = co_await tag_invoke(body_to_tag<json::value>{}, resp);
132 if(ec)
133 co_return { ec, {} };
134 auto r = jv.try_as_object();
135 if(r.has_error())
136 co_return { r.error(), {} };
137 co_return { {}, std::move(*r) };
138 }
139
140 any_request_body
141 1x tag_invoke(body_from_tag<json::array>, json::array value)
142 {
143
1/1
✓ Branch 5 taken 1 time.
1x return json_body{ std::move(value) };
144 }
145
146 capy::io_task<json::array>
147 tag_invoke(body_to_tag<json::array>, response& resp)
148 {
149 auto [ec, jv] = co_await tag_invoke(body_to_tag<json::value>{}, resp);
150 if(ec)
151 co_return { ec, {} };
152 auto r = jv.try_as_array();
153 if(r.has_error())
154 co_return { r.error(), {} };
155 co_return { {}, std::move(*r) };
156 }
157
158 any_request_body
159 1x tag_invoke(body_from_tag<json::string>, json::string value)
160 {
161
1/1
✓ Branch 5 taken 1 time.
1x return json_body{ std::move(value) };
162 }
163
164 capy::io_task<json::string>
165 tag_invoke(body_to_tag<json::string>, response& resp)
166 {
167 auto [ec, jv] = co_await tag_invoke(body_to_tag<json::value>{}, resp);
168 if(ec)
169 co_return { ec, {} };
170 auto r = jv.try_as_string();
171 if(r.has_error())
172 co_return { r.error(), {} };
173 co_return { {}, std::move(*r) };
174 }
175
176 } // namespace burl
177 } // namespace boost
178