LCOV - code coverage report
Current view: top level - spb/pb - deserialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.0 % 300 282
Test Date: 2026-07-19 10:31:31 Functions: 82.4 % 1215 1001

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

Generated by: LCOV version 2.0-1