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 <cstddef>
17 : #include <cstdint>
18 : #include <cstring>
19 : #include <memory>
20 : #include <spb/io/io.hpp>
21 : #include <sys/types.h>
22 : #include <type_traits>
23 :
24 : namespace spb::pb::detail
25 : {
26 : struct ostream_size
27 : {
28 : static constexpr bool size_only = true;
29 : size_t size;
30 :
31 3674 : void write(const void *, size_t data_size)
32 : {
33 3674 : size += data_size;
34 3674 : }
35 :
36 10477 : void write(uint8_t)
37 : {
38 10477 : ++size;
39 10477 : }
40 : };
41 : struct ostream_buffer
42 : {
43 : static constexpr bool size_only = false;
44 : uint8_t *p_buffer;
45 :
46 1972 : explicit ostream_buffer(void *buffer) : p_buffer((uint8_t *)buffer)
47 : {
48 1972 : }
49 :
50 4687 : void write(uint8_t byte)
51 : {
52 4687 : *p_buffer++ = byte;
53 4687 : }
54 :
55 1152 : void write(const void *data, size_t size)
56 : {
57 1152 : memcpy(p_buffer, data, size);
58 1152 : p_buffer += size;
59 1152 : }
60 : };
61 :
62 : struct ostream_writer
63 : {
64 : static constexpr bool size_only = false;
65 : spb::io::writer on_write;
66 : size_t size = 0;
67 :
68 756 : explicit ostream_writer(spb::io::writer writer) : on_write(writer)
69 : {
70 756 : }
71 :
72 2090 : void write(uint8_t byte)
73 : {
74 2090 : write(&byte, 1);
75 2090 : }
76 :
77 2648 : void write(const void *data, size_t data_size)
78 : {
79 2648 : on_write(data, data_size);
80 2648 : size += data_size;
81 2648 : }
82 : };
83 :
84 : template <serialize_mode = serialize_mode{}> size_t serialize_size(const auto &value);
85 : template <serialize_mode = serialize_mode{}> size_t serialize_size(uint32_t field, const auto &value);
86 : template <serialize_mode> void serialize(auto &stream, const spb::detail::proto_message auto &value);
87 :
88 1514 : inline size_t serialize_varint_size(uint64_t value)
89 : {
90 1514 : size_t size = 1;
91 1514 : while (value >= 0x80)
92 : {
93 0 : ++size;
94 0 : value >>= 7;
95 : }
96 1514 : return size;
97 : }
98 :
99 15467 : void serialize_varint(auto &stream, uint64_t value)
100 : {
101 17014 : while (value >= 0x80)
102 : {
103 1547 : stream.write((uint8_t)(value & 0x7F) | 0x80);
104 1547 : value >>= 7;
105 : }
106 15467 : stream.write((uint8_t)value);
107 15467 : }
108 :
109 570 : void serialize_svarint(auto &stream, int64_t value)
110 : {
111 570 : const auto tmp = uint64_t((value << 1) ^ (value >> 63));
112 570 : serialize_varint(stream, tmp);
113 570 : }
114 :
115 7429 : void serialize_tag(auto &stream, uint32_t field_number, wire_type type)
116 : {
117 7429 : const auto tag = (field_number << 3) | uint32_t(type);
118 7429 : serialize_varint(stream, tag);
119 7429 : }
120 :
121 : template <serialize_mode>
122 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_message auto &value);
123 : template <serialize_mode>
124 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_string auto &value);
125 : template <serialize_mode>
126 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_bytes auto &value);
127 : template <serialize_mode>
128 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_repeated auto &value);
129 : template <serialize_mode>
130 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_repeated_fixed_size auto &value);
131 :
132 : template <serialize_mode>
133 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_map auto &value);
134 :
135 : template <serialize_mode mode>
136 3895 : void serialize(auto &stream, uint32_t field, spb::detail::proto_field_number auto value)
137 : {
138 3895 : serialize_tag(stream, field, to_wire_type(mode.encoder));
139 3895 : serialize<mode>(stream, value);
140 3895 : }
141 :
142 435 : template <serialize_mode mode> void serialize(auto &stream, const spb::detail::proto_enum auto &value)
143 : {
144 435 : serialize_varint(stream, int32_t(value));
145 435 : }
146 :
147 5750 : template <serialize_mode mode> void serialize(auto &stream, spb::detail::proto_field_int_or_float auto value)
148 : {
149 : using T = std::remove_cvref_t<decltype(value)>;
150 :
151 5750 : constexpr auto type = encoder_type(mode.encoder);
152 : if constexpr (type == scalar_encoder::varint)
153 : {
154 : static_assert(std::is_integral_v<T>);
155 :
156 : if constexpr (std::is_same_v<bool, T>)
157 : {
158 240 : const uint8_t tmp = value ? 1 : 0;
159 240 : return stream.write(tmp);
160 : }
161 : else if constexpr (std::is_signed_v<T>)
162 : {
163 : //- GPB is serializing all negative ints always as int64_t
164 1655 : const auto u_value = uint64_t(int64_t(value));
165 1655 : return serialize_varint(stream, u_value);
166 : }
167 : else
168 : {
169 330 : return serialize_varint(stream, value);
170 : }
171 : }
172 : else if constexpr (type == scalar_encoder::svarint)
173 : {
174 : static_assert(std::is_signed_v<T> && std::is_integral_v<T>);
175 :
176 570 : return serialize_svarint(stream, value);
177 : }
178 : else if constexpr (type == scalar_encoder::i32)
179 : {
180 : if constexpr (sizeof(value) == sizeof(uint32_t))
181 : {
182 825 : return stream.write(&value, sizeof(value));
183 : }
184 : else
185 : {
186 855 : const auto tmp = uint32_t(value);
187 951 : return stream.write(&tmp, sizeof(tmp));
188 : }
189 : }
190 : else if constexpr (type == scalar_encoder::i64)
191 : {
192 : if constexpr (sizeof(value) == sizeof(uint64_t))
193 : {
194 705 : return stream.write(&value, sizeof(value));
195 : }
196 : else
197 : {
198 570 : const auto tmp = uint64_t(value);
199 634 : return stream.write(&tmp, sizeof(tmp));
200 : }
201 : }
202 : }
203 :
204 : template <serialize_mode mode>
205 60 : void serialize_packed(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &container)
206 : {
207 : static_assert(is_packed(mode.encoder), "repeated field with fixed size has to have attribute 'packed'");
208 :
209 : using ValueType = typename std::remove_cvref_t<decltype(container)>::value_type;
210 :
211 600 : for (size_t i = 0; i < container.size(); i++)
212 : {
213 : if constexpr (std::is_same_v<ValueType, bool>)
214 : serialize<mode>(stream, bool(container[i]));
215 : else
216 240 : serialize<mode>(stream, container[i]);
217 : }
218 60 : }
219 :
220 : template <serialize_mode mode>
221 30 : void serialize(auto &stream, const spb::detail::proto_label_repeated_fixed_size auto &container)
222 : {
223 30 : serialize_packed<mode>(stream, container);
224 30 : }
225 :
226 : template <serialize_mode mode>
227 1100 : void serialize_packed(auto &stream, const spb::detail::proto_label_repeated auto &container)
228 : {
229 : static_assert(is_packed(mode.encoder), "repeated field has to have attribute 'packed'");
230 :
231 : using ValueType = typename std::remove_cvref_t<decltype(container)>::value_type;
232 :
233 3150 : for (const auto &v : container)
234 : {
235 : if constexpr (std::is_same_v<ValueType, bool>)
236 90 : serialize<mode>(stream, bool(v));
237 : else
238 1960 : serialize<mode>(stream, v);
239 : }
240 1100 : }
241 :
242 : template <serialize_mode mode>
243 550 : void serialize(auto &stream, const spb::detail::proto_label_repeated auto &container)
244 : {
245 550 : serialize_packed<mode>(stream, container);
246 550 : }
247 :
248 : template <serialize_mode mode>
249 1765 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_string auto &value)
250 : {
251 : using stream_type = std::remove_cvref_t<decltype(stream)>;
252 :
253 1765 : if (value.empty())
254 15 : return;
255 :
256 : if constexpr (!stream_type::size_only && mode.max_size)
257 64 : check_size(value.size(), mode.max_size);
258 :
259 : if constexpr (!stream_type::size_only)
260 456 : spb::detail::utf8::validate(std::string_view(value.data(), value.size()));
261 :
262 1734 : serialize_tag(stream, field, wire_type::length_delimited);
263 1734 : serialize_varint(stream, value.size());
264 1734 : stream.write(value.data(), value.size());
265 : }
266 :
267 : template <serialize_mode mode>
268 726 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_field_bytes auto &value)
269 : {
270 : using stream_type = std::remove_cvref_t<decltype(stream)>;
271 :
272 726 : if (value.empty())
273 15 : return;
274 :
275 : if constexpr (!stream_type::size_only && mode.max_size)
276 64 : check_size(value.size(), mode.max_size);
277 :
278 695 : serialize_tag(stream, field, wire_type::length_delimited);
279 695 : serialize_varint(stream, value.size());
280 695 : stream.write(value.data(), value.size());
281 : }
282 :
283 : template <serialize_mode mode>
284 120 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_map auto &value)
285 : {
286 120 : if (value.empty())
287 0 : return;
288 :
289 120 : constexpr auto key_encoder = serialize_mode{.encoder = mode.encoder};
290 120 : constexpr auto value_encoder = serialize_mode{.encoder = mode.encoder2};
291 :
292 270 : for (const auto &[k, v] : value)
293 : {
294 150 : const auto size = serialize_size<key_encoder>(1, k) + serialize_size<value_encoder>(2, v);
295 150 : serialize_tag(stream, field, wire_type::length_delimited);
296 150 : serialize_varint(stream, size);
297 150 : serialize<key_encoder>(stream, 1, k);
298 150 : serialize<value_encoder>(stream, 2, v);
299 : }
300 : }
301 :
302 : template <serialize_mode mode>
303 2353 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_repeated auto &container)
304 : {
305 : using value_type = typename std::remove_cvref_t<decltype(container)>::value_type;
306 : using stream_type = std::remove_cvref_t<decltype(stream)>;
307 :
308 : if constexpr (!stream_type::size_only && mode.max_count)
309 136 : check_size(container.size(), mode.max_count);
310 :
311 : if constexpr (is_packed(mode.encoder))
312 : {
313 865 : if (container.empty())
314 315 : return;
315 :
316 550 : const auto size = serialize_size<mode>(container);
317 550 : serialize_tag(stream, field, wire_type::length_delimited);
318 550 : serialize_varint(stream, size);
319 550 : serialize_packed<mode>(stream, container);
320 : }
321 : else
322 : {
323 3594 : for (const auto &value : container)
324 : {
325 : if constexpr (std::is_same_v<value_type, bool>)
326 45 : serialize<mode>(stream, field, bool(value));
327 : else
328 2095 : serialize<mode>(stream, field, value);
329 : }
330 : }
331 1454 : }
332 :
333 : template <serialize_mode mode>
334 30 : void serialize(auto &stream, uint32_t field,
335 : const spb::detail::proto_label_repeated_fixed_size auto &container)
336 : {
337 : static_assert(is_packed(mode.encoder), "repeated field with fixed size has to have attribute 'packed'");
338 :
339 30 : const auto size = serialize_size<mode>(container);
340 30 : serialize_tag(stream, field, wire_type::length_delimited);
341 30 : serialize_varint(stream, size);
342 30 : serialize_packed<mode>(stream, container);
343 30 : }
344 :
345 : template <serialize_mode mode>
346 1977 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_label_optional auto &p_value)
347 : {
348 1977 : if (p_value.has_value())
349 1722 : serialize<mode>(stream, field, *p_value);
350 1961 : }
351 :
352 : template <serialize_mode mode, typename T>
353 : void serialize(auto &stream, uint32_t field, const std::unique_ptr<T> &p_value)
354 : {
355 : if (p_value)
356 : serialize<mode>(stream, field, *p_value);
357 : }
358 :
359 : template <serialize_mode mode>
360 375 : void serialize(auto &stream, uint32_t field, const spb::detail::proto_message auto &value)
361 : {
362 375 : const auto size = serialize_size<mode>(value);
363 375 : if (!size) [[unlikely]]
364 0 : return;
365 :
366 375 : serialize_tag(stream, field, wire_type::length_delimited);
367 375 : serialize_varint(stream, size);
368 375 : serialize_value(stream, value);
369 : }
370 :
371 4439 : template <serialize_mode mode> auto serialize_size(const auto &value) -> size_t
372 : {
373 4439 : auto stream = ostream_size();
374 4439 : serialize<mode>(stream, value);
375 4439 : return stream.size;
376 : }
377 :
378 300 : template <serialize_mode mode> auto serialize_size(uint32_t field, const auto &value) -> size_t
379 : {
380 300 : auto stream = ostream_size();
381 300 : serialize<mode>(stream, field, value);
382 300 : return stream.size;
383 : }
384 :
385 3859 : template <serialize_mode mode> void serialize(auto &stream, const spb::detail::proto_message auto &value)
386 : {
387 3859 : serialize_value(stream, value);
388 3859 : }
389 :
390 : } // namespace spb::pb::detail
|