Line data Source code
1 : /***************************************************************************\
2 : * Name : deserialize library for protobuf *
3 : * Description : all protobuf 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 "../utf8.h"
16 : #include "wire-types.h"
17 : #include <climits>
18 : #include <cstddef>
19 : #include <cstdint>
20 : #include <cstring>
21 : #include <limits>
22 : #include <map>
23 : #include <memory>
24 : #include <spb/io/io.hpp>
25 : #include <stdexcept>
26 : #include <string_view>
27 : #include <type_traits>
28 :
29 : namespace spb::pb::detail
30 : {
31 :
32 : struct istream
33 : {
34 : private:
35 : spb::io::reader on_read;
36 : size_t m_size;
37 :
38 : public:
39 1313 : istream( spb::io::reader reader, size_t size = std::numeric_limits< size_t >::max( ) ) noexcept
40 1313 : : on_read( reader )
41 1313 : , m_size( size )
42 : {
43 1313 : }
44 :
45 : void skip( uint32_t tag );
46 : void read_skip( size_t size );
47 :
48 : void deserialize( auto & value, uint32_t tag );
49 :
50 : template < scalar_encoder encoder >
51 : void deserialize_as( auto & value, uint32_t tag );
52 :
53 : template < size_t ordinal, typename T >
54 : void deserialize_variant( T & variant, uint32_t tag );
55 :
56 : template < size_t ordinal, scalar_encoder encoder, typename T >
57 : void deserialize_variant_as( T & variant, uint32_t tag );
58 :
59 : template < scalar_encoder encoder, typename T >
60 : auto deserialize_bitfield_as( uint32_t bits, uint32_t tag ) -> T;
61 :
62 1171 : [[nodiscard]] auto read_byte( ) -> uint8_t
63 : {
64 1171 : uint8_t result = { };
65 1171 : read_exact( &result, sizeof( result ) );
66 1111 : return result;
67 : }
68 :
69 1734 : [[nodiscard]] auto read_byte_or_eof( ) -> int
70 : {
71 1734 : uint8_t result = { };
72 1734 : if( on_read( &result, sizeof( result ) ) == 0 )
73 : {
74 745 : return -1;
75 : }
76 989 : return result;
77 : }
78 :
79 2790 : [[nodiscard]] auto size( ) const -> size_t
80 : {
81 2790 : return m_size;
82 : }
83 :
84 1798 : void read_exact( void * data, size_t size )
85 : {
86 1798 : if( this->size( ) < size ) [[unlikely]]
87 : {
88 12 : throw std::runtime_error( "unexpected end of stream" );
89 : }
90 :
91 3524 : while( size > 0 )
92 : {
93 1834 : auto chunk_size = on_read( data, size );
94 1834 : if( chunk_size == 0 )
95 : {
96 96 : throw std::runtime_error( "unexpected end of stream" );
97 : }
98 :
99 1738 : size -= chunk_size;
100 1738 : m_size -= chunk_size;
101 : }
102 1690 : }
103 :
104 446 : [[nodiscard]] auto empty( ) const -> bool
105 : {
106 446 : return size( ) == 0;
107 : }
108 :
109 280 : [[nodiscard]] auto sub_stream( size_t sub_size ) -> istream
110 : {
111 280 : if( size( ) < sub_size )
112 : {
113 1 : throw std::runtime_error( "unexpected end of stream" );
114 : }
115 279 : m_size -= sub_size;
116 279 : return istream( on_read, sub_size );
117 : }
118 : };
119 :
120 1999 : [[nodiscard]] static inline auto wire_type_from_tag( uint32_t tag ) -> wire_type
121 : {
122 1999 : return wire_type( tag & 0x07 );
123 : }
124 :
125 1949 : [[nodiscard]] static inline auto field_from_tag( uint32_t tag ) -> uint32_t
126 : {
127 1949 : return tag >> 3;
128 : }
129 :
130 988 : static inline void check_tag( uint32_t tag )
131 : {
132 988 : if( field_from_tag( tag ) == 0 )
133 : {
134 2 : throw std::runtime_error( "invalid field id" );
135 : }
136 986 : }
137 :
138 757 : static inline void check_wire_type( wire_type type1, wire_type type2 )
139 : {
140 757 : if( type1 != type2 )
141 : {
142 9 : throw std::runtime_error( "invalid wire type" );
143 : }
144 748 : }
145 :
146 193 : static inline void check_if_empty( istream & stream )
147 : {
148 193 : if( !stream.empty( ) )
149 : {
150 0 : throw std::runtime_error( "unexpected data in stream" );
151 : }
152 193 : }
153 :
154 1734 : [[nodiscard]] static inline auto read_tag_or_eof( istream & stream ) -> uint32_t
155 : {
156 1734 : auto byte_or_eof = stream.read_byte_or_eof( );
157 1734 : if( byte_or_eof < 0 )
158 : {
159 745 : return 0;
160 : }
161 989 : auto byte = uint8_t( byte_or_eof );
162 989 : auto tag = uint32_t( byte & 0x7F );
163 :
164 1004 : for( size_t shift = CHAR_BIT - 1; ( byte & 0x80 ) != 0; shift += CHAR_BIT - 1 )
165 : {
166 16 : if( shift >= sizeof( tag ) * CHAR_BIT )
167 : {
168 1 : throw std::runtime_error( "invalid tag" );
169 : }
170 :
171 15 : byte = stream.read_byte( );
172 15 : tag |= uint64_t( byte & 0x7F ) << shift;
173 : }
174 :
175 988 : check_tag( tag );
176 :
177 986 : return tag;
178 : }
179 :
180 : template < typename T >
181 691 : [[nodiscard]] static inline auto read_varint( istream & stream ) -> T
182 : {
183 : if constexpr( std::is_same_v< T, bool > )
184 : {
185 38 : switch( stream.read_byte( ) )
186 : {
187 10 : case 0:
188 10 : return false;
189 16 : case 1:
190 16 : return true;
191 8 : default:
192 8 : throw std::runtime_error( "invalid varint for bool" );
193 : }
194 : }
195 : else
196 : {
197 653 : auto value = uint64_t( 0 );
198 :
199 1132 : for( auto shift = 0U; shift < sizeof( value ) * CHAR_BIT; shift += CHAR_BIT - 1 )
200 : {
201 1118 : uint8_t byte = stream.read_byte( );
202 1062 : value |= uint64_t( byte & 0x7F ) << shift;
203 1062 : if( ( byte & 0x80 ) == 0 )
204 : {
205 : if constexpr( std::is_signed_v< T > && sizeof( T ) < sizeof( value ) )
206 : {
207 : //- GPB encodes signed varints always as 64-bits
208 : //- so int32_t(-2) is encoded as "\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01",
209 : // same as int64_t(-2)
210 : //- but it should be encoded as "\xfe\xff\xff\xff\x0f"
211 106 : value = T( value );
212 : }
213 583 : auto result = T( value );
214 : if constexpr( std::is_signed_v< T > )
215 : {
216 134 : if( result == std::make_signed_t< T >( value ) )
217 : {
218 134 : return result;
219 : }
220 : }
221 : else
222 : {
223 449 : if( result == value )
224 : {
225 443 : return result;
226 : }
227 : }
228 :
229 6 : break;
230 : }
231 : }
232 20 : throw std::runtime_error( "invalid varint" );
233 : }
234 : }
235 :
236 : static inline void deserialize( istream & stream, spb::detail::proto_message auto & value,
237 : wire_type type );
238 :
239 : template < scalar_encoder encoder >
240 : static inline void deserialize_as( istream & stream,
241 : spb::detail::proto_field_int_or_float auto & value,
242 : wire_type type );
243 : static inline void deserialize( istream & stream, spb::detail::proto_field_bytes auto & value,
244 : wire_type type );
245 : static inline void deserialize( istream & stream, spb::detail::proto_label_repeated auto & value,
246 : wire_type type );
247 : static inline void deserialize( istream & stream, spb::detail::proto_field_string auto & value,
248 : wire_type type );
249 :
250 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
251 : static inline void deserialize_as( istream & stream, C & value, wire_type type );
252 :
253 : template < scalar_encoder encoder, typename keyT, typename valueT >
254 : static inline void deserialize_as( istream & stream, std::map< keyT, valueT > & value,
255 : wire_type type );
256 :
257 : static inline void deserialize( istream & stream, spb::detail::proto_label_optional auto & p_value,
258 : wire_type type );
259 :
260 : template < scalar_encoder encoder, spb::detail::proto_label_optional C >
261 : static inline void deserialize_as( istream & stream, C & p_value, wire_type type );
262 :
263 : template < typename T >
264 : static inline void deserialize( istream & stream, std::unique_ptr< T > & value, wire_type type );
265 :
266 : template < typename T, typename signedT, typename unsignedT >
267 100 : static auto create_tmp_var( )
268 : {
269 : if constexpr( std::is_signed< T >::value )
270 : {
271 40 : return signedT( );
272 : }
273 : else
274 : {
275 60 : return unsignedT( );
276 : }
277 : }
278 :
279 : template < scalar_encoder encoder, typename T >
280 252 : static inline auto deserialize_bitfield_as( istream & stream, uint32_t bits, wire_type type ) -> T
281 : {
282 252 : auto value = T( );
283 : if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::svarint )
284 : {
285 20 : check_wire_type( type, wire_type::varint );
286 :
287 20 : auto tmp = read_varint< std::make_unsigned_t< T > >( stream );
288 20 : value = T( ( tmp >> 1 ) ^ ( ~( tmp & 1 ) + 1 ) );
289 : }
290 : else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::varint )
291 : {
292 52 : check_wire_type( type, wire_type::varint );
293 52 : value = read_varint< T >( stream );
294 : }
295 : else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i32 )
296 : {
297 : static_assert( sizeof( T ) <= sizeof( uint32_t ) );
298 :
299 100 : check_wire_type( type, wire_type::fixed32 );
300 :
301 : if constexpr( sizeof( value ) == sizeof( uint32_t ) )
302 : {
303 40 : stream.read_exact( &value, sizeof( value ) );
304 : }
305 : else
306 : {
307 60 : auto tmp = create_tmp_var< T, int32_t, uint32_t >( );
308 60 : stream.read_exact( &tmp, sizeof( tmp ) );
309 60 : spb::detail::check_if_value_fit_in_bits( tmp, bits );
310 36 : value = T( tmp );
311 : }
312 : }
313 : else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i64 )
314 : {
315 : static_assert( sizeof( T ) <= sizeof( uint64_t ) );
316 80 : check_wire_type( type, wire_type::fixed64 );
317 :
318 : if constexpr( sizeof( value ) == sizeof( uint64_t ) )
319 : {
320 40 : stream.read_exact( &value, sizeof( value ) );
321 : }
322 : else
323 : {
324 40 : auto tmp = create_tmp_var< T, int64_t, uint64_t >( );
325 40 : stream.read_exact( &tmp, sizeof( tmp ) );
326 40 : spb::detail::check_if_value_fit_in_bits( tmp, bits );
327 24 : value = T( tmp );
328 : }
329 : }
330 208 : spb::detail::check_if_value_fit_in_bits( value, bits );
331 156 : return value;
332 : }
333 :
334 : template < scalar_encoder encoder >
335 50 : static inline void deserialize_as( istream & stream, spb::detail::proto_enum auto & value,
336 : wire_type type )
337 : {
338 : using T = std::remove_cvref_t< decltype( value ) >;
339 : using int_type = std::underlying_type_t< T >;
340 :
341 : if constexpr( !scalar_encoder_is_packed( encoder ) )
342 : {
343 26 : check_wire_type( type, wire_type::varint );
344 : }
345 :
346 50 : value = T( read_varint< int_type >( stream ) );
347 46 : }
348 :
349 : template < scalar_encoder encoder >
350 478 : static inline void deserialize_as( istream & stream,
351 : spb::detail::proto_field_int_or_float auto & value,
352 : wire_type type )
353 : {
354 : using T = std::remove_cvref_t< decltype( value ) >;
355 :
356 : if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::svarint )
357 : {
358 : if constexpr( !scalar_encoder_is_packed( encoder ) )
359 : {
360 48 : check_wire_type( type, wire_type::varint );
361 : }
362 74 : auto tmp = read_varint< std::make_unsigned_t< T > >( stream );
363 54 : value = T( ( tmp >> 1 ) ^ ( ~( tmp & 1 ) + 1 ) );
364 : }
365 : else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::varint )
366 : {
367 : if constexpr( !scalar_encoder_is_packed( encoder ) )
368 : {
369 92 : check_wire_type( type, wire_type::varint );
370 : }
371 132 : value = read_varint< T >( stream );
372 : }
373 : else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i32 )
374 : {
375 : static_assert( sizeof( T ) <= sizeof( uint32_t ) );
376 :
377 : if constexpr( !scalar_encoder_is_packed( encoder ) )
378 : {
379 114 : check_wire_type( type, wire_type::fixed32 );
380 : }
381 : if constexpr( sizeof( value ) == sizeof( uint32_t ) )
382 : {
383 68 : stream.read_exact( &value, sizeof( value ) );
384 : }
385 : else
386 : {
387 : if constexpr( std::is_signed_v< T > )
388 : {
389 26 : auto tmp = int32_t( 0 );
390 26 : stream.read_exact( &tmp, sizeof( tmp ) );
391 44 : if( tmp > std::numeric_limits< T >::max( ) ||
392 20 : tmp < std::numeric_limits< T >::min( ) )
393 : {
394 4 : throw std::runtime_error( "int overflow" );
395 : }
396 20 : value = T( tmp );
397 : }
398 : else
399 : {
400 60 : auto tmp = uint32_t( 0 );
401 60 : stream.read_exact( &tmp, sizeof( tmp ) );
402 52 : if( tmp > std::numeric_limits< T >::max( ) )
403 : {
404 8 : throw std::runtime_error( "int overflow" );
405 : }
406 44 : value = T( tmp );
407 : }
408 : }
409 : }
410 : else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i64 )
411 : {
412 : static_assert( sizeof( T ) <= sizeof( uint64_t ) );
413 : if constexpr( !scalar_encoder_is_packed( encoder ) )
414 : {
415 90 : check_wire_type( type, wire_type::fixed64 );
416 : }
417 : if constexpr( sizeof( value ) == sizeof( uint64_t ) )
418 : {
419 60 : stream.read_exact( &value, sizeof( value ) );
420 : }
421 : else
422 : {
423 : if constexpr( std::is_signed_v< T > )
424 : {
425 26 : auto tmp = int64_t( 0 );
426 26 : stream.read_exact( &tmp, sizeof( tmp ) );
427 44 : if( tmp > std::numeric_limits< T >::max( ) ||
428 20 : tmp < std::numeric_limits< T >::min( ) )
429 : {
430 4 : throw std::runtime_error( "int overflow" );
431 : }
432 20 : value = T( tmp );
433 : }
434 : else
435 : {
436 26 : auto tmp = uint64_t( 0 );
437 26 : stream.read_exact( &tmp, sizeof( tmp ) );
438 24 : if( tmp > std::numeric_limits< T >::max( ) )
439 : {
440 4 : throw std::runtime_error( "int overflow" );
441 : }
442 20 : value = T( tmp );
443 : }
444 : }
445 : }
446 372 : }
447 :
448 41 : static inline void deserialize( istream & stream, spb::detail::proto_label_optional auto & p_value,
449 : wire_type type )
450 : {
451 71 : auto & value = p_value.emplace( typename std::decay_t< decltype( p_value ) >::value_type( ) );
452 41 : deserialize( stream, value, type );
453 28 : }
454 :
455 : template < scalar_encoder encoder, spb::detail::proto_label_optional C >
456 100 : static inline void deserialize_as( istream & stream, C & p_value, wire_type type )
457 : {
458 100 : auto & value = p_value.emplace( typename C::value_type( ) );
459 100 : deserialize_as< encoder >( stream, value, type );
460 92 : }
461 :
462 79 : static inline void deserialize( istream & stream, spb::detail::proto_field_string auto & value,
463 : wire_type type )
464 : {
465 79 : check_wire_type( type, wire_type::length_delimited );
466 : if constexpr( spb::detail::proto_field_string_resizable< decltype( value ) > )
467 : {
468 46 : value.resize( stream.size( ) );
469 : }
470 : else
471 : {
472 30 : if( value.size( ) != stream.size( ) )
473 : {
474 14 : throw std::runtime_error( "invalid string size" );
475 : }
476 : }
477 78 : stream.read_exact( value.data( ), stream.size( ) );
478 71 : spb::detail::utf8::validate( std::string_view( value.data( ), value.size( ) ) );
479 54 : }
480 :
481 : template < typename T >
482 0 : static inline void deserialize( istream & stream, std::unique_ptr< T > & value, wire_type type )
483 : {
484 0 : value = std::make_unique< T >( );
485 0 : deserialize( stream, *value, type );
486 0 : }
487 :
488 48 : static inline void deserialize( istream & stream, spb::detail::proto_field_bytes auto & value,
489 : wire_type type )
490 : {
491 48 : check_wire_type( type, wire_type::length_delimited );
492 : if constexpr( spb::detail::proto_field_bytes_resizable< decltype( value ) > )
493 : {
494 24 : value.resize( stream.size( ) );
495 : }
496 : else
497 : {
498 48 : if( stream.size( ) != value.size( ) )
499 : {
500 12 : throw std::runtime_error( "invalid bytes size" );
501 : }
502 : }
503 48 : stream.read_exact( value.data( ), stream.size( ) );
504 34 : }
505 :
506 38 : static inline void deserialize( istream & stream, spb::detail::proto_label_repeated auto & value,
507 : wire_type type )
508 : {
509 38 : deserialize( stream, value.emplace_back( ), type );
510 30 : }
511 :
512 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
513 100 : static inline void deserialize_packed_as( istream & stream, C & value, wire_type type )
514 : {
515 234 : while( !stream.empty( ) )
516 : {
517 : if constexpr( std::is_same_v< typename C::value_type, bool > )
518 : {
519 10 : value.emplace_back( read_varint< bool >( stream ) );
520 : }
521 : else
522 : {
523 158 : deserialize_as< encoder >( stream, value.emplace_back( ), type );
524 : }
525 : }
526 66 : }
527 :
528 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
529 224 : static inline void deserialize_as( istream & stream, C & value, wire_type type )
530 : {
531 : if constexpr( scalar_encoder_is_packed( encoder ) )
532 : {
533 100 : deserialize_packed_as< encoder >( stream, value, wire_type_from_scalar_encoder( encoder ) );
534 : }
535 : else
536 : {
537 : if constexpr( std::is_same_v< typename C::value_type, bool > )
538 : {
539 14 : value.emplace_back( read_varint< bool >( stream ) );
540 : }
541 : else
542 : {
543 110 : deserialize_as< encoder >( stream, value.emplace_back( ), type );
544 : }
545 : }
546 186 : }
547 :
548 : template < scalar_encoder encoder, typename keyT, typename valueT >
549 0 : static inline void deserialize_as( istream & stream, std::map< keyT, valueT > & value,
550 : wire_type type )
551 : {
552 0 : const auto key_encoder = scalar_encoder_type1( encoder );
553 0 : const auto value_encoder = scalar_encoder_type2( encoder );
554 :
555 0 : check_wire_type( type, wire_type::length_delimited );
556 :
557 0 : auto pair = std::pair< keyT, valueT >( );
558 0 : auto key_defined = false;
559 0 : auto value_defined = false;
560 0 : while( !stream.empty( ) )
561 : {
562 0 : const auto tag = read_varint< uint32_t >( stream );
563 0 : const auto field = field_from_tag( tag );
564 0 : const auto field_type = wire_type_from_tag( tag );
565 :
566 0 : switch( field )
567 : {
568 0 : case 1:
569 : if constexpr( std::is_integral_v< keyT > )
570 : {
571 0 : deserialize_as< key_encoder >( stream, pair.first, field_type );
572 : }
573 : else
574 : {
575 0 : if( field_type == wire_type::length_delimited )
576 : {
577 0 : const auto size = read_varint< uint32_t >( stream );
578 0 : auto substream = stream.sub_stream( size );
579 0 : deserialize( substream, pair.first, field_type );
580 0 : check_if_empty( substream );
581 : }
582 : else
583 : {
584 0 : deserialize( stream, pair.first, field_type );
585 : }
586 : }
587 0 : key_defined = true;
588 0 : break;
589 0 : case 2:
590 : if constexpr( spb::detail::proto_field_number< valueT > )
591 : {
592 0 : deserialize_as< value_encoder >( stream, pair.second, field_type );
593 : }
594 : else
595 : {
596 0 : if( field_type == wire_type::length_delimited )
597 : {
598 0 : const auto size = read_varint< uint32_t >( stream );
599 0 : auto substream = stream.sub_stream( size );
600 0 : deserialize( substream, pair.second, field_type );
601 0 : check_if_empty( substream );
602 : }
603 : else
604 : {
605 0 : throw std::runtime_error( "invalid field" );
606 : }
607 : }
608 0 : value_defined = true;
609 0 : break;
610 0 : default:
611 0 : throw std::runtime_error( "invalid field" );
612 : }
613 : }
614 0 : if( key_defined && value_defined )
615 : {
616 0 : value.insert( std::move( pair ) );
617 : }
618 : else
619 : {
620 0 : throw std::runtime_error( "invalid map item" );
621 : }
622 0 : }
623 :
624 : template < size_t ordinal, typename T >
625 6 : static inline void deserialize_variant( istream & stream, T & variant, wire_type type )
626 : {
627 6 : deserialize( stream, variant.template emplace< ordinal >( ), type );
628 6 : }
629 :
630 : template < size_t ordinal, scalar_encoder encoder, typename T >
631 2 : static inline void deserialize_variant_as( istream & stream, T & variant, wire_type type )
632 : {
633 2 : deserialize_as< encoder >( stream, variant.template emplace< ordinal >( ), type );
634 2 : }
635 :
636 1034 : static inline void deserialize_main( istream & stream, spb::detail::proto_message auto & value )
637 : {
638 700 : for( ;; )
639 : {
640 1734 : const auto tag = read_tag_or_eof( stream );
641 1731 : if( !tag )
642 : {
643 745 : break;
644 : }
645 986 : const auto field_type = wire_type_from_tag( tag );
646 :
647 986 : if( field_type == wire_type::length_delimited )
648 : {
649 270 : const auto size = read_varint< uint32_t >( stream );
650 270 : auto substream = stream.sub_stream( size );
651 270 : deserialize_value( substream, value, tag );
652 186 : check_if_empty( substream );
653 : }
654 : else
655 : {
656 716 : deserialize_value( stream, value, tag );
657 : }
658 : }
659 745 : }
660 :
661 8 : static inline void deserialize( istream & stream, spb::detail::proto_message auto & value,
662 : wire_type type )
663 : {
664 8 : check_wire_type( type, wire_type::length_delimited );
665 :
666 19 : while( !stream.empty( ) )
667 : {
668 15 : const auto tag = read_varint< uint32_t >( stream );
669 14 : const auto field_type = wire_type_from_tag( tag );
670 :
671 14 : if( field_type == wire_type::length_delimited )
672 : {
673 8 : const auto size = read_varint< uint32_t >( stream );
674 8 : auto substream = stream.sub_stream( size );
675 7 : deserialize_value( substream, value, tag );
676 7 : check_if_empty( substream );
677 : }
678 : else
679 : {
680 6 : deserialize_value( stream, value, tag );
681 : }
682 : }
683 4 : }
684 :
685 129 : inline void istream::deserialize( auto & value, uint32_t tag )
686 : {
687 129 : detail::deserialize( *this, value, wire_type_from_tag( tag ) );
688 86 : }
689 :
690 83 : inline void istream::read_skip( size_t size )
691 : {
692 : uint8_t buffer[ 64 ];
693 151 : while( size > 0 )
694 : {
695 83 : auto chunk_size = std::min( size, sizeof( buffer ) );
696 83 : read_exact( buffer, chunk_size );
697 68 : size -= chunk_size;
698 : }
699 68 : }
700 :
701 128 : inline void istream::skip( uint32_t tag )
702 : {
703 128 : switch( wire_type_from_tag( tag ) )
704 : {
705 44 : case wire_type::varint:
706 44 : return ( void ) read_varint< uint64_t >( *this );
707 44 : case wire_type::length_delimited:
708 44 : return read_skip( size( ) );
709 20 : case wire_type::fixed32:
710 20 : return read_skip( sizeof( uint32_t ) );
711 19 : case wire_type::fixed64:
712 19 : return read_skip( sizeof( uint64_t ) );
713 1 : default:
714 1 : throw std::runtime_error( "invalid wire type" );
715 : }
716 : }
717 :
718 : template < scalar_encoder encoder >
719 482 : inline void istream::deserialize_as( auto & value, uint32_t tag )
720 : {
721 482 : detail::deserialize_as< encoder >( *this, value, wire_type_from_tag( tag ) );
722 364 : }
723 :
724 : template < size_t ordinal, typename T >
725 6 : inline void istream::deserialize_variant( T & variant, uint32_t tag )
726 : {
727 6 : detail::deserialize_variant< ordinal >( *this, variant, wire_type_from_tag( tag ) );
728 6 : }
729 :
730 : template < size_t ordinal, scalar_encoder encoder, typename T >
731 2 : inline void istream::deserialize_variant_as( T & variant, uint32_t tag )
732 : {
733 2 : detail::deserialize_variant_as< ordinal, encoder >( *this, variant, wire_type_from_tag( tag ) );
734 2 : }
735 :
736 : template < scalar_encoder encoder, typename T >
737 252 : inline auto istream::deserialize_bitfield_as( uint32_t bits, uint32_t tag ) -> T
738 : {
739 252 : return detail::deserialize_bitfield_as< encoder, T >( *this, bits, wire_type_from_tag( tag ) );
740 : }
741 :
742 : static inline void deserialize( auto & value, spb::io::reader on_read )
743 : {
744 : using T = std::remove_cvref_t< decltype( value ) >;
745 : static_assert( spb::detail::proto_message< T > );
746 :
747 : auto stream = istream( on_read );
748 : deserialize_main( stream, value );
749 : }
750 :
751 : }// namespace spb::pb::detail
|