LCOV - code coverage report
Current view: top level - spb - pb.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 46 46
Test Date: 2026-07-19 10:31:31 Functions: 100.0 % 1918 1918

            Line data    Source code
       1              : /***************************************************************************\
       2              : * Name        : Public API for protobuf                                     *
       3              : * Description : all protobuf serialize and deserialize 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              : #pragma once
      11              : 
      12              : #include "concepts.h"
      13              : #include "pb/deserialize.hpp"
      14              : #include "pb/serialize.hpp"
      15              : #include "spb/io/io.hpp"
      16              : #include "spb/pb/wire-types.h"
      17              : #include <cstdint>
      18              : #include <cstdlib>
      19              : 
      20              : namespace spb::pb
      21              : {
      22              : 
      23              : struct serialize_options
      24              : {
      25              :     /**
      26              :      * @brief Writes the size of the message (as a varint) before the message itself.
      27              :      *        Compatible with Google's `writeDelimitedTo` and NanoPb's PB_ENCODE_DELIMITED.
      28              :      */
      29              :     bool delimited = false;
      30              : };
      31              : 
      32              : struct deserialize_options
      33              : {
      34              :     /**
      35              :      * @brief Expect the size of the message (encoded as a varint) to come before the message
      36              :      * itself. Compatible with Google's `parseDelimitedFrom` and NanoPb's PB_DECODE_DELIMITED. Will
      37              :      * return after having read the specified length; the spb::io::reader object can then be read
      38              :      * from again to get the next message (if any).
      39              :      */
      40              :     bool delimited = false;
      41              : };
      42              : 
      43              : /**
      44              :  * @brief serialize message via writer
      45              :  *
      46              :  * @param[in] message to be serialized
      47              :  * @param[in] on_write function for handling the writes
      48              :  * @param[in] options
      49              :  * @return serialized size in bytes
      50              :  * @throws exceptions only from `on_write`
      51              :  */
      52          756 : size_t serialize(const auto &message, spb::io::writer on_write, const serialize_options &options = {})
      53              : {
      54          756 :     auto stream = detail::ostream_writer{on_write};
      55          756 :     if (options.delimited)
      56          378 :         detail::serialize_varint(stream, detail::serialize_size(message));
      57              : 
      58          756 :     serialize_value(stream, message);
      59          756 :     return stream.size;
      60              : }
      61              : 
      62              : /**
      63              :  * @brief return protobuf serialized size in bytes
      64              :  *
      65              :  * @param[in] message to be serialized
      66              :  * @param[in] options
      67              :  * @return serialized size in bytes
      68              :  */
      69         1512 : [[nodiscard]] size_t serialize_size(const auto &message, const serialize_options &options = {})
      70              : {
      71         1512 :     const auto size = detail::serialize_size(message);
      72         1512 :     return (options.delimited) ? size + detail::serialize_varint_size(size) : size;
      73              : }
      74              : 
      75              : size_t serialize(const auto &message, void *buffer, const serialize_options &options = {})
      76              : {
      77              :     const auto start = (uint8_t *)buffer;
      78              :     auto stream      = detail::ostream_buffer((uint8_t *)buffer);
      79              :     if (options.delimited)
      80              :         detail::serialize_varint(stream, detail::serialize_size(message));
      81              : 
      82              :     serialize_value(stream, message);
      83              :     return stream.p_buffer - start;
      84              : }
      85              : 
      86              : /**
      87              :  * @brief serialize message into protobuf
      88              :  *
      89              :  * @param[in] message to be serialized
      90              :  * @param[in] options
      91              :  * @param[out] result serialized protobuf
      92              :  * @return serialized size in bytes
      93              :  * @throws std::runtime_error on error
      94              :  * @example `auto serialized = std::vector< std::byte >();`
      95              :  *          `spb::pb::serialize( message, serialized );`
      96              :  */
      97              : template <spb::resizable_container Container>
      98         1594 : size_t serialize(const auto &message, Container &result, const serialize_options &options = {})
      99              : {
     100              :     static_assert(sizeof(*result.data()) == sizeof(uint8_t));
     101              : 
     102         1594 :     const auto size            = detail::serialize_size(message);
     103         1594 :     const auto serialized_size = options.delimited ? size + detail::serialize_varint_size(size) : size;
     104         1594 :     result.resize(serialized_size);
     105         1594 :     auto stream = detail::ostream_buffer((uint8_t *)result.data());
     106         1594 :     if (options.delimited)
     107          758 :         detail::serialize_varint(stream, size);
     108              : 
     109         1594 :     serialize_value(stream, message);
     110         3056 :     return result.size();
     111              : }
     112              : 
     113              : /**
     114              :  * @brief serialize message into protobuf
     115              :  *
     116              :  * @param[in] message to be serialized
     117              :  * @param[in] options
     118              :  * @return serialized protobuf
     119              :  * @throws std::runtime_error on error
     120              :  * @example `auto serialized_message = spb::pb::serialize< std::vector< std::byte > >( message );`
     121              :  */
     122              : template <spb::resizable_container Container = std::string>
     123         1594 : [[nodiscard]] Container serialize(const auto &message, const serialize_options &options = {})
     124              : {
     125         1594 :     auto result = Container();
     126         1594 :     serialize(message, result, options);
     127         1528 :     return result;
     128           66 : }
     129              : 
     130         1952 : size_t deserialize(auto &message, const void *buffer, size_t size, const deserialize_options &options = {})
     131              : {
     132         1952 :     detail::istream_buffer stream((const uint8_t *)buffer, size);
     133         1952 :     if (options.delimited)
     134              :     {
     135          758 :         const auto substream_length = read_varint<uint32_t>(stream);
     136          758 :         auto substream              = stream.sub_stream(substream_length);
     137          757 :         deserialize<detail::serialize_mode{}>(substream, message);
     138              :     }
     139              :     else
     140              :     {
     141         1194 :         deserialize<detail::serialize_mode{}>(stream, message);
     142              :     }
     143         3178 :     return size - stream.size();
     144              : }
     145              : 
     146              : /**
     147              :  * @brief deserialize message from protobuf
     148              :  *
     149              :  * @param[in] reader function for handling reads
     150              :  * @param[in] options
     151              :  * @param[out] message deserialized message
     152              :  * @throws std::runtime_error on error
     153              :  */
     154          756 : size_t deserialize(auto &message, spb::io::reader reader, const deserialize_options &options = {})
     155              : {
     156          756 :     detail::istream_reader stream{reader};
     157          756 :     if (options.delimited)
     158              :     {
     159          378 :         const auto substream_length = read_varint<uint32_t>(stream);
     160          378 :         auto substream              = stream.sub_stream(substream_length);
     161          378 :         deserialize<detail::serialize_mode{}>(substream, message);
     162              :     }
     163              :     else
     164              :     {
     165          378 :         deserialize<detail::serialize_mode{}>(stream, message);
     166              :     }
     167         1512 :     return stream.consumed_size();
     168              : }
     169              : 
     170              : /**
     171              :  * @brief deserialize message from protobuf
     172              :  *
     173              :  * @param[in] protobuf string with protobuf
     174              :  * @param[in] options
     175              :  * @param[out] message deserialized message
     176              :  * @throws std::runtime_error on error
     177              :  * @example `auto serialized = std::vector< std::byte >( ... );`
     178              :  *          `auto message = Message();`
     179              :  *          `spb::pb::deserialize( message, serialized );`
     180              :  */
     181              : template <typename Message, spb::size_container Container>
     182          756 : size_t deserialize(Message &message, const Container &protobuf, const deserialize_options &options = {})
     183              : {
     184          756 :     return deserialize(message, protobuf.data(), protobuf.size(), options);
     185              : }
     186              : 
     187              : /**
     188              :  * @brief deserialize message from protobuf
     189              :  *
     190              :  * @param[in] protobuf serialized protobuf
     191              :  * @param[in] options
     192              :  * @return deserialized message
     193              :  * @throws std::runtime_error on error
     194              :  * @example `auto serialized = std::vector< std::byte >( ... );`
     195              :  *          `auto message = spb::pb::deserialize< Message >( serialized );`
     196              :  */
     197              : template <typename Message, spb::size_container Container>
     198         1196 : [[nodiscard]] Message deserialize(const Container &protobuf, const deserialize_options &options = {})
     199              : {
     200         1162 :     auto message = Message{};
     201         1196 :     deserialize(message, protobuf.data(), protobuf.size(), options);
     202          836 :     return message;
     203          128 : }
     204              : 
     205              : /**
     206              :  * @brief deserialize message from reader
     207              :  *
     208              :  * @param[in] reader function for handling reads
     209              :  * @param[in] options
     210              :  * @return deserialized message
     211              :  * @throws std::runtime_error on error
     212              :  */
     213              : template <typename Message>
     214              : [[nodiscard]] Message deserialize(spb::io::reader reader, const deserialize_options &options = {})
     215              : {
     216              :     auto message = Message{};
     217              :     deserialize(message, reader, options);
     218              :     return message;
     219              : }
     220              : } // namespace spb::pb
        

Generated by: LCOV version 2.0-1