LCOV - code coverage report
Current view: top level - spb/pb - serialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.6 % 140 138
Test Date: 2026-10-01 11:28:31 Functions: 71.4 % 1388 991

            Line data    Source code
       1              : /***************************************************************************\
       2              : * Name        : serialize library for protobuf                              *
       3              : * Description : all protobuf serialization 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 "../concepts.h"
      14              : #include "../utf8.h"
      15              : #include "wire-types.h"
      16              : #include <cstddef>
      17              : #include <cstdint>
      18              : #include <cstring>
      19              : #include <memory>
      20              : #include <spb/io/io.hpp>
      21              : #include <sys/types.h>
      22              : #include <type_traits>
      23              : 
      24              : namespace spb::pb::detail
      25              : {
      26              : struct ostream_size
      27              : {
      28              :     static constexpr bool size_only = true;
      29              :     size_t size;
      30              : 
      31         3740 :     void write(const void *, size_t data_size)
      32              :     {
      33         3740 :         size += data_size;
      34         3740 :     }
      35              : 
      36        10718 :     void write(uint8_t)
      37              :     {
      38        10718 :         ++size;
      39        10718 :     }
      40              : };
      41              : struct ostream_buffer
      42              : {
      43              :     static constexpr bool size_only = false;
      44              :     uint8_t *p_buffer;
      45              : 
      46         2012 :     explicit ostream_buffer(void *buffer) : p_buffer((uint8_t *)buffer)
      47              :     {
      48         2012 :     }
      49              : 
      50         4791 :     void write(uint8_t byte)
      51              :     {
      52         4791 :         *p_buffer++ = byte;
      53         4791 :     }
      54              : 
      55         1168 :     void write(const void *data, size_t size)
      56              :     {
      57         1168 :         memcpy(p_buffer, data, size);
      58         1168 :         p_buffer += size;
      59         1168 :     }
      60              : };
      61              : 
      62              : struct ostream_writer
      63              : {
      64              :     static constexpr bool size_only = false;
      65              :     spb::io::writer on_write;
      66              :     size_t size = 0;
      67              : 
      68          772 :     explicit ostream_writer(spb::io::writer writer) : on_write(writer)
      69              :     {
      70          772 :     }
      71              : 
      72         2138 :     void write(uint8_t byte)
      73              :     {
      74         2138 :         write(&byte, 1);
      75         2138 :     }
      76              : 
      77         2704 :     void write(const void *data, size_t data_size)
      78              :     {
      79         2704 :         on_write(data, data_size);
      80         2704 :         size += data_size;
      81         2704 :     }
      82              : };
      83              : 
      84              : template <typename T> void check_enum_value_or_throw(enum_type);
      85              : template <serialize_mode = serialize_mode{}> size_t serialize_size(const auto &value);
      86              : template <serialize_mode = serialize_mode{}> size_t serialize_size(uint32_t field, const auto &value);
      87              : template <serialize_mode> void serialize(auto &stream, const spb::detail::proto_message auto &value);
      88              : 
      89         1546 : inline size_t serialize_varint_size(uint64_t value)
      90              : {
      91         1546 :     size_t size = 1;
      92         1546 :     while (value >= 0x80)
      93              :     {
      94            0 :         ++size;
      95            0 :         value >>= 7;
      96              :     }
      97         1546 :     return size;
      98              : }
      99              : 
     100        15860 : void serialize_varint(auto &stream, uint64_t value)
     101              : {
     102        17407 :     while (value >= 0x80)
     103              :     {
     104         1547 :         stream.write((uint8_t)(value & 0x7F) | 0x80);
     105         1547 :         value >>= 7;
     106              :     }
     107        15860 :     stream.write((uint8_t)value);
     108        15860 : }
     109              : 
     110          570 : void serialize_svarint(auto &stream, int64_t value)
     111              : {
     112          570 :     const auto tmp = uint64_t((value << 1) ^ (value >> 63));
     113          570 :     serialize_varint(stream, tmp);
     114          570 : }
     115              : 
     116         7610 : void serialize_tag(auto &stream, uint32_t field_number, wire_type type)
     117              : {
     118         7610 :     const auto tag = (field_number << 3) | uint32_t(type);
     119         7610 :     serialize_varint(stream, tag);
     120         7610 : }
     121              : 
     122              : template <serialize_mode>
     123              : void serialize(auto &stream, uint32_t field, const spb::detail::proto_message auto &value);
     124              : template <serialize_mode>
     125              : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_string auto &value);
     126              : template <serialize_mode>
     127              : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_bytes auto &value);
     128              : template <serialize_mode>
     129              : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_repeated auto &value);
     130              : template <serialize_mode>
     131              : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_repeated_fixed_size auto &value);
     132              : 
     133              : template <serialize_mode>
     134              : void serialize(auto &stream, uint32_t field, const spb::detail::proto_map auto &value);
     135              : 
     136              : template <serialize_mode mode>
     137         3896 : void serialize(auto &stream, uint32_t field, spb::detail::proto_field_number auto value)
     138              : {
     139         3896 :     serialize_tag(stream, field, to_wire_type(mode.encoder));
     140         3896 :     serialize<mode>(stream, value);
     141         3895 : }
     142              : 
     143          436 : template <serialize_mode mode> void serialize(auto &stream, const spb::detail::proto_enum auto &value)
     144              : {
     145              :     using T = std::remove_cvref_t<decltype(value)>;
     146              : 
     147          436 :     const auto int_enum = (enum_type)value;
     148          436 :     check_enum_value_or_throw<T>(int_enum);
     149          435 :     serialize_varint(stream, int_enum);
     150          435 : }
     151              : 
     152         5750 : template <serialize_mode mode> void serialize(auto &stream, spb::detail::proto_field_int_or_float auto value)
     153              : {
     154              :     using T = std::remove_cvref_t<decltype(value)>;
     155              : 
     156         5750 :     constexpr auto type = encoder_type(mode.encoder);
     157              :     if constexpr (type == scalar_encoder::varint)
     158              :     {
     159              :         static_assert(std::is_integral_v<T>);
     160              : 
     161              :         if constexpr (std::is_same_v<bool, T>)
     162              :         {
     163          240 :             const uint8_t tmp = value ? 1 : 0;
     164          240 :             return stream.write(tmp);
     165              :         }
     166              :         else if constexpr (std::is_signed_v<T>)
     167              :         {
     168              :             //- GPB is serializing all negative ints always as int64_t
     169         1655 :             const auto u_value = uint64_t(int64_t(value));
     170         1655 :             return serialize_varint(stream, u_value);
     171              :         }
     172              :         else
     173              :         {
     174          330 :             return serialize_varint(stream, value);
     175              :         }
     176              :     }
     177              :     else if constexpr (type == scalar_encoder::svarint)
     178              :     {
     179              :         static_assert(std::is_signed_v<T> && std::is_integral_v<T>);
     180              : 
     181          570 :         return serialize_svarint(stream, value);
     182              :     }
     183              :     else if constexpr (type == scalar_encoder::i32)
     184              :     {
     185              :         if constexpr (sizeof(value) == sizeof(uint32_t))
     186              :         {
     187          825 :             return stream.write(&value, sizeof(value));
     188              :         }
     189              :         else
     190              :         {
     191          855 :             const auto tmp = uint32_t(value);
     192          951 :             return stream.write(&tmp, sizeof(tmp));
     193              :         }
     194              :     }
     195              :     else if constexpr (type == scalar_encoder::i64)
     196              :     {
     197              :         if constexpr (sizeof(value) == sizeof(uint64_t))
     198              :         {
     199          705 :             return stream.write(&value, sizeof(value));
     200              :         }
     201              :         else
     202              :         {
     203          570 :             const auto tmp = uint64_t(value);
     204          634 :             return stream.write(&tmp, sizeof(tmp));
     205              :         }
     206              :     }
     207              : }
     208              : 
     209              : template <serialize_mode mode>
     210           60 : void serialize_packed(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &container)
     211              : {
     212              :     static_assert(is_packed(mode.encoder), "repeated field with fixed size has to have attribute 'packed'");
     213              : 
     214              :     using ValueType = typename std::remove_cvref_t<decltype(container)>::value_type;
     215              : 
     216          600 :     for (size_t i = 0; i < container.size(); i++)
     217              :     {
     218              :         if constexpr (std::is_same_v<ValueType, bool>)
     219              :             serialize<mode>(stream, bool(container[i]));
     220              :         else
     221          240 :             serialize<mode>(stream, container[i]);
     222              :     }
     223           60 : }
     224              : 
     225              : template <serialize_mode mode>
     226           30 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &container)
     227              : {
     228           30 :     serialize_packed<mode>(stream, container);
     229           30 : }
     230              : 
     231              : template <serialize_mode mode>
     232         1100 : void serialize_packed(auto &stream, const spb::detail::proto_label_repeated auto &container)
     233              : {
     234              :     static_assert(is_packed(mode.encoder), "repeated field has to have attribute 'packed'");
     235              : 
     236              :     using ValueType = typename std::remove_cvref_t<decltype(container)>::value_type;
     237              : 
     238         3150 :     for (const auto &v : container)
     239              :     {
     240              :         if constexpr (std::is_same_v<ValueType, bool>)
     241           90 :             serialize<mode>(stream, bool(v));
     242              :         else
     243         1960 :             serialize<mode>(stream, v);
     244              :     }
     245         1100 : }
     246              : 
     247              : template <serialize_mode mode>
     248          550 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &container)
     249              : {
     250          550 :     serialize_packed<mode>(stream, container);
     251          550 : }
     252              : 
     253              : template <serialize_mode mode>
     254         1825 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_string auto &value)
     255              : {
     256              :     using stream_type = std::remove_cvref_t<decltype(stream)>;
     257              : 
     258              :     if constexpr (!stream_type::size_only && mode.max_size)
     259           64 :         check_size(value.size(), mode.max_size);
     260              : 
     261              :     if constexpr (!stream_type::size_only)
     262          474 :         spb::detail::utf8::validate(std::string_view(value.data(), value.size()));
     263              : 
     264         1809 :     serialize_tag(stream, field, wire_type::length_delimited);
     265         1809 :     serialize_varint(stream, value.size());
     266         1809 :     stream.write(value.data(), value.size());
     267         1809 : }
     268              : 
     269              : template <serialize_mode mode>
     270          726 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_bytes auto &value)
     271              : {
     272              :     using stream_type = std::remove_cvref_t<decltype(stream)>;
     273              : 
     274              :     if constexpr (!stream_type::size_only && mode.max_size)
     275           64 :         check_size(value.size(), mode.max_size);
     276              : 
     277          710 :     serialize_tag(stream, field, wire_type::length_delimited);
     278          710 :     serialize_varint(stream, value.size());
     279          710 :     stream.write(value.data(), value.size());
     280          710 : }
     281              : 
     282              : template <serialize_mode mode>
     283          135 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_map auto &value)
     284              : {
     285          135 :     constexpr auto key_encoder   = serialize_mode{.encoder = mode.encoder};
     286          135 :     constexpr auto value_encoder = serialize_mode{.encoder = mode.encoder2};
     287              : 
     288          300 :     for (const auto &[k, v] : value)
     289              :     {
     290          165 :         serialize_tag(stream, field, wire_type::length_delimited);
     291          165 :         serialize_varint(stream, serialize_size<key_encoder>(1, k) + serialize_size<value_encoder>(2, v));
     292          165 :         serialize<key_encoder>(stream, 1, k);
     293          165 :         serialize<value_encoder>(stream, 2, v);
     294              :     }
     295          135 : }
     296              : 
     297              : template <serialize_mode mode>
     298         2398 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_repeated auto &container)
     299              : {
     300              :     using value_type  = typename std::remove_cvref_t<decltype(container)>::value_type;
     301              :     using stream_type = std::remove_cvref_t<decltype(stream)>;
     302              : 
     303              :     if constexpr (!stream_type::size_only && mode.max_count)
     304          136 :         check_size(container.size(), mode.max_count);
     305              : 
     306              :     if constexpr (is_packed(mode.encoder))
     307              :     {
     308          865 :         if (container.empty())
     309          315 :             return;
     310              : 
     311          550 :         serialize_tag(stream, field, wire_type::length_delimited);
     312          550 :         serialize_varint(stream, serialize_size<mode>(container));
     313          550 :         serialize_packed<mode>(stream, container);
     314              :     }
     315              :     else
     316              :     {
     317         3684 :         for (const auto &value : container)
     318              :         {
     319              :             if constexpr (std::is_same_v<value_type, bool>)
     320           45 :                 serialize<mode>(stream, field, bool(value));
     321              :             else
     322         2140 :                 serialize<mode>(stream, field, value);
     323              :         }
     324              :     }
     325         1499 : }
     326              : 
     327              : template <serialize_mode mode>
     328           30 : void serialize(auto &stream, uint32_t field,
     329              :                const spb::detail::proto_label_repeated_fixed_size auto &container)
     330              : {
     331              :     static_assert(is_packed(mode.encoder), "repeated field with fixed size has to have attribute 'packed'");
     332              : 
     333           30 :     serialize_tag(stream, field, wire_type::length_delimited);
     334           30 :     serialize_varint(stream, serialize_size<mode>(container));
     335           30 :     serialize_packed<mode>(stream, container);
     336           30 : }
     337              : 
     338              : template <serialize_mode mode>
     339         2007 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_optional auto &p_value)
     340              : {
     341         2007 :     if (p_value.has_value())
     342         1737 :         serialize<mode>(stream, field, *p_value);
     343         1991 : }
     344              : 
     345              : template <serialize_mode mode, typename T>
     346              : void serialize(auto &stream, uint32_t field, const std::unique_ptr<T> &p_value)
     347              : {
     348              :     if (p_value)
     349              :         serialize<mode>(stream, field, *p_value);
     350              : }
     351              : 
     352              : template <serialize_mode mode>
     353          450 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_message auto &value)
     354              : {
     355          450 :     serialize_tag(stream, field, wire_type::length_delimited);
     356          450 :     serialize_varint(stream, serialize_size<mode>(value));
     357          450 :     serialize_value(stream, value);
     358          450 : }
     359              : 
     360         4587 : template <serialize_mode mode> auto serialize_size(const auto &value) -> size_t
     361              : {
     362         4587 :     auto stream = ostream_size();
     363         4587 :     serialize<mode>(stream, value);
     364         4586 :     return stream.size;
     365              : }
     366              : 
     367          330 : template <serialize_mode mode> auto serialize_size(uint32_t field, const auto &value) -> size_t
     368              : {
     369          330 :     auto stream = ostream_size();
     370          330 :     serialize<mode>(stream, field, value);
     371          330 :     return stream.size;
     372              : }
     373              : 
     374         4007 : template <serialize_mode mode> void serialize(auto &stream, const spb::detail::proto_message auto &value)
     375              : {
     376         4007 :     serialize_value(stream, value);
     377         4006 : }
     378              : 
     379              : } // namespace spb::pb::detail
        

Generated by: LCOV version 2.0-1