EmbeddedProto 4.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. EmbeddedProto/EmbeddedProto.py +122 -0
  2. EmbeddedProto/Features.py +255 -0
  3. EmbeddedProto/Field.py +1295 -0
  4. EmbeddedProto/Oneof.py +74 -0
  5. EmbeddedProto/ProtoFile.py +210 -0
  6. EmbeddedProto/TypeDefinitions.py +367 -0
  7. EmbeddedProto/__init__.py +0 -0
  8. EmbeddedProto/__main__.py +28 -0
  9. EmbeddedProto/config.py +173 -0
  10. EmbeddedProto/custom_header.py +513 -0
  11. EmbeddedProto/embedded_proto_options.proto +62 -0
  12. EmbeddedProto/embedded_proto_options_pb2.py +37 -0
  13. EmbeddedProto/field_options.py +344 -0
  14. EmbeddedProto/main.py +316 -0
  15. EmbeddedProto/src/EmbeddedProto/BytesStringCallback.h +476 -0
  16. EmbeddedProto/src/EmbeddedProto/Defines.h +118 -0
  17. EmbeddedProto/src/EmbeddedProto/EmptyArray.h +81 -0
  18. EmbeddedProto/src/EmbeddedProto/Errors.h +53 -0
  19. EmbeddedProto/src/EmbeddedProto/FieldStringBytes.h +793 -0
  20. EmbeddedProto/src/EmbeddedProto/Fields.h +832 -0
  21. EmbeddedProto/src/EmbeddedProto/Functional.h +412 -0
  22. EmbeddedProto/src/EmbeddedProto/MessageCallback.h +688 -0
  23. EmbeddedProto/src/EmbeddedProto/MessageInterface.h +792 -0
  24. EmbeddedProto/src/EmbeddedProto/MessageSizeCalculator.h +109 -0
  25. EmbeddedProto/src/EmbeddedProto/MessageState.h +207 -0
  26. EmbeddedProto/src/EmbeddedProto/ReadBufferFixedSize.h +204 -0
  27. EmbeddedProto/src/EmbeddedProto/ReadBufferInterface.h +181 -0
  28. EmbeddedProto/src/EmbeddedProto/ReadBufferSection.h +232 -0
  29. EmbeddedProto/src/EmbeddedProto/RepeatedField.h +1053 -0
  30. EmbeddedProto/src/EmbeddedProto/RepeatedFieldCallback.h +432 -0
  31. EmbeddedProto/src/EmbeddedProto/RepeatedFieldFixedSize.h +367 -0
  32. EmbeddedProto/src/EmbeddedProto/Version.h +39 -0
  33. EmbeddedProto/src/EmbeddedProto/WireFormatter.h +852 -0
  34. EmbeddedProto/src/EmbeddedProto/WriteBufferFixedSize.h +114 -0
  35. EmbeddedProto/src/EmbeddedProto/WriteBufferInterface.h +134 -0
  36. EmbeddedProto/src/EmbeddedProto.h +55 -0
  37. EmbeddedProto/templates/FieldBasic_Deserialize.h.jinja2 +26 -0
  38. EmbeddedProto/templates/FieldBasic_GetSet.h.jinja2 +89 -0
  39. EmbeddedProto/templates/FieldBytes_GetSet.h.jinja2 +86 -0
  40. EmbeddedProto/templates/FieldEnum_Deserialize.h.jinja2 +50 -0
  41. EmbeddedProto/templates/FieldEnum_GetSet.h.jinja2 +93 -0
  42. EmbeddedProto/templates/FieldErrorRecursive_GetSet.h.jinja2 +29 -0
  43. EmbeddedProto/templates/FieldMap_GetSet.h.jinja2 +203 -0
  44. EmbeddedProto/templates/FieldMsg_Deserialize.h.jinja2 +44 -0
  45. EmbeddedProto/templates/FieldMsg_GetSet.h.jinja2 +93 -0
  46. EmbeddedProto/templates/FieldRepeated_GetSet.h.jinja2 +94 -0
  47. EmbeddedProto/templates/FieldString_GetSet.h.jinja2 +86 -0
  48. EmbeddedProto/templates/Field_DeserializePartial.h.jinja2 +33 -0
  49. EmbeddedProto/templates/Field_Serialize.h.jinja2 +112 -0
  50. EmbeddedProto/templates/Field_SerializePartial.h.jinja2 +119 -0
  51. EmbeddedProto/templates/Header.h.jinja2 +108 -0
  52. EmbeddedProto/templates/TypeDefEnum.h.jinja2 +45 -0
  53. EmbeddedProto/templates/TypeDefMsg.h.jinja2 +791 -0
  54. EmbeddedProto/templates/TypeOneof.h.jinja2 +178 -0
  55. EmbeddedProto/version.json +3 -0
  56. embeddedproto-4.0.0b1.dist-info/METADATA +141 -0
  57. embeddedproto-4.0.0b1.dist-info/RECORD +63 -0
  58. embeddedproto-4.0.0b1.dist-info/WHEEL +5 -0
  59. embeddedproto-4.0.0b1.dist-info/entry_points.txt +3 -0
  60. embeddedproto-4.0.0b1.dist-info/licenses/LICENSE +30 -0
  61. embeddedproto-4.0.0b1.dist-info/licenses/LICENSES/GPL-3.0-only.txt +674 -0
  62. embeddedproto-4.0.0b1.dist-info/licenses/LICENSES/LicenseRef-EmbeddedProto-Commercial.txt +12 -0
  63. embeddedproto-4.0.0b1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,852 @@
1
+ /*
2
+ * Copyright (C) 2020-2026 Embedded AMS B.V. - All Rights Reserved
3
+ *
4
+ * This file is part of Embedded Proto.
5
+ *
6
+ * Embedded Proto is dual licensed. You may use it under the terms of the
7
+ * GNU General Public License version 3 (GPLv3) as published by the Free
8
+ * Software Foundation, or under a commercial license from Embedded AMS B.V.
9
+ *
10
+ * Under the GPLv3 you must release the source code of
11
+ * any product you distribute that includes Embedded Proto or code
12
+ * generated by it. A commercial license removes that obligation.
13
+ * See <https://embeddedproto.com/pricing/>.
14
+ *
15
+ * Embedded Proto is distributed WITHOUT ANY WARRANTY; without even the
16
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
+ * See the LICENSE file in the root of the repository for details.
18
+ *
19
+ * SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-EmbeddedProto-Commercial
20
+ *
21
+ * Embedded AMS B.V., Hoorn, the Netherlands - info at EmbeddedProto dot com
22
+ */
23
+
24
+ #ifndef _WIRE_FORMATTER_H_
25
+ #define _WIRE_FORMATTER_H_
26
+
27
+ #include "Defines.h"
28
+ #include "WriteBufferInterface.h"
29
+ #include "ReadBufferInterface.h"
30
+ #include "Errors.h"
31
+
32
+ #include <array>
33
+ #include <cstdint>
34
+ #include <cstring>
35
+ #include <math.h>
36
+ #include <type_traits>
37
+ #include <limits>
38
+ #include <type_traits>
39
+
40
+ //! Determine whether the target stores multi-byte scalars little-endian.
41
+ /*!
42
+ Protobuf fixed-width fields (fixed32/fixed64/sfixed/float/double) are
43
+ little-endian on the wire, which matches the in-memory representation on a
44
+ little-endian target. When that holds a packed payload can be copied to the
45
+ buffer in a single block; otherwise every value is emitted byte-by-byte so
46
+ the on-wire order stays little-endian. Define EMBEDDED_PROTO_LITTLE_ENDIAN
47
+ yourself (to 0 or 1) to override the automatic detection.
48
+ */
49
+ #if !defined(EMBEDDED_PROTO_LITTLE_ENDIAN)
50
+ #if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \
51
+ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \
52
+ || defined(_WIN32) || defined(_M_IX86) || defined(_M_X64) \
53
+ || defined(_M_ARM) || defined(_M_ARM64)
54
+ #define EMBEDDED_PROTO_LITTLE_ENDIAN 1
55
+ #else
56
+ #define EMBEDDED_PROTO_LITTLE_ENDIAN 0
57
+ #endif
58
+ #endif
59
+
60
+ namespace EmbeddedProto
61
+ {
62
+
63
+ //! This class combines functions to serialize and deserialize messages.
64
+ class WireFormatter
65
+ {
66
+
67
+ //! Definition of the number of bits it takes to serialize a byte of a varint.
68
+ static constexpr uint8_t VARINT_SHIFT_N_BITS = 7;
69
+
70
+ //! Definition of a mask indicating the most significant bit used in varint encoding.
71
+ static constexpr uint8_t VARINT_MSB_BYTE = 0x80;
72
+
73
+ //! Convert the floating point number to the next highes integer.
74
+ /*!
75
+ The ceil function in std is not a constexpr. Some compilers doe not accept this.
76
+
77
+ \param num The value you would like ot convert.
78
+ \return The resulting integer.
79
+ */
80
+ static constexpr int32_t constexpr_ceil(float num)
81
+ {
82
+ return (static_cast<float>(static_cast<int32_t>(num)) == num)
83
+ ? static_cast<int32_t>(num)
84
+ : static_cast<int32_t>(num) + ((num > 0) ? 1 : 0);
85
+ }
86
+
87
+ public:
88
+ //! The largest number of bytes a varint can take, that of a 64-bit value.
89
+ static constexpr uint32_t VARINT_MAX_N_BYTES = 10;
90
+
91
+ //! Definitions of the different encoding types used in protobuf.
92
+ enum class WireType
93
+ {
94
+ VARINT = 0, //!< int32, int64, uint32, uint64, sint32, sint64, bool, enum.
95
+ FIXED64 = 1, //!< fixed64, sfixed64, double
96
+ LENGTH_DELIMITED = 2, //!< string, bytes, embedded messages, packed repeated fields
97
+ START_GROUP = 3, //!< Deprecated
98
+ END_GROUP = 4, //!< Deprecated
99
+ FIXED32 = 5, //!< fixed32, sfixed32, float
100
+ };
101
+
102
+ //! Calculate the number of bytes a varint value will take.
103
+ /*!
104
+ \param[in] value The value of which to calculate the size.
105
+ \return The number of bytes required for serializing the varint.
106
+ */
107
+ static constexpr uint32_t VarintSize(const uint64_t value)
108
+ {
109
+ return (value < (1ULL << 7)) ? 1 :
110
+ (value < (1ULL << 14)) ? 2 :
111
+ (value < (1ULL << 21)) ? 3 :
112
+ (value < (1ULL << 28)) ? 4 :
113
+ (value < (1ULL << 35)) ? 5 :
114
+ (value < (1ULL << 42)) ? 6 :
115
+ (value < (1ULL << 49)) ? 7 :
116
+ (value < (1ULL << 56)) ? 8 :
117
+ (value < (1ULL << 63)) ? 9 : 10;
118
+ }
119
+
120
+ //! Encode a signed integer using the zig zag method
121
+ /*!
122
+ As specified the right-shift must be arithmetic, hence the cast is after the shift. The
123
+ left shift must be unsigned because of overflow.
124
+
125
+ This function is suitable for 32 and 64 bit.
126
+
127
+ \param[in] n The signed value to be encoded.
128
+ \return The zig zag transformed value ready for serialization into the array.
129
+ */
130
+ template<class INT_TYPE>
131
+ static constexpr typename std::make_unsigned<INT_TYPE>::type ZigZagEncode(const INT_TYPE n)
132
+ {
133
+ static_assert(std::is_same<INT_TYPE, int32_t>::value ||
134
+ std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to ZigZagEncode.");
135
+
136
+ using UINT_TYPE = typename std::make_unsigned<INT_TYPE>::type;
137
+ // Prior to reverting back to C++11 we had defined:
138
+ // constexpr uint8_t N_BITS_TO_ZIGZAG = std::numeric_limits<UINT_TYPE>::digits - 1;
139
+ return (static_cast<UINT_TYPE>(n) << 1) ^ static_cast<UINT_TYPE>(n >> (std::numeric_limits<UINT_TYPE>::digits - 1));
140
+ }
141
+
142
+ //! Decode a signed integer using the zig zag method
143
+ /*!
144
+ \param[in] n The value encoded in zig zag to be decoded.
145
+ \return The decoded signed value.
146
+
147
+ This function is suitable for 32 and 64 bit.
148
+ */
149
+ template<class UINT_TYPE>
150
+ static constexpr typename std::make_signed<UINT_TYPE>::type ZigZagDecode(const UINT_TYPE n)
151
+ {
152
+ static_assert(std::is_same<UINT_TYPE, uint32_t>::value ||
153
+ std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to ZigZagDecode.");
154
+
155
+ using INT_TYPE = typename std::make_signed<UINT_TYPE>::type;
156
+
157
+ return static_cast<INT_TYPE>((n >> 1) ^ (~(n & 1) + 1));
158
+ }
159
+
160
+ //! Create the tag of a field.
161
+ /*!
162
+ This is the combination of the field number and wire type of the field. The field number is
163
+ shifted to the left by three bits. This creates space to or the wire type of the designated
164
+ field.
165
+ */
166
+ static constexpr uint32_t MakeTag(const uint32_t field_number, const WireType type)
167
+ {
168
+ return ((field_number << 3) | static_cast<uint32_t>(type));
169
+ }
170
+
171
+ /**
172
+ @brief Serialize fields, without tags the given buffer.
173
+ @{
174
+ **/
175
+
176
+ //! Serialize an unsigned fixed length field without the tag.
177
+ template<class UINT_TYPE>
178
+ static Error SerializeFixedNoTag(const UINT_TYPE value, WriteBufferInterface& buffer)
179
+ {
180
+ static_assert(std::is_same<UINT_TYPE, uint32_t>::value ||
181
+ std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to SerializeFixedNoTag.");
182
+
183
+ // Push the data little endian to the buffer.
184
+ bool result = true;
185
+
186
+ #if EMBEDDED_PROTO_LITTLE_ENDIAN
187
+ // The in-memory bytes already are the wire order, push them as one block.
188
+ result = buffer.push(const_bytes_view{reinterpret_cast<const uint8_t*>(&value),
189
+ static_cast<uint32_t>(sizeof(UINT_TYPE))});
190
+ #else
191
+ // Build the little-endian wire bytes locally and push them as one block, so the
192
+ // write is all-or-nothing just like on a little-endian target.
193
+ std::array<uint8_t, sizeof(UINT_TYPE)> bytes = {0};
194
+ for(uint32_t i = 0; i < static_cast<uint32_t>(sizeof(UINT_TYPE)); ++i)
195
+ {
196
+ bytes[i] = static_cast<uint8_t>((value >> (i * 8U)) & 0x00FFU);
197
+ }
198
+ result = buffer.push(const_bytes_view{bytes.data(), static_cast<uint32_t>(bytes.size())});
199
+ #endif
200
+ return result ? Error::NO_ERRORS : Error::BUFFER_FULL;
201
+ }
202
+
203
+ //! Serialize a signed fixed length field without the tag.
204
+ template<class INT_TYPE>
205
+ static Error SerialzieSFixedNoTag(const INT_TYPE value, WriteBufferInterface& buffer)
206
+ {
207
+ static_assert(std::is_same<INT_TYPE, int32_t>::value ||
208
+ std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to SerialzieSFixedNoTag.");
209
+
210
+ using UINT_TYPE = typename std::make_unsigned<INT_TYPE>::type;
211
+
212
+ return SerializeFixedNoTag(static_cast<UINT_TYPE>(value), buffer);
213
+ }
214
+
215
+ //! Serialize a 32bit real value without tag.
216
+ static Error SerialzieFloatNoTag(const float value, WriteBufferInterface& buffer)
217
+ {
218
+ // Cast the type to void and to a 32 fixed number
219
+ const auto* pVoid = static_cast<const void*>(&value);
220
+ const auto* fixed = static_cast<const uint32_t*>(pVoid);
221
+ return SerializeFixedNoTag(*fixed, buffer);
222
+ }
223
+
224
+ //! Serialize a 64bit real value without tag.
225
+ static Error SerialzieDoubleNoTag(const double value, WriteBufferInterface& buffer)
226
+ {
227
+ // Cast the type to void and to a 64 fixed number
228
+ const auto* pVoid = static_cast<const void*>(&value);
229
+ const auto* fixed = static_cast<const uint64_t*>(pVoid);
230
+ return SerializeFixedNoTag(*fixed, buffer);
231
+ }
232
+
233
+ //! Serialize a contiguous array of fixed-width scalar values without tags.
234
+ /*!
235
+ Writes `count` values, each `sizeof(VAR_TYPE)` bytes wide, little-endian
236
+ on the wire (protobuf packed fixed32/fixed64 layout). On a little-endian
237
+ target the whole block is copied to the buffer with a single
238
+ push(const_bytes_view) call. On a big-endian target every value is byte
239
+ swapped into a local array and pushed as one block, so the on-wire order
240
+ stays little-endian and each value is still written all-or-nothing.
241
+
242
+ This is used to batch packed repeated fixed32/sfixed32/float and
243
+ fixed64/sfixed64/double fields into as few buffer writes as possible.
244
+
245
+ \param[in] data A view on the values to serialize.
246
+ \param[in] buffer The buffer to write to.
247
+ \return NO_ERRORS on success, BUFFER_FULL when the buffer ran out of space.
248
+ */
249
+ template<class VAR_TYPE>
250
+ static Error SerializeFixedArrayNoTag(const array_view<const VAR_TYPE>& data,
251
+ WriteBufferInterface& buffer)
252
+ {
253
+ static_assert((4U == sizeof(VAR_TYPE)) || (8U == sizeof(VAR_TYPE)),
254
+ "SerializeFixedArrayNoTag only supports 32 and 64 bit values.");
255
+
256
+ #if EMBEDDED_PROTO_LITTLE_ENDIAN
257
+ // The in-memory representation already equals the little-endian wire
258
+ // format, so the whole block can be pushed in one call.
259
+ const auto* const raw = reinterpret_cast<const uint8_t*>(data.data);
260
+ const uint32_t n_bytes = data.size * static_cast<uint32_t>(sizeof(VAR_TYPE));
261
+ return buffer.push(const_bytes_view{raw, n_bytes}) ? Error::NO_ERRORS : Error::BUFFER_FULL;
262
+ #else
263
+ // Big-endian fallback: every value is pushed as one little-endian block.
264
+ using UINT_TYPE = typename std::conditional<4U == sizeof(VAR_TYPE),
265
+ uint32_t, uint64_t>::type;
266
+ Error return_value = Error::NO_ERRORS;
267
+ for(uint32_t i = 0; (i < data.size) && (Error::NO_ERRORS == return_value); ++i)
268
+ {
269
+ UINT_TYPE bits = 0;
270
+ memcpy(&bits, reinterpret_cast<const uint8_t*>(data.data) + (i * sizeof(VAR_TYPE)),
271
+ sizeof(VAR_TYPE));
272
+ return_value = SerializeFixedNoTag(bits, buffer);
273
+ }
274
+ return return_value;
275
+ #endif
276
+ }
277
+
278
+ //! Serialize a contiguous array of fixed-width scalar values, pointer and count form.
279
+ /*!
280
+ Pointer and count form of SerializeFixedArrayNoTag(const array_view<const VAR_TYPE>&, WriteBufferInterface&).
281
+
282
+ \deprecated Use the array_view overload, a view keeps the pointer and its bound together.
283
+ \param[in] data Pointer to the first value.
284
+ \param[in] count The number of values to serialize.
285
+ \param[in] buffer The buffer to write to.
286
+ \return NO_ERRORS on success, BUFFER_FULL when the buffer ran out of space.
287
+ */
288
+ template<class VAR_TYPE>
289
+ [[deprecated("use the array_view overload SerializeFixedArrayNoTag(const array_view<const VAR_TYPE>&, WriteBufferInterface&)")]]
290
+ static Error SerializeFixedArrayNoTag(const VAR_TYPE* data, const uint32_t count,
291
+ WriteBufferInterface& buffer)
292
+ {
293
+ return SerializeFixedArrayNoTag(array_view<const VAR_TYPE>{data, count}, buffer);
294
+ }
295
+ /** @} **/
296
+
297
+
298
+ /**
299
+ @brief Serialize fields, including tags to the given buffer.
300
+ @{
301
+ **/
302
+ template<class INT_TYPE>
303
+ static Error SerializeInt(const uint32_t field_number, const INT_TYPE value,
304
+ WriteBufferInterface& buffer)
305
+ {
306
+ using UINT_TYPE = typename std::make_unsigned<INT_TYPE>::type;
307
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::VARINT), buffer);
308
+ if(Error::NO_ERRORS == return_value)
309
+ {
310
+ return_value = SerializeVarint(static_cast<UINT_TYPE>(value), buffer);
311
+ }
312
+ return return_value;
313
+ }
314
+
315
+ template<class UINT_TYPE>
316
+ static Error SerializeUInt(const uint32_t field_number, const UINT_TYPE value,
317
+ WriteBufferInterface& buffer)
318
+ {
319
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::VARINT), buffer);
320
+ if(Error::NO_ERRORS == return_value)
321
+ {
322
+ return_value = SerializeVarint(value, buffer);
323
+ }
324
+ return return_value;
325
+ }
326
+
327
+ template<class INT_TYPE>
328
+ static Error SerializeSInt(const uint32_t field_number, const INT_TYPE value,
329
+ WriteBufferInterface& buffer)
330
+ {
331
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::VARINT), buffer);
332
+ if(Error::NO_ERRORS == return_value)
333
+ {
334
+ return_value = SerializeVarint(ZigZagEncode(value), buffer);
335
+ }
336
+ return return_value;
337
+ }
338
+
339
+ static Error SerializeFixed(const uint32_t field_number, const uint32_t value,
340
+ WriteBufferInterface& buffer)
341
+ {
342
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::FIXED32), buffer);
343
+ if(Error::NO_ERRORS == return_value)
344
+ {
345
+ return_value = SerializeFixedNoTag(value, buffer);
346
+ }
347
+ return return_value;
348
+ }
349
+
350
+ static Error SerializeFixed(const uint32_t field_number, const uint64_t value,
351
+ WriteBufferInterface& buffer)
352
+ {
353
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::FIXED64), buffer);
354
+ if(Error::NO_ERRORS == return_value)
355
+ {
356
+ return_value = SerializeFixedNoTag(value, buffer);
357
+ }
358
+ return return_value;
359
+ }
360
+
361
+ static Error SerializeSFixed(const uint32_t field_number, const int32_t value,
362
+ WriteBufferInterface& buffer)
363
+ {
364
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::FIXED32), buffer);
365
+ if(Error::NO_ERRORS == return_value)
366
+ {
367
+ return_value = SerialzieSFixedNoTag(value, buffer);
368
+ }
369
+ return return_value;
370
+ }
371
+
372
+ static Error SerializeSFixed(const uint32_t field_number, const int64_t value,
373
+ WriteBufferInterface& buffer)
374
+ {
375
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::FIXED64), buffer);
376
+ if(Error::NO_ERRORS == return_value)
377
+ {
378
+ return_value = SerialzieSFixedNoTag(value, buffer);
379
+ }
380
+ return return_value;
381
+ }
382
+
383
+ static Error SerializeFloat(const uint32_t field_number, const float value,
384
+ WriteBufferInterface& buffer)
385
+ {
386
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::FIXED32), buffer);
387
+ if(Error::NO_ERRORS == return_value)
388
+ {
389
+ return_value = SerialzieFloatNoTag(value, buffer);
390
+ }
391
+ return return_value;
392
+ }
393
+
394
+ static Error SerializeDouble(const uint32_t field_number, const double value,
395
+ WriteBufferInterface& buffer)
396
+ {
397
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::FIXED64), buffer);
398
+ if(Error::NO_ERRORS == return_value)
399
+ {
400
+ return_value = SerialzieDoubleNoTag(value, buffer);
401
+ }
402
+ return return_value;
403
+ }
404
+
405
+ static Error SerializeBool(const uint32_t field_number, const bool value,
406
+ WriteBufferInterface& buffer)
407
+ {
408
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::VARINT), buffer);
409
+ if(Error::NO_ERRORS == return_value)
410
+ {
411
+ const uint8_t byte = value ? 0x01 : 0x00;
412
+ return_value = buffer.push(byte) ? Error::NO_ERRORS : Error::BUFFER_FULL;
413
+ }
414
+ return return_value;
415
+ }
416
+
417
+ static Error SerializeEnum(const uint32_t field_number, const uint32_t value,
418
+ WriteBufferInterface& buffer)
419
+ {
420
+ Error return_value = SerializeVarint(MakeTag(field_number, WireType::VARINT), buffer);
421
+ if(Error::NO_ERRORS == return_value)
422
+ {
423
+ return_value = SerializeVarint(value, buffer);
424
+ }
425
+ return return_value;
426
+ }
427
+
428
+ /** @} **/
429
+
430
+ /**
431
+ @brief Deserialize fields from the given buffer.
432
+ @{
433
+ **/
434
+
435
+ //! Read from the buffer the next wiretype and field id.
436
+ /*!
437
+ \param[in] buffer The data source from which to read the type and id.
438
+ \param[out] type This parameter returns the wiretype of the next field in the data buffer.
439
+ \param[out] id This parameter returns the next field id.
440
+ \return A value from the EmbeddedProto::Error enum indicating if the process succeeded.
441
+ */
442
+ static Error DeserializeTag(ReadBufferInterface& buffer, WireType& type, uint32_t& id)
443
+ {
444
+ uint32_t temp_value;
445
+ // Read the next varint considered to be a tag.
446
+ Error return_value = DeserializeVarint(buffer, temp_value);
447
+
448
+ if(Error::NO_ERRORS == return_value)
449
+ {
450
+ // Next check the validity of the wire type.
451
+ if((temp_value & 0x07) <= static_cast<uint32_t>(WireType::FIXED32))
452
+ {
453
+ // If reading the tag succeeded and the wire type is a valid one.
454
+ type = static_cast<WireType>(temp_value & 0x07);
455
+ id = (temp_value >> 3);
456
+ }
457
+ else
458
+ {
459
+ return_value = Error::INVALID_WIRETYPE;
460
+ }
461
+ }
462
+ return return_value;
463
+ }
464
+
465
+ template<class UINT_TYPE>
466
+ static Error DeserializeUInt(ReadBufferInterface& buffer, UINT_TYPE& value)
467
+ {
468
+ static_assert(std::is_same<UINT_TYPE, uint32_t>::value ||
469
+ std::is_same<UINT_TYPE, uint64_t>::value, "Wrong type passed to DeserializeUInt.");
470
+
471
+ return DeserializeVarint(buffer, value);
472
+ }
473
+
474
+ template<class INT_TYPE>
475
+ static Error DeserializeInt(ReadBufferInterface& buffer, INT_TYPE& value)
476
+ {
477
+ static_assert(std::is_same<INT_TYPE, int32_t>::value ||
478
+ std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to DeserializeInt.");
479
+
480
+ // Use a 64 value even for 32 bit as some implementations serialize 32 bit values with 10 bytes.
481
+ uint64_t uint_value64;
482
+
483
+ Error result = DeserializeVarint(buffer, uint_value64);
484
+ if(Error::NO_ERRORS == result)
485
+ {
486
+ value = static_cast<INT_TYPE>(uint_value64);
487
+ }
488
+ return result;
489
+ }
490
+
491
+ template<class INT_TYPE>
492
+ static Error DeserializeSInt(ReadBufferInterface& buffer, INT_TYPE& value)
493
+ {
494
+ static_assert(std::is_same<INT_TYPE, int32_t>::value ||
495
+ std::is_same<INT_TYPE, int64_t>::value, "Wrong type passed to DeserializeSInt.");
496
+
497
+ // Use a 64 value even for 32 bit as some implementations serialize 32 bit values with 10 bytes.
498
+ uint64_t uint_value64;
499
+
500
+ Error result = DeserializeVarint(buffer, uint_value64);
501
+ if(Error::NO_ERRORS == result)
502
+ {
503
+ using UINT_TYPE = typename std::make_unsigned<INT_TYPE>::type;
504
+ const auto uint_value = static_cast<UINT_TYPE>(uint_value64);
505
+ value = ZigZagDecode(uint_value);
506
+ }
507
+ return result;
508
+ }
509
+
510
+ template<class TYPE>
511
+ static Error DeserializeFixed(ReadBufferInterface& buffer, TYPE& value)
512
+ {
513
+ static_assert(std::is_same<TYPE, uint32_t>::value ||
514
+ std::is_same<TYPE, uint64_t>::value, "Wrong type passed to DeserializeFixed.");
515
+
516
+ // Pop the little endian wire bytes as one block. The pop is all-or-nothing, a
517
+ // buffer holding only part of the value is left untouched.
518
+ std::array<uint8_t, sizeof(TYPE)> bytes = {0};
519
+ Error return_value = Error::END_OF_BUFFER;
520
+ if(buffer.pop(bytes_view{bytes.data(), static_cast<uint32_t>(bytes.size())}))
521
+ {
522
+ TYPE temp_value = 0;
523
+ for(uint32_t i = 0U; i < static_cast<uint32_t>(bytes.size()); ++i)
524
+ {
525
+ temp_value |= (static_cast<TYPE>(bytes[i]) << (i * 8U));
526
+ }
527
+ value = temp_value;
528
+ return_value = Error::NO_ERRORS;
529
+ }
530
+
531
+ return return_value;
532
+ }
533
+
534
+ template<class STYPE>
535
+ static Error DeserializeSFixed(ReadBufferInterface& buffer, STYPE& value)
536
+ {
537
+ static_assert(std::is_same<STYPE, int32_t>::value ||
538
+ std::is_same<STYPE, int64_t>::value, "Wrong type passed to DeserializeSFixed.");
539
+
540
+ using USTYPE = typename std::make_unsigned<STYPE>::type;
541
+ USTYPE temp_unsigned_value = 0;
542
+ Error result = DeserializeFixed(buffer, temp_unsigned_value);
543
+ if(Error::NO_ERRORS == result)
544
+ {
545
+ value = static_cast<STYPE>(temp_unsigned_value);
546
+ }
547
+
548
+ return result;
549
+ }
550
+
551
+ static Error DeserializeFloat(ReadBufferInterface& buffer, float& value)
552
+ {
553
+ uint32_t temp_value = 0;
554
+ Error result = DeserializeFixed(buffer, temp_value);
555
+ if(Error::NO_ERRORS == result)
556
+ {
557
+ // Cast from unsigned int to a float.
558
+ const auto* pVoid = static_cast<const void*>(&temp_value);
559
+ const auto* pFloat = static_cast<const float*>(pVoid);
560
+ value = *pFloat;
561
+ }
562
+ return result;
563
+ }
564
+
565
+ static Error DeserializeDouble(ReadBufferInterface& buffer, double& value)
566
+ {
567
+ uint64_t temp_value = 0;
568
+ Error result = DeserializeFixed(buffer, temp_value);
569
+ if(Error::NO_ERRORS == result)
570
+ {
571
+ // Cast from unsigned int to a double.
572
+ const auto* pVoid = static_cast<const void*>(&temp_value);
573
+ const auto* pDouble = static_cast<const double*>(pVoid);
574
+ value = *pDouble;
575
+ }
576
+ return result;
577
+ }
578
+
579
+ //! Deserialize a contiguous array of fixed-width scalar values without tags.
580
+ /*!
581
+ Reads `count` values, each `sizeof(VAR_TYPE)` bytes wide, from the packed
582
+ little-endian on-wire layout (protobuf fixed32/fixed64). On a
583
+ little-endian target the whole block is copied out of the buffer with a
584
+ single pop(bytes_view) call. On a big-endian target every value is
585
+ read individually so the little-endian wire order is honoured.
586
+
587
+ The operation is all-or-nothing: when the buffer holds fewer than
588
+ `count * sizeof(VAR_TYPE)` bytes nothing is consumed and END_OF_BUFFER is
589
+ returned, mirroring DeserializeFixed(). This is the receive-side
590
+ counterpart of SerializeFixedArrayNoTag() and is used to batch packed
591
+ repeated fixed-width fields into as few buffer reads as possible.
592
+
593
+ \param[out] dest A view on the values to fill.
594
+ \param[in] buffer The buffer to read from.
595
+ \return NO_ERRORS on success, END_OF_BUFFER when too few bytes are available.
596
+ */
597
+ template<class VAR_TYPE>
598
+ static Error DeserializeFixedArrayNoTag(const array_view<VAR_TYPE>& dest,
599
+ ReadBufferInterface& buffer)
600
+ {
601
+ static_assert((4U == sizeof(VAR_TYPE)) || (8U == sizeof(VAR_TYPE)),
602
+ "DeserializeFixedArrayNoTag only supports 32 and 64 bit values.");
603
+
604
+ #if EMBEDDED_PROTO_LITTLE_ENDIAN
605
+ // The little-endian wire layout equals the in-memory representation, so
606
+ // the whole block can be popped in one call.
607
+ auto* const raw = reinterpret_cast<uint8_t*>(dest.data);
608
+ const uint32_t n_bytes = dest.size * static_cast<uint32_t>(sizeof(VAR_TYPE));
609
+ return buffer.pop(bytes_view{raw, n_bytes}) ? Error::NO_ERRORS : Error::END_OF_BUFFER;
610
+ #else
611
+ // Big-endian fallback: read every value from its little-endian byte order.
612
+ using UINT_TYPE = typename std::conditional<4U == sizeof(VAR_TYPE),
613
+ uint32_t, uint64_t>::type;
614
+ Error return_value = Error::NO_ERRORS;
615
+ for(uint32_t i = 0; (i < dest.size) && (Error::NO_ERRORS == return_value); ++i)
616
+ {
617
+ UINT_TYPE bits = 0;
618
+ return_value = DeserializeFixed(buffer, bits);
619
+ if(Error::NO_ERRORS == return_value)
620
+ {
621
+ memcpy(dest.data + i, &bits, sizeof(VAR_TYPE));
622
+ }
623
+ }
624
+ return return_value;
625
+ #endif
626
+ }
627
+
628
+ //! Deserialize a contiguous array of fixed-width scalar values, pointer and count form.
629
+ /*!
630
+ Pointer and count form of DeserializeFixedArrayNoTag(const array_view<VAR_TYPE>&, ReadBufferInterface&).
631
+
632
+ \deprecated Use the array_view overload, a view keeps the pointer and its bound together.
633
+ \param[out] dest Pointer to the first value to fill.
634
+ \param[in] count The number of values to deserialize.
635
+ \param[in] buffer The buffer to read from.
636
+ \return NO_ERRORS on success, END_OF_BUFFER when too few bytes are available.
637
+ */
638
+ template<class VAR_TYPE>
639
+ [[deprecated("use the array_view overload DeserializeFixedArrayNoTag(const array_view<VAR_TYPE>&, ReadBufferInterface&)")]]
640
+ static Error DeserializeFixedArrayNoTag(VAR_TYPE* dest, const uint32_t count,
641
+ ReadBufferInterface& buffer)
642
+ {
643
+ return DeserializeFixedArrayNoTag(array_view<VAR_TYPE>{dest, count}, buffer);
644
+ }
645
+
646
+ static Error DeserializeBool(ReadBufferInterface& buffer, bool& value)
647
+ {
648
+ uint8_t byte;
649
+ Error result = Error::NO_ERRORS;
650
+ if(buffer.peek(byte))
651
+ {
652
+ value = static_cast<bool>(byte);
653
+ buffer.advance();
654
+ }
655
+ else
656
+ {
657
+ result = Error::END_OF_BUFFER;
658
+ }
659
+ return result;
660
+ }
661
+
662
+ template<class ENUM_TYPE>
663
+ static Error DeserializeEnum(ReadBufferInterface& buffer, ENUM_TYPE& value)
664
+ {
665
+ static_assert(std::is_enum<ENUM_TYPE>::value, "No enum given to DeserializeEnum parameter value.");
666
+ uint64_t temp_value;
667
+ Error result = DeserializeVarint(buffer, temp_value);
668
+ if(Error::NO_ERRORS == result)
669
+ {
670
+ value = static_cast<ENUM_TYPE>(temp_value);
671
+ }
672
+ return result;
673
+ }
674
+
675
+
676
+ /** @} **/
677
+
678
+
679
+ //! Encode an unsigned integer as a varint into a local array instead of a buffer.
680
+ /*!
681
+ The caller can push the bytes as one block afterwards. The packed partial
682
+ serialization path relies on this to write an element all-or-nothing, so a
683
+ varint that does not fit is never written half and retried in full later.
684
+
685
+ \param[in] value The value to encode, a 32-bit value is zero extended.
686
+ \param[out] bytes The array receiving the encoded bytes.
687
+ \return The number of bytes used in the array, one up to VARINT_MAX_N_BYTES.
688
+ */
689
+ static uint32_t EncodeVarint(uint64_t value, std::array<uint8_t, VARINT_MAX_N_BYTES>& bytes)
690
+ {
691
+ uint32_t n_bytes = 0U;
692
+ while(value >= VARINT_MSB_BYTE)
693
+ {
694
+ bytes[n_bytes] = static_cast<uint8_t>(value | VARINT_MSB_BYTE);
695
+ value >>= VARINT_SHIFT_N_BITS;
696
+ ++n_bytes;
697
+ }
698
+ bytes[n_bytes] = static_cast<uint8_t>(value);
699
+ ++n_bytes;
700
+ return n_bytes;
701
+ }
702
+
703
+ //! Decode one varint from a local array instead of a buffer.
704
+ /*!
705
+ The counterpart of EncodeVarint(): a caller which peeked a block of bytes out of a
706
+ buffer decodes the varints in it one after the other and advances the buffer by
707
+ the bytes they took. The decoding rules are those of DeserializeVarint().
708
+
709
+ \param[in] bytes The bytes to decode, the varint starts at the first one.
710
+ \param[out] value The decoded value, uint32_t or uint64_t, only set when NO_ERRORS is returned.
711
+ \param[out] n_used The number of bytes the varint took, zero when the array ended before it closed.
712
+ \return NO_ERRORS, END_OF_BUFFER when the array ends inside the varint, or OVERLONG_VARINT
713
+ when it is still open after the largest number of bytes the type allows.
714
+ */
715
+ template<class UINT_TYPE>
716
+ static Error DecodeVarint(const const_bytes_view& bytes, UINT_TYPE& value, uint32_t& n_used)
717
+ {
718
+ static_assert(std::is_same<UINT_TYPE, uint32_t>::value ||
719
+ std::is_same<UINT_TYPE, uint64_t>::value,
720
+ "Wrong type passed to DecodeVarint.");
721
+
722
+ // Calculate how many bytes there are in a varint 128 base encoded number. This should
723
+ // yield 5 for a 32bit number and 10 for a 64bit number.
724
+ constexpr auto N_DIGITS = std::numeric_limits<UINT_TYPE>::digits;
725
+ constexpr auto N_BITS_FLOAT = static_cast<float>(VARINT_SHIFT_N_BITS);
726
+ constexpr auto DIV_RESULT = N_DIGITS / N_BITS_FLOAT;
727
+ constexpr auto DIV_CEIL = constexpr_ceil(DIV_RESULT);
728
+ constexpr auto N_BYTES_IN_VARINT = static_cast<uint32_t>(DIV_CEIL);
729
+
730
+ const uint32_t n_available = EmbeddedProto::min(N_BYTES_IN_VARINT, bytes.size);
731
+ UINT_TYPE temp_value = 0;
732
+ uint8_t byte = VARINT_MSB_BYTE;
733
+ uint32_t i = 0;
734
+ while((0U != (byte & VARINT_MSB_BYTE)) && (i < n_available))
735
+ {
736
+ byte = bytes.data[i];
737
+ temp_value |= static_cast<UINT_TYPE>(byte & (~VARINT_MSB_BYTE)) << (i * VARINT_SHIFT_N_BITS);
738
+ ++i;
739
+ }
740
+
741
+ Error return_value = Error::END_OF_BUFFER;
742
+ n_used = 0U;
743
+ if(0U == (byte & VARINT_MSB_BYTE))
744
+ {
745
+ // The closing byte was found.
746
+ value = temp_value;
747
+ n_used = i;
748
+ return_value = Error::NO_ERRORS;
749
+ }
750
+ else if(N_BYTES_IN_VARINT == i)
751
+ {
752
+ // Still open after the largest number of bytes the type allows, the bytes are used up.
753
+ n_used = i;
754
+ return_value = Error::OVERLONG_VARINT;
755
+ }
756
+ else
757
+ {
758
+ // The array ended before the varint closed.
759
+ }
760
+
761
+ return return_value;
762
+ }
763
+
764
+ //! This function converts a given value unsigned integer to a varint formatted data buffer.
765
+ /*!
766
+ \param[in] value The data to be serialized, uint32_t or uint64_t.
767
+ \param[in] buffer A reference to a message buffer object in which to store the variable.
768
+ \return A value from the Error enum, NO_ERROR in case everything is fine.
769
+ */
770
+ template<class UINT_TYPE>
771
+ static Error SerializeVarint(UINT_TYPE value, WriteBufferInterface& buffer)
772
+ {
773
+ static_assert(std::is_same<UINT_TYPE, uint32_t>::value ||
774
+ std::is_same<UINT_TYPE, uint64_t>::value,
775
+ "Wrong type passed to SerializeVarint.");
776
+
777
+ bool memory_free = true;
778
+ while((value >= VARINT_MSB_BYTE) && memory_free)
779
+ {
780
+ memory_free = buffer.push(static_cast<uint8_t>(value | VARINT_MSB_BYTE));
781
+ value >>= VARINT_SHIFT_N_BITS;
782
+ }
783
+ memory_free = buffer.push(static_cast<uint8_t>(value));
784
+
785
+ const Error return_value = memory_free ? Error::NO_ERRORS : Error::BUFFER_FULL;
786
+ return return_value;
787
+ }
788
+
789
+ //! This function deserializes the following N bytes into a varint.
790
+ /*!
791
+ \param[in] buffer The data buffer from which bytes are popped.
792
+ \param[out] value The variable in which the varint is returned.
793
+ \return A value from the Error enum, NO_ERROR in case everything is fine.
794
+ */
795
+ template<class UINT_TYPE>
796
+ static Error DeserializeVarint(ReadBufferInterface& buffer, UINT_TYPE& value)
797
+ {
798
+ static_assert(std::is_same<UINT_TYPE, uint32_t>::value ||
799
+ std::is_same<UINT_TYPE, uint64_t>::value,
800
+ "Wrong type passed to DeserializeVarint.");
801
+
802
+ // Calculate how many bytes there are in a varint 128 base encoded number. This should
803
+ // yield 5 for a 32bit number and 10 for a 64bit number.
804
+ constexpr auto N_DIGITS = std::numeric_limits<UINT_TYPE>::digits;
805
+ constexpr auto N_BITS_FLOAT = static_cast<float>(VARINT_SHIFT_N_BITS);
806
+ constexpr auto DIV_RESULT = N_DIGITS / N_BITS_FLOAT;
807
+ constexpr auto DIV_CEIL = constexpr_ceil(DIV_RESULT);
808
+ constexpr auto N_BYTES_IN_VARINT = static_cast<uint8_t>(DIV_CEIL);
809
+
810
+ UINT_TYPE temp_value = 0;
811
+ uint8_t byte = 0;
812
+ uint8_t i = 0;
813
+ bool result = false;
814
+ do
815
+ {
816
+ result = buffer.peek(i, byte);
817
+ if(result)
818
+ {
819
+ temp_value |= static_cast<UINT_TYPE>(byte & (~VARINT_MSB_BYTE)) << (i * VARINT_SHIFT_N_BITS);
820
+ }
821
+ ++i;
822
+ } while((byte & VARINT_MSB_BYTE) && (i < N_BYTES_IN_VARINT) && result);
823
+
824
+ Error return_value = Error::NO_ERRORS;
825
+ if(result)
826
+ {
827
+ if(byte & VARINT_MSB_BYTE)
828
+ {
829
+ // This varint was not closed properly.
830
+ return_value = Error::OVERLONG_VARINT;
831
+ }
832
+ else
833
+ {
834
+ // All is well.
835
+ value = temp_value;
836
+ }
837
+ // In any case advance the buffer.
838
+ buffer.advance(i);
839
+ }
840
+ else
841
+ {
842
+ return_value = Error::END_OF_BUFFER;
843
+ }
844
+
845
+ return return_value;
846
+ }
847
+
848
+
849
+ };
850
+
851
+ } // End of namespace EmbeddedProto.
852
+ #endif