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