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 <cctype>
17 : #include <cstddef>
18 : #include <cstdint>
19 : #include <cstring>
20 : #include <map>
21 : #include <memory>
22 : #include <spb/io/io.hpp>
23 : #include <sys/types.h>
24 : #include <type_traits>
25 :
26 : namespace spb::pb::detail
27 : {
28 : struct ostream
29 : {
30 : private:
31 : size_t bytes_written = 0;
32 : spb::io::writer on_write;
33 :
34 : public:
35 : /**
36 : * @brief Construct a new ostream object
37 : *
38 : * @param writer if null, stream will skip all writes but will still count number of written
39 : * bytes
40 : */
41 1911 : explicit ostream( spb::io::writer writer = nullptr ) noexcept
42 1911 : : on_write( writer )
43 : {
44 1911 : }
45 :
46 4103 : void write( const void * p_data, size_t size ) noexcept
47 : {
48 4103 : if( on_write )
49 : {
50 1468 : on_write( p_data, size );
51 : }
52 :
53 4103 : bytes_written += size;
54 4103 : }
55 :
56 1905 : [[nodiscard]] auto size( ) const noexcept -> size_t
57 : {
58 1905 : return bytes_written;
59 : }
60 :
61 : void serialize( uint32_t field_number, const auto & value );
62 :
63 : template < scalar_encoder encoder >
64 : void serialize_as( uint32_t field_number, const auto & value );
65 : };
66 :
67 : static inline auto serialize_size( const auto & value ) -> size_t;
68 :
69 : using namespace std::literals;
70 :
71 2797 : static inline void serialize_varint( ostream & stream, uint64_t value )
72 : {
73 2797 : size_t i = 0;
74 : uint8_t buffer[ 10 ];
75 :
76 : do
77 : {
78 3316 : uint8_t byte = value & 0x7F;
79 3316 : value >>= 7;
80 3316 : byte |= value > 0 ? 0x80U : 0;
81 3316 : buffer[ i++ ] = byte;
82 3316 : } while( value > 0 );
83 :
84 2797 : return stream.write( buffer, i );
85 : }
86 190 : static inline void serialize_svarint( ostream & stream, int64_t value )
87 : {
88 190 : const auto tmp = uint64_t( ( value << 1 ) ^ ( value >> 63 ) );
89 190 : return serialize_varint( stream, tmp );
90 : }
91 :
92 1624 : static inline void serialize_tag( ostream & stream, uint32_t field_number, wire_type type )
93 : {
94 1624 : const auto tag = ( field_number << 3 ) | uint32_t( type );
95 1624 : serialize_varint( stream, tag );
96 1624 : }
97 :
98 : static inline void serialize( ostream & stream, uint32_t field_number,
99 : const spb::detail::proto_message auto & value );
100 : static inline void serialize( ostream & stream, uint32_t field_number,
101 : const spb::detail::proto_field_string auto & value );
102 : static inline void serialize( ostream & stream, uint32_t field_number,
103 : const spb::detail::proto_field_bytes auto & value );
104 : static inline void serialize( ostream & stream, uint32_t field_number,
105 : const spb::detail::proto_label_repeated auto & value );
106 :
107 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
108 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & value );
109 :
110 : template < scalar_encoder encoder, spb::detail::proto_label_repeated_fixed_size C >
111 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & value );
112 :
113 : template < scalar_encoder encoder, typename keyT, typename valueT >
114 : static inline void serialize_as( ostream & stream, uint32_t field_number,
115 : const std::map< keyT, valueT > & value );
116 :
117 : template < scalar_encoder encoder >
118 1177 : static inline void serialize_as( ostream & stream, uint32_t field_number,
119 : spb::detail::proto_field_number auto value )
120 : {
121 1177 : serialize_tag( stream, field_number, wire_type_from_scalar_encoder( encoder ) );
122 1177 : serialize_as< encoder >( stream, value );
123 1177 : }
124 :
125 : template < scalar_encoder encoder >
126 145 : static inline void serialize_as( ostream & stream, const spb::detail::proto_enum auto & value )
127 : {
128 145 : serialize_varint( stream, int32_t( value ) );
129 145 : }
130 :
131 : template < scalar_encoder encoder >
132 1642 : static inline void serialize_as( ostream & stream,
133 : spb::detail::proto_field_int_or_float auto value )
134 : {
135 : using T = std::remove_cvref_t< decltype( value ) >;
136 :
137 1642 : const auto type = scalar_encoder_type1( encoder );
138 :
139 : if constexpr( type == scalar_encoder::varint )
140 : {
141 : static_assert( std::is_integral_v< T > );
142 :
143 : if constexpr( std::is_same_v< bool, T > )
144 : {
145 80 : const uint8_t tmp = value ? 1 : 0;
146 80 : return stream.write( &tmp, 1 );
147 : }
148 : else if constexpr( std::is_signed_v< T > )
149 : {
150 : //- GPB is serializing all negative ints always as int64_t
151 277 : const auto u_value = uint64_t( int64_t( value ) );
152 277 : return serialize_varint( stream, u_value );
153 : }
154 : else
155 : {
156 110 : return serialize_varint( stream, value );
157 : }
158 : }
159 : else if constexpr( type == scalar_encoder::svarint )
160 : {
161 : static_assert( std::is_signed_v< T > && std::is_integral_v< T > );
162 :
163 190 : return serialize_svarint( stream, value );
164 : }
165 : else if constexpr( type == scalar_encoder::i32 )
166 : {
167 : if constexpr( sizeof( value ) == sizeof( uint32_t ) )
168 : {
169 275 : return stream.write( &value, sizeof( value ) );
170 : }
171 : else
172 : {
173 285 : const auto tmp = uint32_t( value );
174 285 : return stream.write( &tmp, sizeof( tmp ) );
175 : }
176 : }
177 : else if constexpr( type == scalar_encoder::i64 )
178 : {
179 : if constexpr( sizeof( value ) == sizeof( uint64_t ) )
180 : {
181 235 : return stream.write( &value, sizeof( value ) );
182 : }
183 : else
184 : {
185 190 : const auto tmp = uint64_t( value );
186 190 : return stream.write( &tmp, sizeof( tmp ) );
187 : }
188 : }
189 : }
190 :
191 161 : static inline void serialize( ostream & stream, uint32_t field_number,
192 : const spb::detail::proto_field_string auto & value )
193 : {
194 161 : if( !value.empty( ) )
195 : {
196 156 : spb::detail::utf8::validate( std::string_view( value.data( ), value.size( ) ) );
197 156 : serialize_tag( stream, field_number, wire_type::length_delimited );
198 156 : serialize_varint( stream, value.size( ) );
199 156 : stream.write( value.data( ), value.size( ) );
200 : }
201 161 : }
202 :
203 90 : static inline void serialize( ostream & stream, uint32_t field_number,
204 : const spb::detail::proto_field_bytes auto & value )
205 : {
206 90 : if( !value.empty( ) )
207 : {
208 85 : serialize_tag( stream, field_number, wire_type::length_delimited );
209 85 : serialize_varint( stream, value.size( ) );
210 85 : stream.write( value.data( ), value.size( ) );
211 : }
212 90 : }
213 :
214 : template < scalar_encoder encoder, typename keyT, typename valueT >
215 24 : static inline void serialize_as( ostream & stream, const std::map< keyT, valueT > & value )
216 : {
217 24 : const auto key_encoder = scalar_encoder_type1( encoder );
218 24 : const auto value_encoder = scalar_encoder_type2( encoder );
219 :
220 52 : for( const auto & [ k, v ] : value )
221 : {
222 : if constexpr( std::is_integral_v< keyT > )
223 : {
224 16 : serialize_as< key_encoder >( stream, 1, k );
225 : }
226 : else
227 : {
228 12 : serialize( stream, 1, k );
229 : }
230 : if constexpr( spb::detail::proto_field_number< valueT > )
231 : {
232 16 : serialize_as< value_encoder >( stream, 2, v );
233 : }
234 : else
235 : {
236 12 : serialize( stream, 2, v );
237 : }
238 : }
239 24 : }
240 :
241 : template < scalar_encoder encoder, typename keyT, typename valueT >
242 12 : static inline void serialize_as( ostream & stream, uint32_t field_number,
243 : const std::map< keyT, valueT > & value )
244 : {
245 12 : auto size_stream = ostream( );
246 12 : serialize_as< encoder >( size_stream, value );
247 12 : const auto size = size_stream.size( );
248 :
249 12 : serialize_tag( stream, field_number, wire_type::length_delimited );
250 12 : serialize_varint( stream, size );
251 12 : serialize_as< encoder >( stream, value );
252 12 : }
253 :
254 : template < scalar_encoder encoder, spb::detail::proto_label_repeated_fixed_size C >
255 20 : static inline void serialize_packed_as( ostream & stream, const C & container )
256 : {
257 200 : for( size_t i = 0; i < container.size( ); i++ )
258 : {
259 : if constexpr( std::is_same_v< typename C::value_type, bool > )
260 : {
261 : serialize_as< encoder >( stream, bool( container[ i ] ) );
262 : }
263 : else
264 : {
265 80 : serialize_as< encoder >( stream, container[ i ] );
266 : }
267 : }
268 20 : }
269 :
270 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
271 330 : static inline void serialize_packed_as( ostream & stream, const C & container )
272 : {
273 860 : for( const auto & v : container )
274 : {
275 : if constexpr( std::is_same_v< typename C::value_type, bool > )
276 : {
277 30 : serialize_as< encoder >( stream, bool( v ) );
278 : }
279 : else
280 : {
281 500 : serialize_as< encoder >( stream, v );
282 : }
283 : }
284 330 : }
285 :
286 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
287 600 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & value )
288 : {
289 : if constexpr( scalar_encoder_is_packed( encoder ) )
290 : {
291 270 : if( value.empty( ) )
292 : {
293 105 : return;
294 : }
295 :
296 165 : auto size_stream = ostream( );
297 165 : serialize_packed_as< encoder >( size_stream, value );
298 165 : const auto size = size_stream.size( );
299 :
300 165 : serialize_tag( stream, field_number, wire_type::length_delimited );
301 165 : serialize_varint( stream, size );
302 165 : serialize_packed_as< encoder >( stream, value );
303 : }
304 : else
305 : {
306 620 : for( const auto & v : value )
307 : {
308 : if constexpr( std::is_same_v< typename C::value_type, bool > )
309 : {
310 15 : serialize_as< encoder >( stream, field_number, bool( v ) );
311 : }
312 : else
313 : {
314 275 : serialize_as< encoder >( stream, field_number, v );
315 : }
316 : }
317 : }
318 330 : }
319 :
320 : template < scalar_encoder encoder, spb::detail::proto_label_repeated_fixed_size C >
321 10 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & value )
322 : {
323 : static_assert( scalar_encoder_is_packed( encoder ),
324 : "repeated field with fixed size has to have attribute 'packed'" );
325 :
326 10 : auto size_stream = ostream( );
327 10 : serialize_packed_as< encoder >( size_stream, value );
328 10 : const auto size = size_stream.size( );
329 :
330 10 : serialize_tag( stream, field_number, wire_type::length_delimited );
331 10 : serialize_varint( stream, size );
332 10 : serialize_packed_as< encoder >( stream, value );
333 10 : }
334 :
335 70 : static inline void serialize( ostream & stream, uint32_t field_number,
336 : const spb::detail::proto_label_repeated auto & value )
337 : {
338 140 : for( const auto & v : value )
339 : {
340 : if constexpr( std::is_same_v< typename std::decay_t< decltype( value ) >::value_type,
341 : bool > )
342 : {
343 : serialize_as< scalar_encoder::varint >( stream, field_number, bool( v ) );
344 : }
345 : else
346 : {
347 70 : serialize( stream, field_number, v );
348 : }
349 : }
350 70 : }
351 :
352 125 : static inline void serialize( ostream & stream, uint32_t field_number,
353 : const spb::detail::proto_label_optional auto & p_value )
354 : {
355 125 : if( p_value.has_value( ) )
356 : {
357 77 : return serialize( stream, field_number, *p_value );
358 : }
359 : }
360 :
361 : template < scalar_encoder encoder, spb::detail::proto_label_optional C >
362 280 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & p_value )
363 : {
364 280 : if( p_value.has_value( ) )
365 : {
366 235 : return serialize_as< encoder >( stream, field_number, *p_value );
367 : }
368 : }
369 :
370 : template < typename T >
371 0 : static inline void serialize( ostream & stream, uint32_t field_number,
372 : const std::unique_ptr< T > & p_value )
373 : {
374 0 : if( p_value )
375 : {
376 0 : return serialize( stream, field_number, *p_value );
377 : }
378 : }
379 :
380 19 : static inline void serialize( ostream & stream, uint32_t field_number,
381 : const spb::detail::proto_message auto & value )
382 : {
383 19 : if( const auto size = serialize_size( value ); size > 0 )
384 : {
385 19 : serialize_tag( stream, field_number, wire_type::length_delimited );
386 19 : serialize_varint( stream, size );
387 : //
388 : //- serialize is generated by the spb-protoc
389 : //
390 19 : serialize( stream, value );
391 : }
392 19 : }
393 :
394 : static inline auto serialize( const auto & value, spb::io::writer on_write ) -> size_t
395 : {
396 : auto stream = ostream( on_write );
397 : serialize( stream, value );
398 : return stream.size( );
399 : }
400 :
401 23 : static inline auto serialize_size( const auto & value ) -> size_t
402 : {
403 23 : auto stream = ostream( nullptr );
404 :
405 23 : serialize( stream, value );
406 46 : return stream.size( );
407 : }
408 :
409 294 : void ostream::serialize( uint32_t field_number, const auto & value )
410 : {
411 294 : detail::serialize( *this, field_number, value );
412 294 : }
413 :
414 : template < scalar_encoder encoder >
415 1510 : void ostream::serialize_as( uint32_t field_number, const auto & value )
416 : {
417 1510 : detail::serialize_as< encoder >( *this, field_number, value );
418 1510 : }
419 :
420 : }// namespace spb::pb::detail
|