LCOV - code coverage report
Current view: top level - spb/pb - serialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.3 % 146 142
Test Date: 2026-07-19 10:31:31 Functions: 71.2 % 1368 974

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

Generated by: LCOV version 2.0-1