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