LCOV - code coverage report
Current view: top level - spb/pb - deserialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.6 % 261 260
Test Date: 2026-05-30 19:41:37 Functions: 69.9 % 642 449

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

Generated by: LCOV version 2.0-1