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