Line data Source code
1 : /***************************************************************************\
2 : * Name : deserialize library for json *
3 : * Description : all json deserialization 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 "../bits.h"
14 : #include "../concepts.h"
15 : #include "../to_from_chars.h"
16 : #include "../utf8.h"
17 : #include "base64.h"
18 : #include "field.hpp"
19 : #include <algorithm>
20 : #include <cctype>
21 : #include <cstddef>
22 : #include <cstdint>
23 : #include <cstring>
24 : #include <memory>
25 : #include <spb/io/buffer-io.hpp>
26 : #include <spb/io/io.hpp>
27 : #include <stdexcept>
28 : #include <string>
29 : #include <string_view>
30 : #include <type_traits>
31 : #include <variant>
32 :
33 : namespace spb::json::detail
34 : {
35 : using namespace std::literals;
36 :
37 : static const auto escape = '\\';
38 :
39 : /**
40 : * @brief helper for std::variant visit
41 : * https://en.cppreference.com/w/cpp/utility/variant/visit
42 : *
43 : */
44 : template <class... Ts> struct overloaded : Ts...
45 : {
46 : using Ts::operator()...;
47 : };
48 : // explicit deduction guide (not needed as of C++20)
49 : template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
50 :
51 : /**
52 : * @brief djb2_hash for strings
53 : * http://www.cse.yorku.ca/~oz/hash.html
54 : *
55 : * @param str
56 : * @return uint32_t
57 : */
58 3520 : static constexpr inline auto djb2_hash(std::string_view str) noexcept -> uint32_t
59 : {
60 3520 : uint32_t hash = 5381U;
61 :
62 33989 : for (auto c : str)
63 : {
64 30469 : hash = ((hash << 5U) + hash) + uint8_t(c); /* hash * 33 + c */
65 : }
66 :
67 3520 : return hash;
68 : }
69 :
70 : static constexpr inline auto fnv1a_hash(std::string_view str) noexcept -> uint64_t
71 : {
72 : uint64_t hash = 14695981039346656037ULL;
73 : const uint64_t prime = 1099511628211ULL;
74 :
75 : for (auto c : str)
76 : {
77 : hash *= prime;
78 : hash ^= c;
79 : }
80 :
81 : return hash;
82 : }
83 :
84 2 : template <spb::detail::proto_field_bytes T> void clear(T &container)
85 : {
86 : if constexpr (spb::detail::proto_field_bytes_resizable<T>)
87 : {
88 2 : container.clear();
89 : }
90 : else
91 : {
92 0 : std::fill(container.begin(), container.end(), typename T::value_type());
93 : }
94 2 : }
95 :
96 : struct istream_buffer
97 : {
98 : const uint8_t *p_start;
99 : const uint8_t *p_end;
100 :
101 : istream_buffer(const void *start, const void *end) noexcept
102 : : p_start((uint8_t *)start), p_end((uint8_t *)end)
103 : {
104 : assert(start <= end);
105 : }
106 3972 : istream_buffer(const void *start, size_t size) noexcept : p_start((uint8_t *)start), p_end(p_start + size)
107 : {
108 3972 : }
109 22082 : [[nodiscard]] size_t size() const noexcept
110 : {
111 22082 : return p_end - p_start;
112 : }
113 5358 : [[nodiscard]] bool empty() const noexcept
114 : {
115 5358 : return p_start >= p_end;
116 : }
117 7617 : void skip(size_t chars)
118 : {
119 7617 : assert(size() >= chars);
120 7617 : p_start += chars;
121 7617 : }
122 12698 : [[nodiscard]] bool consume(char c)
123 : {
124 12698 : if (current_char() != c)
125 4913 : return false;
126 :
127 7785 : ++p_start;
128 7785 : return true;
129 : }
130 :
131 8529 : [[nodiscard]] bool consume_and_skip_white_space(char c)
132 : {
133 8529 : if (!consume(c))
134 4895 : return false;
135 :
136 3634 : skip_white_spaces();
137 3634 : return true;
138 : }
139 :
140 840 : [[nodiscard]] bool consume_and_skip_white_space(std::string_view token)
141 : {
142 840 : assert(!token.empty());
143 :
144 840 : if (size() < token.size()) [[unlikely]]
145 97 : return false;
146 :
147 743 : if (memcmp(token.data(), p_start, token.size()) != 0)
148 670 : return false;
149 :
150 73 : if (size() == token.size()) [[unlikely]]
151 37 : return true;
152 :
153 36 : const auto char_behind_token = p_start[token.size()];
154 36 : if (!isalnum(char_behind_token) && char_behind_token != '_')
155 : {
156 30 : skip(token.size());
157 30 : return true;
158 : }
159 :
160 6 : if (isspace(char_behind_token))
161 : {
162 0 : skip(token.size());
163 0 : skip_white_spaces();
164 0 : return true;
165 : }
166 6 : return false;
167 : }
168 13923 : [[nodiscard]] int current_char() const
169 : {
170 13923 : return (p_start < p_end) ? *p_start : -1;
171 : }
172 4602 : void skip_white_spaces() noexcept
173 : {
174 5032 : while (!empty() && isspace(*p_start))
175 : {
176 430 : ++p_start;
177 : }
178 4602 : }
179 326 : void consume_current_char(bool skip_white_space)
180 : {
181 326 : if (empty()) [[unlikely]]
182 1 : throw std::runtime_error("unexpected end of stream");
183 :
184 325 : ++p_start;
185 325 : if (skip_white_space)
186 17 : skip_white_spaces();
187 325 : }
188 :
189 7584 : [[nodiscard]] auto view(size_t min_size, size_t max_size) -> std::string_view
190 : {
191 7584 : if (size() < min_size) [[unlikely]]
192 2581 : throw std::runtime_error("unexpected end of stream");
193 :
194 5003 : return {(char *)p_start, std::min(size(), max_size)};
195 : }
196 : };
197 :
198 : struct istream_reader
199 : {
200 : private:
201 : spb::io::buffered_reader reader;
202 : size_t m_consumed_size = 0;
203 :
204 4226 : void consume_bytes(size_t size)
205 : {
206 4226 : m_consumed_size += size;
207 4226 : reader.skip(size);
208 4226 : }
209 :
210 : public:
211 378 : istream_reader(spb::io::reader reader) : reader(reader)
212 : {
213 378 : }
214 :
215 378 : size_t consumed_size() const
216 : {
217 378 : return m_consumed_size;
218 : }
219 :
220 3184 : [[nodiscard]] auto current_char() -> char
221 : {
222 3184 : auto view = reader.view(1);
223 3184 : if (view.empty())
224 0 : throw std::runtime_error("unexpected end of stream");
225 :
226 6368 : return view[0];
227 : }
228 :
229 2865 : [[nodiscard]] auto consume(char c) -> bool
230 : {
231 2865 : if (current_char() != c)
232 923 : return false;
233 :
234 1942 : skip(1);
235 1942 : return true;
236 : }
237 :
238 2390 : [[nodiscard]] auto consume_and_skip_white_space(char c) -> bool
239 : {
240 2390 : if (!consume(c))
241 923 : return false;
242 :
243 1467 : skip_white_spaces();
244 1467 : return true;
245 : }
246 :
247 248 : [[nodiscard]] auto consume_and_skip_white_space(std::string_view token) -> bool
248 : {
249 248 : assert(!token.empty());
250 :
251 248 : const auto token_view = reader.view(token.size() + 1);
252 248 : if (!token_view.starts_with(token))
253 236 : return false;
254 :
255 12 : if (token_view.size() == token.size()) [[unlikely]]
256 0 : return true;
257 :
258 12 : const auto char_behind_token = token_view.back();
259 12 : if (!isalnum(char_behind_token) && char_behind_token != '_')
260 : {
261 12 : skip(token.size());
262 12 : return true;
263 : }
264 :
265 0 : if (isspace(char_behind_token))
266 : {
267 0 : skip(token.size());
268 0 : skip_white_spaces();
269 0 : return true;
270 : }
271 0 : return false;
272 : }
273 :
274 1829 : void skip_white_spaces()
275 : {
276 : for (;;)
277 : {
278 1829 : auto view = reader.view(1);
279 1829 : if (view.empty())
280 1829 : return;
281 :
282 1451 : size_t spaces = 0;
283 1451 : for (auto c : view)
284 : {
285 1451 : if (!isspace(c))
286 : {
287 1451 : consume_bytes(spaces);
288 1451 : return;
289 : }
290 0 : spaces += 1;
291 : }
292 0 : consume_bytes(spaces);
293 0 : }
294 : }
295 :
296 780 : [[nodiscard]] auto view(size_t min_size, size_t max_size) -> std::string_view
297 : {
298 780 : auto result = reader.view(max_size);
299 780 : if (result.size() < min_size) [[unlikely]]
300 0 : throw std::runtime_error("unexpected end of stream");
301 :
302 780 : if (result.size() > max_size)
303 357 : result = result.substr(0, max_size);
304 :
305 780 : return result;
306 : }
307 :
308 19 : void consume_current_char(bool skip_white_space) noexcept
309 : {
310 19 : consume_bytes(1);
311 19 : if (skip_white_space)
312 0 : skip_white_spaces();
313 19 : }
314 :
315 2756 : void skip(size_t size)
316 : {
317 2756 : consume_bytes(size);
318 2756 : }
319 : };
320 :
321 : [[nodiscard]] bool eof(const auto &stream)
322 : {
323 : return stream.current_char() == -1;
324 : }
325 :
326 70 : template <field_attributes> void deserialize(auto &stream, spb::detail::proto_enum auto &value)
327 : {
328 70 : deserialize_value(stream, value);
329 68 : }
330 :
331 26 : void ignore_string_until_double_quota(auto &stream)
332 : {
333 0 : for (;;)
334 : {
335 26 : auto view = stream.view(1, UINT32_MAX);
336 26 : auto pos = view.find_first_of(R"(\")");
337 26 : if (pos == view.npos)
338 : {
339 0 : stream.skip(view.size());
340 0 : continue;
341 : }
342 :
343 26 : if (view[pos] == '"') [[likely]]
344 : {
345 : // +1 for '""
346 26 : stream.skip(pos + 1);
347 26 : stream.skip_white_spaces();
348 26 : return;
349 : }
350 :
351 0 : stream.skip(pos + 1);
352 : // +1 for char behind '\'
353 0 : (void)stream.view(1, UINT32_MAX);
354 0 : stream.skip(1);
355 : }
356 : }
357 :
358 19 : void ignore_string(auto &stream)
359 : {
360 19 : if (!stream.consume('"')) [[unlikely]]
361 1 : throw std::runtime_error(R"(expecting '"')");
362 :
363 18 : if (stream.consume_and_skip_white_space('"')) [[unlikely]]
364 0 : return;
365 :
366 18 : ignore_string_until_double_quota(stream);
367 : }
368 :
369 1296 : auto deserialize_string_to_buffer(auto &stream, size_t min_size, size_t max_size, char *buffer)
370 : -> std::string_view
371 : {
372 1296 : assert(max_size < io::buffered_reader::BUFFER_SIZE);
373 :
374 1296 : if (!stream.consume('"')) [[unlikely]]
375 1 : throw std::runtime_error(R"(expecting '"')");
376 :
377 : // +1 for "
378 1295 : auto view = stream.view(1, max_size + 1);
379 1295 : size_t start = 0;
380 0 : for (;;)
381 : {
382 1295 : const auto pos = view.find_first_of(R"(\")", start);
383 1295 : if (pos == view.npos) [[unlikely]]
384 : {
385 8 : stream.skip(view.size());
386 8 : break;
387 : }
388 :
389 1287 : if (view[pos] == '"') [[likely]]
390 : {
391 1287 : memcpy(buffer, view.data(), pos);
392 : // +1 for '""
393 1287 : stream.skip(pos + 1);
394 1287 : stream.skip_white_spaces();
395 1287 : return (pos >= min_size) ? std::string_view{buffer, pos} : std::string_view{};
396 : }
397 :
398 : // +2 for \ and char behind
399 0 : start = pos + 2;
400 : }
401 8 : ignore_string_until_double_quota(stream);
402 8 : return {};
403 : }
404 :
405 26 : auto unicode_from_hex(auto &stream) -> uint16_t
406 : {
407 26 : const auto esc_size = 4U;
408 26 : auto unicode_view = stream.view(esc_size, esc_size);
409 23 : if (unicode_view.size() < esc_size) [[unlikely]]
410 0 : throw std::runtime_error("invalid escape sequence");
411 :
412 23 : auto value = uint16_t(0);
413 23 : auto result = spb_std_emu::from_chars(unicode_view.data(), unicode_view.data() + esc_size, value, 16);
414 23 : if (result.ec != std::errc{} || result.ptr != unicode_view.data() + esc_size) [[unlikely]]
415 2 : throw std::runtime_error("invalid escape sequence");
416 :
417 21 : stream.skip(esc_size);
418 21 : return value;
419 : }
420 :
421 19 : auto unescape_unicode(auto &stream, char utf8[4]) -> uint32_t
422 : {
423 19 : auto value = uint32_t(unicode_from_hex(stream));
424 16 : if (value >= 0xD800 && value <= 0xDBFF && stream.view(2, 2).starts_with("\\u"sv))
425 : {
426 7 : stream.skip(2);
427 7 : auto low = unicode_from_hex(stream);
428 :
429 5 : if (low < 0xDC00 || low > 0xDFFF) [[unlikely]]
430 2 : throw std::invalid_argument("invalid escape sequence");
431 :
432 3 : value = ((value - 0xD800) << 10) + (low - 0xDC00) + 0x10000;
433 : }
434 12 : if (auto result = spb::detail::utf8::encode_point(value, utf8); result != 0)
435 12 : return result;
436 :
437 0 : throw std::runtime_error("invalid escape sequence");
438 : }
439 :
440 328 : auto unescape(auto &stream, char utf8[4]) -> uint32_t
441 : {
442 328 : auto c = stream.current_char();
443 328 : stream.consume_current_char(false);
444 327 : switch (c)
445 : {
446 12 : case '"':
447 12 : utf8[0] = '"';
448 12 : return 1;
449 7 : case '\\':
450 7 : utf8[0] = '\\';
451 7 : return 1;
452 1 : case '/':
453 1 : utf8[0] = '/';
454 1 : return 1;
455 5 : case 'b':
456 5 : utf8[0] = '\b';
457 5 : return 1;
458 5 : case 'f':
459 5 : utf8[0] = '\f';
460 5 : return 1;
461 9 : case 'n':
462 9 : utf8[0] = '\n';
463 9 : return 1;
464 8 : case 'r':
465 8 : utf8[0] = '\r';
466 8 : return 1;
467 15 : case 't':
468 15 : utf8[0] = '\t';
469 15 : return 1;
470 19 : case 'u':
471 19 : return unescape_unicode(stream, utf8);
472 246 : default:
473 246 : throw std::runtime_error("invalid escape sequence");
474 : }
475 : }
476 :
477 : template <field_attributes attributes>
478 573 : void deserialize(auto &stream, spb::detail::proto_field_string auto &value)
479 : {
480 573 : if (!stream.consume('"')) [[unlikely]]
481 7 : throw std::runtime_error(R"(expecting '"')");
482 :
483 : if constexpr (spb::detail::proto_field_string_resizable<decltype(value)>)
484 : {
485 539 : value.clear();
486 : }
487 566 : auto index = size_t(0);
488 1241 : auto append_to_value = [&](const char *str, size_t size)
489 : {
490 : if constexpr (attributes.max_size)
491 40 : check_size(value.size() + size, attributes.max_size);
492 :
493 : if constexpr (spb::detail::proto_field_string_resizable<decltype(value)>)
494 : {
495 643 : value.append(str, size);
496 : }
497 : else
498 : {
499 126 : if (auto space_left = value.size() - index; size <= space_left) [[likely]]
500 : {
501 61 : memcpy(value.data() + index, str, size);
502 61 : index += size;
503 : }
504 : else
505 : {
506 2 : throw std::runtime_error("invalid string size");
507 : }
508 : }
509 : };
510 :
511 75 : for (;;)
512 : {
513 641 : auto view = stream.view(1, UINT32_MAX);
514 640 : auto found = view.find_first_of(R"("\)");
515 640 : if (found == view.npos) [[unlikely]]
516 : {
517 1 : append_to_value(view.data(), view.size());
518 1 : stream.skip(view.size());
519 1 : continue;
520 : }
521 :
522 639 : append_to_value(view.data(), found);
523 : // +1 for '"' or '\'
524 629 : stream.skip(found + 1);
525 629 : if (view[found] == '"') [[likely]]
526 : {
527 : if constexpr (!spb::detail::proto_field_string_resizable<decltype(value)>)
528 : {
529 25 : if (index != value.size()) [[unlikely]]
530 2 : throw std::runtime_error("invalid string size");
531 : }
532 299 : return;
533 : }
534 : char utf8_buffer[4];
535 328 : auto utf8_size = unescape(stream, utf8_buffer);
536 74 : append_to_value(utf8_buffer, utf8_size);
537 : }
538 : spb::detail::utf8::validate(std::string_view(value.data(), value.size()));
539 : }
540 :
541 1100 : template <field_attributes> void deserialize(auto &stream, spb::detail::proto_field_int_or_float auto &value)
542 : {
543 1100 : if (stream.current_char() == '"') [[unlikely]]
544 : {
545 : //- https://protobuf.dev/programming-guides/proto2/#json
546 : //- number can be a string
547 : char buffer[32];
548 36 : auto view = deserialize_string_to_buffer(stream, 1, 32, buffer);
549 36 : auto result = spb_std_emu::from_chars(view.data(), view.data() + view.size(), value);
550 36 : if (result.ec != std::errc{} || result.ptr != (view.data() + view.size())) [[unlikely]]
551 12 : throw std::runtime_error("invalid number");
552 :
553 24 : return;
554 : }
555 1064 : auto view = stream.view(1, 32);
556 1051 : auto result = spb_std_emu::from_chars(view.data(), view.data() + view.size(), value);
557 1051 : if (result.ec != std::errc{}) [[unlikely]]
558 29 : throw std::runtime_error("invalid number");
559 :
560 1022 : stream.skip(result.ptr - view.data());
561 : }
562 :
563 78 : template <field_attributes> void deserialize(auto &stream, bool &value)
564 : {
565 78 : if (stream.consume_and_skip_white_space("true"sv))
566 : {
567 34 : value = true;
568 : }
569 44 : else if (stream.consume_and_skip_white_space("false"sv))
570 : {
571 27 : value = false;
572 : }
573 17 : else [[unlikely]]
574 : {
575 17 : throw std::runtime_error("expecting 'true' or 'false'");
576 : }
577 61 : }
578 :
579 : template <field_attributes> void deserialize(auto &stream, spb::detail::proto_message auto &value);
580 : template <field_attributes> void deserialize(auto &stream, spb::detail::proto_map auto &value);
581 :
582 : template <field_attributes attributes, spb::detail::proto_label_optional Container>
583 : void deserialize(auto &stream, Container &p_value);
584 :
585 : template <field_attributes attributes, spb::detail::proto_label_repeated Container>
586 374 : void deserialize(auto &stream, Container &value)
587 : {
588 374 : if (stream.consume_and_skip_white_space("null"sv))
589 : {
590 5 : value.clear();
591 5 : return;
592 : }
593 :
594 369 : if (!stream.consume_and_skip_white_space('[')) [[unlikely]]
595 10 : throw std::runtime_error("expecting '['");
596 :
597 359 : if (stream.consume_and_skip_white_space(']'))
598 5 : return;
599 :
600 : do
601 : {
602 : if constexpr (attributes.max_count)
603 325 : check_size(value.size() + 1, attributes.max_count);
604 :
605 : if constexpr (std::is_same_v<typename Container::value_type, bool>)
606 : {
607 22 : auto b = false;
608 22 : deserialize<attributes>(stream, b);
609 20 : value.push_back(b);
610 : }
611 : else
612 : {
613 712 : deserialize<attributes>(stream, value.emplace_back());
614 : }
615 716 : } while (stream.consume_and_skip_white_space(','));
616 :
617 327 : if (!stream.consume_and_skip_white_space(']')) [[unlikely]]
618 2 : throw std::runtime_error("expecting ']'");
619 : }
620 :
621 : template <field_attributes attributes, spb::detail::proto_label_repeated_fixed_size Container>
622 14 : void deserialize(auto &stream, Container &value)
623 : {
624 14 : if (stream.consume_and_skip_white_space("null"sv))
625 : {
626 0 : typename Container::value_type tmp = {};
627 0 : for (size_t i = 0; i < value.size(); i++)
628 : {
629 0 : value[i] = tmp;
630 : }
631 0 : return;
632 : }
633 :
634 14 : if (!stream.consume_and_skip_white_space('[')) [[unlikely]]
635 0 : throw std::runtime_error("expecting '['");
636 :
637 112 : for (size_t i = 0; i < value.size(); i++)
638 : {
639 : typename Container::value_type tmp;
640 56 : deserialize<attributes>(stream, tmp);
641 52 : value[i] = tmp;
642 104 : if (i + 1 >= value.size())
643 10 : break;
644 :
645 80 : while (stream.consume_and_skip_white_space(','))
646 : ;
647 : }
648 :
649 10 : if (!stream.consume_and_skip_white_space(']')) [[unlikely]]
650 4 : throw std::runtime_error("expecting ']'");
651 : }
652 :
653 : template <field_attributes attributes>
654 183 : void deserialize(auto &stream, spb::detail::proto_field_bytes auto &value)
655 : {
656 183 : if (stream.consume_and_skip_white_space("null"sv))
657 : {
658 2 : clear(value);
659 2 : return;
660 : }
661 :
662 181 : base64_decode_string(value, stream, attributes.max_size);
663 : }
664 :
665 46 : template <field_attributes attributes, typename T> void deserialize_map_key(auto &stream, T &map_key)
666 : {
667 : if constexpr (std::is_same_v<T, std::string>)
668 : {
669 23 : deserialize<attributes>(stream, map_key);
670 : }
671 : else
672 : {
673 : char buffer[128];
674 23 : auto str_key_map = deserialize_string_to_buffer(stream, 1, 128, buffer);
675 23 : auto key_stream = istream_buffer(str_key_map.data(), str_key_map.size());
676 23 : deserialize<attributes>(key_stream, map_key);
677 : }
678 44 : }
679 :
680 52 : template <field_attributes attributes> void deserialize(auto &stream, spb::detail::proto_map auto &value)
681 : {
682 : using map_type = std::remove_cvref_t<decltype(value)>;
683 : using key_type = typename map_type::key_type;
684 : using mapped_type = typename map_type::mapped_type;
685 :
686 52 : if (stream.consume_and_skip_white_space("null"sv))
687 : {
688 4 : value.clear();
689 4 : return;
690 : }
691 :
692 48 : if (!stream.consume_and_skip_white_space('{')) [[unlikely]]
693 5 : throw std::runtime_error("expecting '{'");
694 :
695 43 : if (stream.consume_and_skip_white_space('}'))
696 4 : return;
697 :
698 : do
699 : {
700 46 : auto map_key = key_type();
701 46 : deserialize_map_key<attributes>(stream, map_key);
702 44 : if (!stream.consume_and_skip_white_space(':')) [[unlikely]]
703 1 : throw std::runtime_error("expecting ':'");
704 :
705 43 : auto map_value = mapped_type();
706 43 : deserialize<attributes>(stream, map_value);
707 38 : value.emplace(std::move(map_key), std::move(map_value));
708 45 : } while (stream.consume_and_skip_white_space(','));
709 :
710 31 : if (!stream.consume_and_skip_white_space('}')) [[unlikely]]
711 1 : throw std::runtime_error("expecting '}'");
712 : }
713 :
714 : template <field_attributes attributes, spb::detail::proto_label_optional Container>
715 328 : void deserialize(auto &stream, Container &p_value)
716 : {
717 328 : if (stream.consume_and_skip_white_space("null"sv))
718 : {
719 4 : p_value.reset();
720 4 : return;
721 : }
722 :
723 324 : if (p_value.has_value())
724 : {
725 4 : deserialize<attributes>(stream, *p_value);
726 : }
727 : else
728 : {
729 345 : deserialize<attributes>(stream, p_value.emplace(typename Container::value_type()));
730 : }
731 : }
732 :
733 13 : template <field_attributes attributes, typename T> void deserialize(auto &stream, std::unique_ptr<T> &value)
734 : {
735 13 : if (stream.consume_and_skip_white_space("null"sv))
736 : {
737 2 : value.reset();
738 2 : return;
739 : }
740 :
741 11 : if (value)
742 : {
743 5 : deserialize<attributes>(stream, *value);
744 : }
745 : else
746 : {
747 6 : value = std::make_unique<T>();
748 6 : deserialize<attributes>(stream, *value);
749 : }
750 : }
751 :
752 : void ignore_value(auto &stream);
753 10 : void ignore_key_and_value(auto &stream)
754 : {
755 10 : ignore_string(stream);
756 9 : if (!stream.consume_and_skip_white_space(':')) [[unlikely]]
757 1 : throw std::runtime_error("expecting ':'");
758 :
759 8 : ignore_value(stream);
760 7 : }
761 :
762 8 : void ignore_object(auto &stream)
763 : {
764 : //- '{' was already checked by caller
765 8 : stream.consume_current_char(true);
766 :
767 8 : if (stream.consume_and_skip_white_space('}'))
768 1 : return;
769 :
770 : do
771 : {
772 10 : ignore_key_and_value(stream);
773 7 : } while (stream.consume_and_skip_white_space(','));
774 :
775 4 : if (!stream.consume_and_skip_white_space('}'))
776 : {
777 1 : throw std::runtime_error("expecting '}'");
778 : }
779 : }
780 :
781 9 : void ignore_array(auto &stream)
782 : {
783 : //- '[' was already checked by caller
784 9 : stream.consume_current_char(true);
785 :
786 9 : if (stream.consume_and_skip_white_space(']'))
787 2 : return;
788 :
789 : do
790 : {
791 9 : ignore_value(stream);
792 6 : } while (stream.consume_and_skip_white_space(','));
793 :
794 4 : if (!stream.consume_and_skip_white_space(']')) [[unlikely]]
795 1 : throw std::runtime_error("expecting ']");
796 : }
797 :
798 13 : void ignore_number(auto &stream)
799 : {
800 : double value;
801 13 : deserialize<field_attributes{}>(stream, value);
802 9 : }
803 :
804 5 : void ignore_bool(auto &stream)
805 : {
806 : bool value;
807 5 : deserialize<field_attributes{}>(stream, value);
808 3 : }
809 :
810 2 : void ignore_null(auto &stream)
811 : {
812 2 : if (!stream.consume_and_skip_white_space("null"sv)) [[unlikely]]
813 1 : throw std::runtime_error("expecting 'null'");
814 1 : }
815 :
816 46 : void ignore_value(auto &stream)
817 : {
818 46 : switch (stream.current_char())
819 : {
820 8 : case '{':
821 8 : return ignore_object(stream);
822 9 : case '[':
823 9 : return ignore_array(stream);
824 9 : case '"':
825 9 : return ignore_string(stream);
826 2 : case 'n':
827 2 : return ignore_null(stream);
828 5 : case 't':
829 : case 'f':
830 5 : return ignore_bool(stream);
831 13 : default:
832 13 : return ignore_number(stream);
833 : }
834 : }
835 :
836 237 : template <field_attributes attributes, typename T> T deserialize_bitfield(auto &stream, uint32_t bits)
837 : {
838 237 : auto value = T();
839 237 : deserialize<attributes>(stream, value);
840 237 : spb::detail::check_if_value_fit_in_bits(value, bits);
841 236 : return value;
842 : }
843 :
844 : template <field_attributes attributes, size_t ordinal, typename T>
845 16 : void deserialize_variant(auto &stream, T &variant)
846 : {
847 16 : deserialize<attributes>(stream, variant.template emplace<ordinal>());
848 16 : }
849 :
850 1341 : template <field_attributes> void deserialize(auto &stream, spb::detail::proto_message auto &value)
851 : {
852 1341 : if (!stream.consume_and_skip_white_space('{')) [[unlikely]]
853 2 : throw std::runtime_error("expecting '{'");
854 :
855 1339 : if (stream.consume_and_skip_white_space('}'))
856 200 : return;
857 :
858 : for (;;)
859 : {
860 : //- generated by the sprotoc
861 1170 : deserialize_value(stream, value);
862 :
863 1105 : if (stream.consume_and_skip_white_space(','))
864 31 : continue;
865 :
866 1074 : if (stream.consume_and_skip_white_space('}'))
867 1073 : return;
868 :
869 1 : throw std::runtime_error("expecting '}' or ','");
870 : }
871 : }
872 :
873 1170 : auto deserialize_key(auto &stream, size_t min_size, size_t max_size, char *buffer) -> std::string_view
874 : {
875 1170 : auto key = deserialize_string_to_buffer(stream, min_size, max_size, buffer);
876 1169 : if (!stream.consume_and_skip_white_space(':')) [[unlikely]]
877 1 : throw std::runtime_error("expecting ':'");
878 :
879 1168 : return key;
880 : }
881 :
882 70 : auto deserialize_string_or_int(auto &stream, size_t min_size, size_t max_size, char *buffer)
883 : -> std::variant<std::string_view, int32_t>
884 : {
885 70 : if (stream.current_char() == '"')
886 67 : return deserialize_string_to_buffer(stream, min_size, max_size, buffer);
887 :
888 3 : return deserialize_int(stream);
889 : }
890 :
891 3 : auto deserialize_int(auto &stream) -> int32_t
892 : {
893 : int32_t result;
894 3 : deserialize<field_attributes{}>(stream, result);
895 2 : return result;
896 : }
897 :
898 29 : void skip_value(auto &stream)
899 : {
900 29 : ignore_value(stream);
901 18 : }
902 :
903 : } // namespace spb::json::detail
|