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 <memory>
20 : #include <cstring>
21 : #include <map>
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 1881 : explicit ostream( spb::io::writer writer = nullptr ) noexcept
42 1881 : : on_write( writer )
43 : {
44 1881 : }
45 :
46 3953 : void write( const void * p_data, size_t size ) noexcept
47 : {
48 3953 : if( on_write )
49 : {
50 1432 : on_write( p_data, size );
51 : }
52 :
53 3953 : bytes_written += size;
54 3953 : }
55 :
56 1875 : [[nodiscard]] auto size( ) const noexcept -> size_t
57 : {
58 1875 : 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 2697 : static inline void serialize_varint( ostream & stream, uint64_t value )
72 : {
73 2697 : size_t i = 0;
74 : uint8_t buffer[ 10 ];
75 :
76 : do
77 : {
78 3216 : uint8_t byte = value & 0x7F;
79 3216 : value >>= 7;
80 3216 : byte |= value > 0 ? 0x80U : 0;
81 3216 : buffer[ i++ ] = byte;
82 3216 : } while( value > 0 );
83 :
84 2697 : 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 1589 : static inline void serialize_tag( ostream & stream, uint32_t field_number, wire_type type )
93 : {
94 1589 : const auto tag = ( field_number << 3 ) | uint32_t( type );
95 1589 : serialize_varint( stream, tag );
96 1589 : }
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, typename keyT, typename valueT >
111 : static inline void serialize_as( ostream & stream, uint32_t field_number,
112 : const std::map< keyT, valueT > & value );
113 :
114 : template < scalar_encoder encoder >
115 1157 : static inline void serialize_as( ostream & stream, uint32_t field_number,
116 : spb::detail::proto_field_number auto value )
117 : {
118 1157 : serialize_tag( stream, field_number, wire_type_from_scalar_encoder( encoder ) );
119 1157 : serialize_as< encoder >( stream, value );
120 1157 : }
121 :
122 : template < scalar_encoder encoder >
123 145 : static inline void serialize_as( ostream & stream, const spb::detail::proto_enum auto & value )
124 : {
125 145 : serialize_varint( stream, int32_t( value ) );
126 145 : }
127 :
128 : template < scalar_encoder encoder >
129 1542 : static inline void serialize_as( ostream & stream,
130 : spb::detail::proto_field_int_or_float auto value )
131 : {
132 : using T = std::remove_cvref_t< decltype( value ) >;
133 :
134 1542 : const auto type = scalar_encoder_type1( encoder );
135 :
136 : if constexpr( type == scalar_encoder::varint )
137 : {
138 : static_assert( std::is_integral_v< T > );
139 :
140 : if constexpr( std::is_same_v< bool, T > )
141 : {
142 70 : const uint8_t tmp = value ? 1 : 0;
143 70 : return stream.write( &tmp, 1 );
144 : }
145 : else if constexpr( std::is_signed_v< T > )
146 : {
147 : //- GPB is serializing all negative ints always as int64_t
148 227 : const auto u_value = uint64_t( int64_t( value ) );
149 227 : return serialize_varint( stream, u_value );
150 : }
151 : else
152 : {
153 110 : return serialize_varint( stream, value );
154 : }
155 : }
156 : else if constexpr( type == scalar_encoder::svarint )
157 : {
158 : static_assert( std::is_signed_v< T > && std::is_integral_v< T > );
159 :
160 190 : return serialize_svarint( stream, value );
161 : }
162 : else if constexpr( type == scalar_encoder::i32 )
163 : {
164 : if constexpr( sizeof( value ) == sizeof( uint32_t ) )
165 : {
166 235 : return stream.write( &value, sizeof( value ) );
167 : }
168 : else
169 : {
170 285 : const auto tmp = uint32_t( value );
171 285 : return stream.write( &tmp, sizeof( tmp ) );
172 : }
173 : }
174 : else if constexpr( type == scalar_encoder::i64 )
175 : {
176 : if constexpr( sizeof( value ) == sizeof( uint64_t ) )
177 : {
178 235 : return stream.write( &value, sizeof( value ) );
179 : }
180 : else
181 : {
182 190 : const auto tmp = uint64_t( value );
183 190 : return stream.write( &tmp, sizeof( tmp ) );
184 : }
185 : }
186 : }
187 :
188 161 : static inline void serialize( ostream & stream, uint32_t field_number,
189 : const spb::detail::proto_field_string auto & value )
190 : {
191 161 : if( !value.empty( ) )
192 : {
193 156 : spb::detail::utf8::validate( std::string_view( value.data( ), value.size( ) ) );
194 156 : serialize_tag( stream, field_number, wire_type::length_delimited );
195 156 : serialize_varint( stream, value.size( ) );
196 156 : stream.write( value.data( ), value.size( ) );
197 : }
198 161 : }
199 :
200 90 : static inline void serialize( ostream & stream, uint32_t field_number,
201 : const spb::detail::proto_field_bytes auto & value )
202 : {
203 90 : if( !value.empty( ) )
204 : {
205 85 : serialize_tag( stream, field_number, wire_type::length_delimited );
206 85 : serialize_varint( stream, value.size( ) );
207 85 : stream.write( value.data( ), value.size( ) );
208 : }
209 90 : }
210 :
211 : template < scalar_encoder encoder, typename keyT, typename valueT >
212 24 : static inline void serialize_as( ostream & stream, const std::map< keyT, valueT > & value )
213 : {
214 24 : const auto key_encoder = scalar_encoder_type1( encoder );
215 24 : const auto value_encoder = scalar_encoder_type2( encoder );
216 :
217 52 : for( const auto & [ k, v ] : value )
218 : {
219 : if constexpr( std::is_integral_v< keyT > )
220 : {
221 16 : serialize_as< key_encoder >( stream, 1, k );
222 : }
223 : else
224 : {
225 12 : serialize( stream, 1, k );
226 : }
227 : if constexpr( spb::detail::proto_field_number< valueT > )
228 : {
229 16 : serialize_as< value_encoder >( stream, 2, v );
230 : }
231 : else
232 : {
233 12 : serialize( stream, 2, v );
234 : }
235 : }
236 24 : }
237 :
238 : template < scalar_encoder encoder, typename keyT, typename valueT >
239 12 : static inline void serialize_as( ostream & stream, uint32_t field_number,
240 : const std::map< keyT, valueT > & value )
241 : {
242 12 : auto size_stream = ostream( );
243 12 : serialize_as< encoder >( size_stream, value );
244 12 : const auto size = size_stream.size( );
245 :
246 12 : serialize_tag( stream, field_number, wire_type::length_delimited );
247 12 : serialize_varint( stream, size );
248 12 : serialize_as< encoder >( stream, value );
249 12 : }
250 :
251 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
252 330 : static inline void serialize_packed_as( ostream & stream, const C & container )
253 : {
254 860 : for( const auto & v : container )
255 : {
256 : if constexpr( std::is_same_v< typename C::value_type, bool > )
257 : {
258 30 : serialize_as< encoder >( stream, bool( v ) );
259 : }
260 : else
261 : {
262 500 : serialize_as< encoder >( stream, v );
263 : }
264 : }
265 330 : }
266 :
267 : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
268 590 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & value )
269 : {
270 : if constexpr( scalar_encoder_is_packed( encoder ) )
271 : {
272 270 : if( value.empty( ) )
273 : {
274 105 : return;
275 : }
276 :
277 165 : auto size_stream = ostream( );
278 165 : serialize_packed_as< encoder >( size_stream, value );
279 165 : const auto size = size_stream.size( );
280 :
281 165 : serialize_tag( stream, field_number, wire_type::length_delimited );
282 165 : serialize_varint( stream, size );
283 165 : serialize_packed_as< encoder >( stream, value );
284 : }
285 : else
286 : {
287 610 : for( const auto & v : value )
288 : {
289 : if constexpr( std::is_same_v< typename C::value_type, bool > )
290 : {
291 15 : serialize_as< encoder >( stream, field_number, bool( v ) );
292 : }
293 : else
294 : {
295 275 : serialize_as< encoder >( stream, field_number, v );
296 : }
297 : }
298 : }
299 320 : }
300 :
301 70 : static inline void serialize( ostream & stream, uint32_t field_number,
302 : const spb::detail::proto_label_repeated auto & value )
303 : {
304 140 : for( const auto & v : value )
305 : {
306 : if constexpr( std::is_same_v< typename std::decay_t< decltype( value ) >::value_type,
307 : bool > )
308 : {
309 : serialize_as< scalar_encoder::varint >( stream, field_number, bool( v ) );
310 : }
311 : else
312 : {
313 70 : serialize( stream, field_number, v );
314 : }
315 : }
316 70 : }
317 :
318 120 : static inline void serialize( ostream & stream, uint32_t field_number,
319 : const spb::detail::proto_label_optional auto & p_value )
320 : {
321 120 : if( p_value.has_value( ) )
322 : {
323 72 : return serialize( stream, field_number, *p_value );
324 : }
325 : }
326 :
327 : template < scalar_encoder encoder, spb::detail::proto_label_optional C >
328 265 : static inline void serialize_as( ostream & stream, uint32_t field_number, const C & p_value )
329 : {
330 265 : if( p_value.has_value( ) )
331 : {
332 225 : return serialize_as< encoder >( stream, field_number, *p_value );
333 : }
334 : }
335 :
336 : template < typename T >
337 0 : static inline void serialize( ostream & stream, uint32_t field_number,
338 : const std::unique_ptr< T > & p_value )
339 : {
340 0 : if( p_value )
341 : {
342 0 : return serialize( stream, field_number, *p_value );
343 : }
344 : }
345 :
346 14 : static inline void serialize( ostream & stream, uint32_t field_number,
347 : const spb::detail::proto_message auto & value )
348 : {
349 14 : if( const auto size = serialize_size( value ); size > 0 )
350 : {
351 14 : serialize_tag( stream, field_number, wire_type::length_delimited );
352 14 : serialize_varint( stream, size );
353 : //
354 : //- serialize is generated by the spb-protoc
355 : //
356 14 : serialize( stream, value );
357 : }
358 14 : }
359 :
360 : static inline auto serialize( const auto & value, spb::io::writer on_write ) -> size_t
361 : {
362 : auto stream = ostream( on_write );
363 : serialize( stream, value );
364 : return stream.size( );
365 : }
366 :
367 18 : static inline auto serialize_size( const auto & value ) -> size_t
368 : {
369 18 : auto stream = ostream( nullptr );
370 :
371 18 : serialize( stream, value );
372 36 : return stream.size( );
373 : }
374 :
375 289 : void ostream::serialize( uint32_t field_number, const auto & value )
376 : {
377 289 : detail::serialize( *this, field_number, value );
378 289 : }
379 :
380 : template < scalar_encoder encoder >
381 1465 : void ostream::serialize_as( uint32_t field_number, const auto & value )
382 : {
383 1465 : detail::serialize_as< encoder >( *this, field_number, value );
384 1465 : }
385 :
386 : }// namespace spb::pb::detail
|