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