LCOV - code coverage report
Current view: top level - spb - pb.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.6 % 41 40
Test Date: 2025-05-23 14:18:13 Functions: 99.9 % 1409 1407

            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 <cstdlib>
      17              : 
      18              : namespace spb::pb
      19              : {
      20              : 
      21              : struct serialize_options
      22              : {
      23              :     /**
      24              :      * @brief Writes the size of the message (as a varint) before the message itself.
      25              :      *        Compatible with Google's `writeDelimitedTo` and NanoPb's PB_ENCODE_DELIMITED.
      26              :      */
      27              :     bool delimited = false;
      28              : };
      29              : 
      30              : struct deserialize_options
      31              : {
      32              :     /**
      33              :      * @brief Expect the size of the message (encoded as a varint) to come before the message
      34              :      * itself. Compatible with Google's `parseDelimitedFrom` and NanoPb's PB_DECODE_DELIMITED. Will
      35              :      * return after having read the specified length; the spb::io::reader object can then be read
      36              :      * from again to get the next message (if any).
      37              :      */
      38              :     bool delimited = false;
      39              : };
      40              : 
      41              : /**
      42              :  * @brief serialize message via writer
      43              :  *
      44              :  * @param[in] message to be serialized
      45              :  * @param[in] on_write function for handling the writes
      46              :  * @param[in] options
      47              :  * @return serialized size in bytes
      48              :  * @throws exceptions only from `on_write`
      49              :  */
      50         1674 : static inline auto serialize( const auto & message, spb::io::writer on_write,
      51              :                               const serialize_options & options = { } ) -> size_t
      52              : {
      53         1674 :     auto stream = detail::ostream{ on_write };
      54         1674 :     if( options.delimited )
      55              :     {
      56            4 :         detail::serialize_varint( stream, detail::serialize_size( message ) );
      57              :     }
      58         1674 :     serialize( stream, message );
      59         3348 :     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         1004 : [[nodiscard]] static inline auto serialize_size( const auto & message,
      70              :                                                  const serialize_options & options = { } ) -> size_t
      71              : {
      72         1004 :     return serialize( message, spb::io::writer( nullptr ), options );
      73              : }
      74              : 
      75              : /**
      76              :  * @brief serialize message into protobuf
      77              :  *
      78              :  * @param[in] message to be serialized
      79              :  * @param[in] options
      80              :  * @param[out] result serialized protobuf
      81              :  * @return serialized size in bytes
      82              :  * @throws std::runtime_error on error
      83              :  * @example `auto serialized = std::vector< std::byte >();`
      84              :  *          `spb::pb::serialize( message, serialized );`
      85              :  */
      86              : template < typename Message, spb::resizable_container Container >
      87          670 : static inline auto serialize( const Message & message, Container & result,
      88              :                               const serialize_options & options = { } ) -> size_t
      89              : {
      90          670 :     const auto size = serialize_size( message, options );
      91          670 :     result.resize( size );
      92         2054 :     auto writer = [ ptr = result.data( ) ]( const void * data, size_t size ) mutable
      93              :     {
      94         1384 :         memcpy( ptr, data, size );
      95         1384 :         ptr += size;
      96              :     };
      97              : 
      98          670 :     serialize( message, writer, options );
      99          670 :     return size;
     100              : }
     101              : 
     102              : /**
     103              :  * @brief serialize message into protobuf
     104              :  *
     105              :  * @param[in] message to be serialized
     106              :  * @param[in] options
     107              :  * @return serialized protobuf
     108              :  * @throws std::runtime_error on error
     109              :  * @example `auto serialized_message = spb::pb::serialize< std::vector< std::byte > >( message );`
     110              :  */
     111              : template < spb::resizable_container Container = std::string, typename Message >
     112          670 : [[nodiscard]] static inline auto serialize( const Message & message,
     113              :                                             const serialize_options & options = { } ) -> Container
     114              : {
     115          670 :     auto result = Container( );
     116          670 :     serialize< Message, Container >( message, result, options );
     117          670 :     return result;
     118            0 : }
     119              : 
     120              : /**
     121              :  * @brief deserialize message from protobuf
     122              :  *
     123              :  * @param[in] reader function for handling reads
     124              :  * @param[in] options
     125              :  * @param[out] message deserialized message
     126              :  * @throws std::runtime_error on error
     127              :  */
     128         1034 : static inline void deserialize( auto & message, spb::io::reader reader,
     129              :                                 const deserialize_options & options = { } )
     130              : {
     131         1034 :     detail::istream stream{ reader };
     132         1034 :     if( options.delimited )
     133              :     {
     134            2 :         const auto substream_length = read_varint< uint32_t >( stream );
     135            2 :         auto substream              = stream.sub_stream( substream_length );
     136            2 :         return deserialize_main( substream, message );
     137              :     }
     138              :     else
     139              :     {
     140         1032 :         return deserialize_main( stream, message );
     141              :     }
     142              : }
     143              : 
     144              : /**
     145              :  * @brief deserialize message from protobuf
     146              :  *
     147              :  * @param[in] protobuf string with protobuf
     148              :  * @param[in] options
     149              :  * @param[out] message deserialized message
     150              :  * @throws std::runtime_error on error
     151              :  * @example `auto serialized = std::vector< std::byte >( ... );`
     152              :  *          `auto message = Message();`
     153              :  *          `spb::pb::deserialize( message, serialized );`
     154              :  */
     155              : template < typename Message, spb::size_container Container >
     156         1034 : static inline void deserialize( Message & message, const Container & protobuf,
     157              :                                 const deserialize_options & options = { } )
     158              : {
     159         4602 :     auto reader = [ ptr = protobuf.data( ), end = protobuf.data( ) + protobuf.size( ) ](
     160              :                       void * data, size_t size ) mutable -> size_t
     161              :     {
     162         3568 :         size_t bytes_left = end - ptr;
     163              : 
     164         3568 :         size = std::min( size, bytes_left );
     165         3568 :         memcpy( data, ptr, size );
     166         3568 :         ptr += size;
     167         3568 :         return size;
     168              :     };
     169         1779 :     return deserialize( message, reader, options );
     170              : }
     171              : 
     172              : /**
     173              :  * @brief deserialize message from protobuf
     174              :  *
     175              :  * @param[in] protobuf serialized protobuf
     176              :  * @param[in] options
     177              :  * @return deserialized message
     178              :  * @throws std::runtime_error on error
     179              :  * @example `auto serialized = std::vector< std::byte >( ... );`
     180              :  *          `auto message = spb::pb::deserialize< Message >( serialized );`
     181              :  */
     182              : template < typename Message, spb::size_container Container >
     183          700 : [[nodiscard]] static inline auto deserialize( const Container & protobuf,
     184              :                                               const deserialize_options & options = { } ) -> Message
     185              : {
     186          666 :     auto message = Message{ };
     187          700 :     deserialize( message, protobuf, options );
     188          414 :     return message;
     189           62 : }
     190              : 
     191              : /**
     192              :  * @brief deserialize message from reader
     193              :  *
     194              :  * @param[in] reader function for handling reads
     195              :  * @param[in] options
     196              :  * @return deserialized message
     197              :  * @throws std::runtime_error on error
     198              :  */
     199              : template < typename Message >
     200              : [[nodiscard]] static inline auto deserialize( spb::io::reader reader,
     201              :                                               const deserialize_options & options = { } ) -> Message
     202              : {
     203              :     auto message = Message{ };
     204              :     deserialize( message, reader, options );
     205              :     return message;
     206              : }
     207              : 
     208              : }// namespace spb::pb
        

Generated by: LCOV version 2.0-1