Line data Source code
1 : /***************************************************************************\
2 : * Name : serialize library for json *
3 : * Description : all json serialization functions *
4 : * Author : antonin.kriz@gmail.com *
5 : * ------------------------------------------------------------------------- *
6 : * This is free software; you can redistribute it and/or modify it under the *
7 : * terms of the MIT license. A copy of the license can be found in the file *
8 : * "LICENSE" at the root of this distribution. *
9 : \***************************************************************************/
10 :
11 : #pragma once
12 :
13 : #include "../concepts.h"
14 :
15 : #include "../to_from_chars.h"
16 : #include "base64.h"
17 : #include "field.hpp"
18 : #include "spb/utf8.h"
19 : #include <algorithm>
20 : #include <array>
21 : #include <charconv>
22 : #include <cinttypes>
23 : #include <cstddef>
24 : #include <cstdint>
25 : #include <cstring>
26 : #include <memory>
27 : #include <spb/io/io.hpp>
28 : #include <stdexcept>
29 : #include <string>
30 : #include <string_view>
31 : #include <sys/types.h>
32 : #include <type_traits>
33 :
34 : namespace spb::json::detail
35 : {
36 : struct ostream_size
37 : {
38 : static constexpr bool size_only = true;
39 : size_t size;
40 : bool put_comma = false;
41 :
42 4381749 : void write(uint8_t) noexcept
43 : {
44 4381749 : size += sizeof(uint8_t);
45 4381749 : }
46 :
47 3747 : void write(const void *, size_t data_size) noexcept
48 : {
49 3747 : size += data_size;
50 3747 : }
51 : };
52 :
53 : struct ostream_buffer
54 : {
55 : static constexpr bool size_only = false;
56 :
57 : uint8_t *p_buffer;
58 : bool put_comma = false;
59 :
60 3472 : explicit ostream_buffer(void *buffer) : p_buffer((std::uint8_t *)buffer)
61 : {
62 3472 : }
63 :
64 4379239 : void write(uint8_t byte) noexcept
65 : {
66 4379239 : *p_buffer++ = byte;
67 4379239 : }
68 :
69 2545 : void write(const void *data, size_t data_size) noexcept
70 : {
71 2545 : memcpy(p_buffer, data, data_size);
72 2545 : p_buffer += data_size;
73 2545 : }
74 : };
75 :
76 : struct ostream_writer
77 : {
78 : static constexpr bool size_only = false;
79 : spb::io::writer on_write;
80 : size_t size = 0;
81 : bool put_comma = false;
82 :
83 378 : explicit ostream_writer(spb::io::writer writer) : on_write(writer)
84 : {
85 378 : }
86 :
87 2013 : void write(uint8_t byte)
88 : {
89 2013 : write(&byte, 1);
90 2013 : }
91 :
92 3100 : void write(const void *data, size_t data_size)
93 : {
94 3100 : on_write(data, data_size);
95 3100 : size += data_size;
96 3100 : }
97 : };
98 :
99 : template <field_attributes = field_attributes{}> size_t serialize_size(const auto &value);
100 :
101 24 : void write_unicode(auto &stream, uint32_t codepoint)
102 : {
103 24 : if (codepoint <= 0xffff)
104 : {
105 18 : char buffer[8] = {};
106 18 : auto size = snprintf(buffer, sizeof(buffer), "\\u%04" PRIx32, codepoint);
107 18 : return stream.write(buffer, size);
108 : }
109 6 : if (codepoint <= 0x10FFFF)
110 : {
111 6 : codepoint -= 0x10000;
112 :
113 6 : auto high = static_cast<uint16_t>((codepoint >> 10) + 0xD800);
114 6 : auto low = static_cast<uint16_t>((codepoint & 0x3FF) + 0xDC00);
115 6 : char buffer[16] = {};
116 6 : auto size = snprintf(buffer, sizeof(buffer), "\\u%04" PRIx16 "\\u%04" PRIx16, high, low);
117 6 : return stream.write(buffer, size);
118 : }
119 0 : throw std::invalid_argument("invalid utf8");
120 : }
121 :
122 2543 : template <size_t N> void write_string(auto &stream, const char (&string)[N])
123 : {
124 2543 : stream.write(string, N - 1);
125 2543 : }
126 :
127 1910 : static constexpr auto is_escape(uint8_t c) -> bool
128 : {
129 1910 : switch (c)
130 : {
131 66 : case '\\':
132 : case '\"':
133 66 : return true;
134 1844 : default:
135 1844 : return (c < ' ') | (c >= 0x80);
136 : }
137 : }
138 :
139 603 : static constexpr auto has_escape_chars(std::string_view str) -> bool
140 : {
141 603 : return std::any_of(str.begin(), str.end(), is_escape);
142 : }
143 :
144 603 : void write_escaped(auto &stream, std::string_view str)
145 : {
146 603 : if (!has_escape_chars(str)) [[likely]]
147 : {
148 554 : stream.write(str.data(), str.size());
149 554 : return;
150 : }
151 :
152 49 : uint32_t codepoint = 0;
153 49 : uint32_t state = spb::detail::utf8::ok;
154 49 : bool decoding_utf8 = false;
155 329 : for (uint8_t c : str)
156 : {
157 280 : if (decoding_utf8)
158 : {
159 36 : if (spb::detail::utf8::decode_point(&state, &codepoint, c) == spb::detail::utf8::ok)
160 : {
161 18 : write_unicode(stream, codepoint);
162 18 : decoding_utf8 = false;
163 : }
164 36 : continue;
165 : }
166 244 : if (is_escape(c))
167 : {
168 147 : switch (c)
169 : {
170 24 : case '"':
171 24 : write_string(stream, R"(\")");
172 24 : break;
173 16 : case '\\':
174 16 : write_string(stream, R"(\\)");
175 16 : break;
176 10 : case '\b':
177 10 : write_string(stream, R"(\b)");
178 10 : break;
179 10 : case '\f':
180 10 : write_string(stream, R"(\f)");
181 10 : break;
182 16 : case '\n':
183 16 : write_string(stream, R"(\n)");
184 16 : break;
185 16 : case '\r':
186 16 : write_string(stream, R"(\r)");
187 16 : break;
188 30 : case '\t':
189 30 : write_string(stream, R"(\t)");
190 30 : break;
191 25 : default:
192 25 : decoding_utf8 = true;
193 25 : if (spb::detail::utf8::decode_point(&state, &codepoint, c) == spb::detail::utf8::ok)
194 : {
195 6 : write_unicode(stream, codepoint);
196 6 : decoding_utf8 = false;
197 : }
198 : }
199 : }
200 : else
201 : {
202 97 : stream.write(c);
203 : }
204 : }
205 49 : if (state != spb::detail::utf8::ok) [[unlikely]]
206 : {
207 1 : throw std::runtime_error("invalid utf8");
208 : }
209 : }
210 :
211 3800 : void put_comma_if_needed(auto &stream)
212 : {
213 3800 : if (stream.put_comma)
214 870 : stream.write(',');
215 :
216 3800 : stream.put_comma = true;
217 3800 : }
218 :
219 2295 : void serialize_key(auto &stream, std::string_view key)
220 : {
221 2295 : put_comma_if_needed(stream);
222 :
223 2295 : stream.write('"');
224 2295 : stream.write(key.data(), key.size());
225 2295 : write_string(stream, R"(":)");
226 2295 : }
227 :
228 : template <field_attributes> void serialize(auto &stream, const bool &value);
229 : template <field_attributes> void serialize(auto &stream, const bool &value, std::string_view field);
230 :
231 : template <field_attributes>
232 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value);
233 : template <field_attributes>
234 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value, std::string_view field);
235 :
236 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_message auto &value);
237 : template <field_attributes>
238 : void serialize(auto &stream, const spb::detail::proto_message auto &value, std::string_view field);
239 :
240 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_enum auto &value);
241 : template <field_attributes>
242 : void serialize(auto &stream, const spb::detail::proto_enum auto &value, std::string_view field);
243 :
244 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_field_string auto &value);
245 : template <field_attributes>
246 : void serialize(auto &stream, const spb::detail::proto_field_string auto &value, std::string_view field);
247 :
248 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value);
249 : template <field_attributes>
250 : void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value, std::string_view field);
251 :
252 : template <field_attributes attributes>
253 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value);
254 : template <field_attributes attributes>
255 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value, std::string_view field);
256 :
257 : template <field_attributes attributes, typename T>
258 : void serialize(auto &stream, const std::unique_ptr<T> &p_value);
259 : template <field_attributes attributes, typename T>
260 : void serialize(auto &stream, const std::unique_ptr<T> &p_value, std::string_view field);
261 :
262 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value);
263 : template <field_attributes>
264 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value, std::string_view field);
265 :
266 : template <field_attributes>
267 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value);
268 : template <field_attributes>
269 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value,
270 : std::string_view field);
271 :
272 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_map auto &map);
273 : template <field_attributes>
274 : void serialize(auto &stream, const spb::detail::proto_map auto &map, std::string_view field);
275 :
276 88 : template <field_attributes> void serialize(auto &stream, const bool &value)
277 : {
278 88 : return value ? write_string(stream, "true") : write_string(stream, "false");
279 : }
280 :
281 124 : void serialize_enum(auto &stream, std::string_view value)
282 : {
283 124 : stream.write('"');
284 124 : stream.write(value.data(), value.size());
285 124 : stream.write('"');
286 124 : }
287 :
288 611 : template <field_attributes attributes> void serialize(auto &stream, const std::string_view &value)
289 : {
290 : using stream_type = std::remove_cvref_t<decltype(stream)>;
291 :
292 : if constexpr (!stream_type::size_only && attributes.max_size)
293 40 : check_size(value.size(), attributes.max_size);
294 :
295 603 : stream.write('"');
296 603 : write_escaped(stream, value);
297 602 : stream.write('"');
298 602 : }
299 :
300 : template <field_attributes attributes>
301 611 : void serialize(auto &stream, const spb::detail::proto_field_string auto &value)
302 : {
303 611 : serialize<attributes>(stream, std::string_view(value.data(), value.size()));
304 602 : }
305 :
306 : template <field_attributes>
307 1839 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value)
308 : {
309 1839 : auto buffer = std::array<char, 32>();
310 5517 : auto result = spb_std_emu::to_chars(buffer.data(), buffer.data() + sizeof(buffer), value);
311 5517 : stream.write(buffer.data(), static_cast<size_t>(result.ptr - buffer.data()));
312 1839 : }
313 :
314 36 : template <field_attributes attributes> void serialize(auto &stream, const bool &value, std::string_view field)
315 : {
316 36 : serialize_key(stream, field);
317 36 : serialize<attributes>(stream, value);
318 36 : }
319 :
320 : template <field_attributes attributes>
321 946 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value, std::string_view field)
322 : {
323 946 : serialize_key(stream, field);
324 946 : serialize<attributes>(stream, value);
325 946 : }
326 :
327 : template <field_attributes attributes>
328 363 : void serialize(auto &stream, const spb::detail::proto_field_string auto &value, std::string_view field)
329 : {
330 363 : if (value.empty())
331 6 : return;
332 :
333 357 : serialize_key(stream, field);
334 357 : serialize<attributes>(stream, value);
335 : }
336 :
337 : template <field_attributes attributes>
338 388 : void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value)
339 : {
340 : using stream_type = std::remove_cvref_t<decltype(stream)>;
341 :
342 : if constexpr (!stream_type::size_only && attributes.max_size)
343 40 : check_size(value.size(), attributes.max_size);
344 :
345 380 : stream.write('"');
346 380 : base64_encode(stream, value);
347 380 : stream.write('"');
348 380 : }
349 :
350 : template <field_attributes attributes>
351 152 : void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value, std::string_view field)
352 : {
353 152 : if (value.empty())
354 6 : return;
355 :
356 146 : serialize_key(stream, field);
357 146 : serialize<attributes>(stream, value);
358 : }
359 :
360 : template <field_attributes attributes>
361 980 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value, std::string_view field)
362 : {
363 980 : if (value.empty())
364 312 : return;
365 :
366 668 : serialize_key(stream, field);
367 668 : serialize<attributes>(stream, value);
368 : }
369 :
370 : template <field_attributes attributes>
371 694 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value)
372 : {
373 : using stream_type = std::remove_cvref_t<decltype(stream)>;
374 :
375 : if constexpr (!stream_type::size_only && attributes.max_count)
376 85 : check_size(value.size(), attributes.max_count);
377 :
378 677 : stream.write('[');
379 677 : stream.put_comma = false;
380 2134 : for (const auto &v : value)
381 : {
382 1457 : put_comma_if_needed(stream);
383 :
384 : if constexpr (std::is_same_v<typename std::decay_t<decltype(value)>::value_type, bool>)
385 : {
386 40 : serialize<attributes>(stream, bool(v));
387 : }
388 : else
389 : {
390 1417 : serialize<attributes>(stream, v);
391 : }
392 : }
393 677 : stream.write(']');
394 677 : stream.put_comma = true;
395 677 : }
396 :
397 : template <field_attributes attributes>
398 12 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value)
399 : {
400 12 : stream.write('[');
401 12 : stream.put_comma = false;
402 120 : for (size_t i = 0; i < value.size(); i++)
403 : {
404 48 : put_comma_if_needed(stream);
405 :
406 : if constexpr (std::is_same_v<typename std::decay_t<decltype(value)>::value_type, bool>)
407 : {
408 : serialize<attributes>(stream, bool(value[i]));
409 : }
410 : else
411 : {
412 48 : serialize<attributes>(stream, value[i]);
413 : }
414 : }
415 12 : stream.write(']');
416 12 : stream.put_comma = true;
417 12 : }
418 :
419 : template <field_attributes attributes>
420 12 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value,
421 : std::string_view field)
422 : {
423 12 : serialize_key(stream, field);
424 12 : serialize<attributes>(stream, value);
425 12 : }
426 :
427 : template <field_attributes attributes>
428 48 : void serialize(auto &stream, const spb::detail::proto_map auto &map, std::string_view field)
429 : {
430 48 : if (map.empty())
431 0 : return;
432 :
433 48 : serialize_key(stream, field);
434 48 : serialize<attributes>(stream, map);
435 : }
436 :
437 68 : template <field_attributes attributes> void serialize(auto &stream, const spb::detail::proto_map auto &map)
438 : {
439 : using map_type = std::remove_cvref_t<decltype(map)>;
440 : using key_type = typename map_type::key_type;
441 :
442 68 : stream.write('{');
443 68 : stream.put_comma = false;
444 142 : for (const auto &[map_key, map_value] : map)
445 : {
446 : if constexpr (std::is_same_v<key_type, std::string_view> || std::is_same_v<key_type, std::string>)
447 : {
448 36 : serialize_key(stream, map_key);
449 : }
450 : else
451 : {
452 38 : if (stream.put_comma)
453 8 : stream.write(',');
454 :
455 38 : stream.write('"');
456 38 : serialize<attributes>(stream, map_key);
457 38 : write_string(stream, R"(":)");
458 : }
459 74 : stream.put_comma = false;
460 74 : serialize<attributes>(stream, map_value);
461 74 : stream.put_comma = true;
462 : }
463 68 : stream.write('}');
464 68 : stream.put_comma = true;
465 68 : }
466 :
467 : template <field_attributes attributes>
468 34 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value)
469 : {
470 34 : if (p_value.has_value())
471 22 : return serialize<attributes>(stream, *p_value);
472 : }
473 :
474 : template <field_attributes attributes>
475 712 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value, std::string_view field)
476 : {
477 712 : if (p_value.has_value())
478 606 : return serialize<attributes>(stream, *p_value, field);
479 : }
480 :
481 : template <field_attributes attributes, typename T>
482 : void serialize(auto &stream, const std::unique_ptr<T> &p_value)
483 : {
484 : if (p_value)
485 : return serialize<attributes>(stream, *p_value);
486 : }
487 :
488 : template <field_attributes attributes, typename T>
489 : void serialize(auto &stream, const std::unique_ptr<T> &p_value, std::string_view field)
490 : {
491 : if (p_value)
492 : return serialize<attributes>(stream, *p_value, field);
493 : }
494 :
495 2620 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_message auto &value)
496 : {
497 2620 : stream.write('{');
498 2620 : stream.put_comma = false;
499 2620 : serialize_value(stream, value);
500 2586 : stream.write('}');
501 2586 : stream.put_comma = true;
502 2586 : }
503 :
504 : template <field_attributes attributes>
505 14 : void serialize(auto &stream, const spb::detail::proto_message auto &value, std::string_view field)
506 : {
507 14 : serialize_key(stream, field);
508 14 : serialize<attributes>(stream, value);
509 14 : }
510 :
511 92 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_enum auto &value)
512 : {
513 92 : serialize_value(stream, value);
514 92 : }
515 :
516 : template <field_attributes>
517 32 : void serialize(auto &stream, const spb::detail::proto_enum auto &value, std::string_view field)
518 : {
519 32 : serialize_key(stream, field);
520 32 : serialize_value(stream, value);
521 32 : }
522 :
523 1291 : template <field_attributes attributes> size_t serialize_size(const auto &value)
524 : {
525 1291 : auto stream = ostream_size();
526 1291 : serialize<attributes>(stream, value);
527 1290 : return stream.size;
528 : }
529 :
530 : } // namespace spb::json::detail
|