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 4381872 : void write(uint8_t) noexcept
43 : {
44 4381872 : size += sizeof(uint8_t);
45 4381872 : }
46 :
47 3786 : void write(const void *, size_t data_size) noexcept
48 : {
49 3786 : size += data_size;
50 3786 : }
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 3488 : explicit ostream_buffer(void *buffer) : p_buffer((std::uint8_t *)buffer)
61 : {
62 3488 : }
63 :
64 4379321 : void write(uint8_t byte) noexcept
65 : {
66 4379321 : *p_buffer++ = byte;
67 4379321 : }
68 :
69 2571 : void write(const void *data, size_t data_size) noexcept
70 : {
71 2571 : memcpy(p_buffer, data, data_size);
72 2571 : p_buffer += data_size;
73 2571 : }
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 386 : explicit ostream_writer(spb::io::writer writer) : on_write(writer)
84 : {
85 386 : }
86 :
87 2054 : void write(uint8_t byte)
88 : {
89 2054 : write(&byte, 1);
90 2054 : }
91 :
92 3154 : void write(const void *data, size_t data_size)
93 : {
94 3154 : on_write(data, data_size);
95 3154 : size += data_size;
96 3154 : }
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 2579 : template <size_t N> void write_string(auto &stream, const char (&string)[N])
123 : {
124 2579 : stream.write(string, N - 1);
125 2579 : }
126 :
127 1910 : static constexpr auto is_escape(uint8_t c) -> bool
128 : {
129 1910 : switch (c)
130 : {
131 66 : case '\\':
132 : case '\"':
133 : case '<':
134 : case '>':
135 66 : return true;
136 1844 : default:
137 1844 : return (c < ' ') | (c >= 0x7f);
138 : }
139 : }
140 :
141 609 : static constexpr auto has_escape_chars(std::string_view str) -> bool
142 : {
143 609 : return std::any_of(str.begin(), str.end(), is_escape);
144 : }
145 :
146 609 : void write_escaped(auto &stream, std::string_view str)
147 : {
148 609 : if (!has_escape_chars(str)) [[likely]]
149 : {
150 560 : stream.write(str.data(), str.size());
151 560 : return;
152 : }
153 :
154 49 : uint32_t codepoint = 0;
155 49 : uint32_t state = spb::detail::utf8::ok;
156 49 : bool decoding_utf8 = false;
157 329 : for (uint8_t c : str)
158 : {
159 280 : if (decoding_utf8)
160 : {
161 36 : if (spb::detail::utf8::decode_point(&state, &codepoint, c) == spb::detail::utf8::ok)
162 : {
163 18 : write_unicode(stream, codepoint);
164 18 : decoding_utf8 = false;
165 : }
166 36 : continue;
167 : }
168 244 : if (is_escape(c))
169 : {
170 147 : switch (c)
171 : {
172 24 : case '"':
173 24 : write_string(stream, R"(\")");
174 24 : break;
175 16 : case '\\':
176 16 : write_string(stream, R"(\\)");
177 16 : break;
178 10 : case '\b':
179 10 : write_string(stream, R"(\b)");
180 10 : break;
181 10 : case '\f':
182 10 : write_string(stream, R"(\f)");
183 10 : break;
184 16 : case '\n':
185 16 : write_string(stream, R"(\n)");
186 16 : break;
187 16 : case '\r':
188 16 : write_string(stream, R"(\r)");
189 16 : break;
190 30 : case '\t':
191 30 : write_string(stream, R"(\t)");
192 30 : break;
193 25 : default:
194 25 : decoding_utf8 = true;
195 25 : if (spb::detail::utf8::decode_point(&state, &codepoint, c) == spb::detail::utf8::ok)
196 : {
197 6 : write_unicode(stream, codepoint);
198 6 : decoding_utf8 = false;
199 : }
200 : }
201 : }
202 : else
203 : {
204 97 : stream.write(c);
205 : }
206 : }
207 49 : if (state != spb::detail::utf8::ok) [[unlikely]]
208 : {
209 1 : throw std::runtime_error("invalid utf8");
210 : }
211 : }
212 :
213 3854 : void put_comma_if_needed(auto &stream)
214 : {
215 3854 : if (stream.put_comma)
216 876 : stream.write(',');
217 :
218 3854 : stream.put_comma = true;
219 3854 : }
220 :
221 2331 : void serialize_key(auto &stream, std::string_view key)
222 : {
223 2331 : put_comma_if_needed(stream);
224 :
225 2331 : stream.write('"');
226 2331 : stream.write(key.data(), key.size());
227 2331 : write_string(stream, R"(":)");
228 2331 : }
229 :
230 : template <field_attributes> void serialize(auto &stream, const bool &value);
231 : template <field_attributes> void serialize(auto &stream, const bool &value, std::string_view field);
232 :
233 : template <field_attributes>
234 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value);
235 : template <field_attributes>
236 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value, std::string_view field);
237 :
238 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_message auto &value);
239 : template <field_attributes>
240 : void serialize(auto &stream, const spb::detail::proto_message auto &value, std::string_view field);
241 :
242 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_enum auto &value);
243 : template <field_attributes>
244 : void serialize(auto &stream, const spb::detail::proto_enum auto &value, std::string_view field);
245 :
246 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_field_string auto &value);
247 : template <field_attributes>
248 : void serialize(auto &stream, const spb::detail::proto_field_string auto &value, std::string_view field);
249 :
250 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value);
251 : template <field_attributes>
252 : void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value, std::string_view field);
253 :
254 : template <field_attributes attributes>
255 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value);
256 : template <field_attributes attributes>
257 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value, std::string_view field);
258 :
259 : template <field_attributes attributes, typename T>
260 : void serialize(auto &stream, const std::unique_ptr<T> &p_value);
261 : template <field_attributes attributes, typename T>
262 : void serialize(auto &stream, const std::unique_ptr<T> &p_value, std::string_view field);
263 :
264 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value);
265 : template <field_attributes>
266 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value, std::string_view field);
267 :
268 : template <field_attributes>
269 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value);
270 : template <field_attributes>
271 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value,
272 : std::string_view field);
273 :
274 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_map auto &map);
275 : template <field_attributes>
276 : void serialize(auto &stream, const spb::detail::proto_map auto &map, std::string_view field);
277 :
278 88 : template <field_attributes> void serialize(auto &stream, const bool &value)
279 : {
280 88 : return value ? write_string(stream, "true") : write_string(stream, "false");
281 : }
282 :
283 124 : void serialize_enum(auto &stream, std::string_view value)
284 : {
285 124 : stream.write('"');
286 124 : stream.write(value.data(), value.size());
287 124 : stream.write('"');
288 124 : }
289 :
290 617 : template <field_attributes attributes> void serialize(auto &stream, const std::string_view &value)
291 : {
292 : using stream_type = std::remove_cvref_t<decltype(stream)>;
293 :
294 : if constexpr (!stream_type::size_only && attributes.max_size)
295 40 : check_size(value.size(), attributes.max_size);
296 :
297 609 : stream.write('"');
298 609 : write_escaped(stream, value);
299 608 : stream.write('"');
300 608 : }
301 :
302 : template <field_attributes attributes>
303 617 : void serialize(auto &stream, const spb::detail::proto_field_string auto &value)
304 : {
305 617 : serialize<attributes>(stream, std::string_view(value.data(), value.size()));
306 608 : }
307 :
308 : template <field_attributes>
309 1839 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value)
310 : {
311 1839 : auto buffer = std::array<char, 32>();
312 5517 : auto result = spb_std_emu::to_chars(buffer.data(), buffer.data() + sizeof(buffer), value);
313 5517 : stream.write(buffer.data(), static_cast<size_t>(result.ptr - buffer.data()));
314 1839 : }
315 :
316 36 : template <field_attributes attributes> void serialize(auto &stream, const bool &value, std::string_view field)
317 : {
318 36 : serialize_key(stream, field);
319 36 : serialize<attributes>(stream, value);
320 36 : }
321 :
322 : template <field_attributes attributes>
323 946 : void serialize(auto &stream, const spb::detail::proto_field_int_or_float auto &value, std::string_view field)
324 : {
325 946 : serialize_key(stream, field);
326 946 : serialize<attributes>(stream, value);
327 946 : }
328 :
329 : template <field_attributes attributes>
330 363 : void serialize(auto &stream, const spb::detail::proto_field_string auto &value, std::string_view field)
331 : {
332 363 : if (value.empty())
333 6 : return;
334 :
335 357 : serialize_key(stream, field);
336 357 : serialize<attributes>(stream, value);
337 : }
338 :
339 : template <field_attributes attributes>
340 388 : void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value)
341 : {
342 : using stream_type = std::remove_cvref_t<decltype(stream)>;
343 :
344 : if constexpr (!stream_type::size_only && attributes.max_size)
345 40 : check_size(value.size(), attributes.max_size);
346 :
347 380 : stream.write('"');
348 380 : base64_encode(stream, value);
349 380 : stream.write('"');
350 380 : }
351 :
352 : template <field_attributes attributes>
353 152 : void serialize(auto &stream, const spb::detail::proto_field_bytes auto &value, std::string_view field)
354 : {
355 152 : if (value.empty())
356 6 : return;
357 :
358 146 : serialize_key(stream, field);
359 146 : serialize<attributes>(stream, value);
360 : }
361 :
362 : template <field_attributes attributes>
363 998 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value, std::string_view field)
364 : {
365 998 : if (value.empty())
366 318 : return;
367 :
368 680 : serialize_key(stream, field);
369 680 : serialize<attributes>(stream, value);
370 : }
371 :
372 : template <field_attributes attributes>
373 706 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &value)
374 : {
375 : using stream_type = std::remove_cvref_t<decltype(stream)>;
376 :
377 : if constexpr (!stream_type::size_only && attributes.max_count)
378 85 : check_size(value.size(), attributes.max_count);
379 :
380 689 : stream.write('[');
381 689 : stream.put_comma = false;
382 2164 : for (const auto &v : value)
383 : {
384 1475 : put_comma_if_needed(stream);
385 :
386 : if constexpr (std::is_same_v<typename std::decay_t<decltype(value)>::value_type, bool>)
387 : {
388 40 : serialize<attributes>(stream, bool(v));
389 : }
390 : else
391 : {
392 1435 : serialize<attributes>(stream, v);
393 : }
394 : }
395 689 : stream.write(']');
396 689 : stream.put_comma = true;
397 689 : }
398 :
399 : template <field_attributes attributes>
400 12 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value)
401 : {
402 12 : stream.write('[');
403 12 : stream.put_comma = false;
404 120 : for (size_t i = 0; i < value.size(); i++)
405 : {
406 48 : put_comma_if_needed(stream);
407 :
408 : if constexpr (std::is_same_v<typename std::decay_t<decltype(value)>::value_type, bool>)
409 : {
410 : serialize<attributes>(stream, bool(value[i]));
411 : }
412 : else
413 : {
414 48 : serialize<attributes>(stream, value[i]);
415 : }
416 : }
417 12 : stream.write(']');
418 12 : stream.put_comma = true;
419 12 : }
420 :
421 : template <field_attributes attributes>
422 12 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &value,
423 : std::string_view field)
424 : {
425 12 : serialize_key(stream, field);
426 12 : serialize<attributes>(stream, value);
427 12 : }
428 :
429 : template <field_attributes attributes>
430 54 : void serialize(auto &stream, const spb::detail::proto_map auto &map, std::string_view field)
431 : {
432 54 : if (map.empty())
433 0 : return;
434 :
435 54 : serialize_key(stream, field);
436 54 : serialize<attributes>(stream, map);
437 : }
438 :
439 74 : template <field_attributes attributes> void serialize(auto &stream, const spb::detail::proto_map auto &map)
440 : {
441 : using map_type = std::remove_cvref_t<decltype(map)>;
442 : using key_type = typename map_type::key_type;
443 :
444 74 : stream.write('{');
445 74 : stream.put_comma = false;
446 154 : for (const auto &[map_key, map_value] : map)
447 : {
448 : if constexpr (std::is_same_v<key_type, std::string_view> || std::is_same_v<key_type, std::string>)
449 : {
450 42 : serialize_key(stream, map_key);
451 : }
452 : else
453 : {
454 38 : if (stream.put_comma)
455 8 : stream.write(',');
456 :
457 38 : stream.write('"');
458 38 : serialize<attributes>(stream, map_key);
459 38 : write_string(stream, R"(":)");
460 : }
461 80 : stream.put_comma = false;
462 80 : serialize<attributes>(stream, map_value);
463 80 : stream.put_comma = true;
464 : }
465 74 : stream.write('}');
466 74 : stream.put_comma = true;
467 74 : }
468 :
469 : template <field_attributes attributes>
470 34 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value)
471 : {
472 34 : if (p_value.has_value())
473 22 : return serialize<attributes>(stream, *p_value);
474 : }
475 :
476 : template <field_attributes attributes>
477 724 : void serialize(auto &stream, const spb::detail::proto_label_optional auto &p_value, std::string_view field)
478 : {
479 724 : if (p_value.has_value())
480 612 : return serialize<attributes>(stream, *p_value, field);
481 : }
482 :
483 : template <field_attributes attributes, typename T>
484 : void serialize(auto &stream, const std::unique_ptr<T> &p_value)
485 : {
486 : if (p_value)
487 : return serialize<attributes>(stream, *p_value);
488 : }
489 :
490 : template <field_attributes attributes, typename T>
491 : void serialize(auto &stream, const std::unique_ptr<T> &p_value, std::string_view field)
492 : {
493 : if (p_value)
494 : return serialize<attributes>(stream, *p_value, field);
495 : }
496 :
497 2698 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_message auto &value)
498 : {
499 2698 : stream.write('{');
500 2698 : stream.put_comma = false;
501 2698 : serialize_value(stream, value);
502 2664 : stream.write('}');
503 2664 : stream.put_comma = true;
504 2664 : }
505 :
506 : template <field_attributes attributes>
507 26 : void serialize(auto &stream, const spb::detail::proto_message auto &value, std::string_view field)
508 : {
509 26 : serialize_key(stream, field);
510 26 : serialize<attributes>(stream, value);
511 26 : }
512 :
513 92 : template <field_attributes> void serialize(auto &stream, const spb::detail::proto_enum auto &value)
514 : {
515 92 : serialize_value(stream, value);
516 92 : }
517 :
518 : template <field_attributes>
519 32 : void serialize(auto &stream, const spb::detail::proto_enum auto &value, std::string_view field)
520 : {
521 32 : serialize_key(stream, field);
522 32 : serialize_value(stream, value);
523 32 : }
524 :
525 1315 : template <field_attributes attributes> size_t serialize_size(const auto &value)
526 : {
527 1315 : auto stream = ostream_size();
528 1315 : serialize<attributes>(stream, value);
529 1314 : return stream.size;
530 : }
531 :
532 : } // namespace spb::json::detail
|