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.
- EmbeddedProto/EmbeddedProto.py +122 -0
- EmbeddedProto/Features.py +255 -0
- EmbeddedProto/Field.py +1295 -0
- EmbeddedProto/Oneof.py +74 -0
- EmbeddedProto/ProtoFile.py +210 -0
- EmbeddedProto/TypeDefinitions.py +367 -0
- EmbeddedProto/__init__.py +0 -0
- EmbeddedProto/__main__.py +28 -0
- EmbeddedProto/config.py +173 -0
- EmbeddedProto/custom_header.py +513 -0
- EmbeddedProto/embedded_proto_options.proto +62 -0
- EmbeddedProto/embedded_proto_options_pb2.py +37 -0
- EmbeddedProto/field_options.py +344 -0
- EmbeddedProto/main.py +316 -0
- EmbeddedProto/src/EmbeddedProto/BytesStringCallback.h +476 -0
- EmbeddedProto/src/EmbeddedProto/Defines.h +118 -0
- EmbeddedProto/src/EmbeddedProto/EmptyArray.h +81 -0
- EmbeddedProto/src/EmbeddedProto/Errors.h +53 -0
- EmbeddedProto/src/EmbeddedProto/FieldStringBytes.h +793 -0
- EmbeddedProto/src/EmbeddedProto/Fields.h +832 -0
- EmbeddedProto/src/EmbeddedProto/Functional.h +412 -0
- EmbeddedProto/src/EmbeddedProto/MessageCallback.h +688 -0
- EmbeddedProto/src/EmbeddedProto/MessageInterface.h +792 -0
- EmbeddedProto/src/EmbeddedProto/MessageSizeCalculator.h +109 -0
- EmbeddedProto/src/EmbeddedProto/MessageState.h +207 -0
- EmbeddedProto/src/EmbeddedProto/ReadBufferFixedSize.h +204 -0
- EmbeddedProto/src/EmbeddedProto/ReadBufferInterface.h +181 -0
- EmbeddedProto/src/EmbeddedProto/ReadBufferSection.h +232 -0
- EmbeddedProto/src/EmbeddedProto/RepeatedField.h +1053 -0
- EmbeddedProto/src/EmbeddedProto/RepeatedFieldCallback.h +432 -0
- EmbeddedProto/src/EmbeddedProto/RepeatedFieldFixedSize.h +367 -0
- EmbeddedProto/src/EmbeddedProto/Version.h +39 -0
- EmbeddedProto/src/EmbeddedProto/WireFormatter.h +852 -0
- EmbeddedProto/src/EmbeddedProto/WriteBufferFixedSize.h +114 -0
- EmbeddedProto/src/EmbeddedProto/WriteBufferInterface.h +134 -0
- EmbeddedProto/src/EmbeddedProto.h +55 -0
- EmbeddedProto/templates/FieldBasic_Deserialize.h.jinja2 +26 -0
- EmbeddedProto/templates/FieldBasic_GetSet.h.jinja2 +89 -0
- EmbeddedProto/templates/FieldBytes_GetSet.h.jinja2 +86 -0
- EmbeddedProto/templates/FieldEnum_Deserialize.h.jinja2 +50 -0
- EmbeddedProto/templates/FieldEnum_GetSet.h.jinja2 +93 -0
- EmbeddedProto/templates/FieldErrorRecursive_GetSet.h.jinja2 +29 -0
- EmbeddedProto/templates/FieldMap_GetSet.h.jinja2 +203 -0
- EmbeddedProto/templates/FieldMsg_Deserialize.h.jinja2 +44 -0
- EmbeddedProto/templates/FieldMsg_GetSet.h.jinja2 +93 -0
- EmbeddedProto/templates/FieldRepeated_GetSet.h.jinja2 +94 -0
- EmbeddedProto/templates/FieldString_GetSet.h.jinja2 +86 -0
- EmbeddedProto/templates/Field_DeserializePartial.h.jinja2 +33 -0
- EmbeddedProto/templates/Field_Serialize.h.jinja2 +112 -0
- EmbeddedProto/templates/Field_SerializePartial.h.jinja2 +119 -0
- EmbeddedProto/templates/Header.h.jinja2 +108 -0
- EmbeddedProto/templates/TypeDefEnum.h.jinja2 +45 -0
- EmbeddedProto/templates/TypeDefMsg.h.jinja2 +791 -0
- EmbeddedProto/templates/TypeOneof.h.jinja2 +178 -0
- EmbeddedProto/version.json +3 -0
- embeddedproto-4.0.0b1.dist-info/METADATA +141 -0
- embeddedproto-4.0.0b1.dist-info/RECORD +63 -0
- embeddedproto-4.0.0b1.dist-info/WHEEL +5 -0
- embeddedproto-4.0.0b1.dist-info/entry_points.txt +3 -0
- embeddedproto-4.0.0b1.dist-info/licenses/LICENSE +30 -0
- embeddedproto-4.0.0b1.dist-info/licenses/LICENSES/GPL-3.0-only.txt +674 -0
- embeddedproto-4.0.0b1.dist-info/licenses/LICENSES/LicenseRef-EmbeddedProto-Commercial.txt +12 -0
- embeddedproto-4.0.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1053 @@
|
|
|
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 _REPEATED_FIELD_H_
|
|
25
|
+
#define _REPEATED_FIELD_H_
|
|
26
|
+
|
|
27
|
+
#include "Defines.h"
|
|
28
|
+
#include "Fields.h"
|
|
29
|
+
#include "MessageInterface.h"
|
|
30
|
+
#include "MessageSizeCalculator.h"
|
|
31
|
+
#include "ReadBufferSection.h"
|
|
32
|
+
#include "FieldStringBytes.h"
|
|
33
|
+
#include "Errors.h"
|
|
34
|
+
|
|
35
|
+
#include <array>
|
|
36
|
+
#include <cstdint>
|
|
37
|
+
#include <type_traits>
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
namespace EmbeddedProto
|
|
41
|
+
{
|
|
42
|
+
|
|
43
|
+
namespace internal
|
|
44
|
+
{
|
|
45
|
+
//! Trait describing whether DATA_TYPE is a packed fixed-width scalar field.
|
|
46
|
+
/*!
|
|
47
|
+
Fixed-width scalar fields (fixed32/sfixed32/float and
|
|
48
|
+
fixed64/sfixed64/double) use the FIXED32 or FIXED64 wire type and store
|
|
49
|
+
their value in little-endian layout on a little-endian target. The trait
|
|
50
|
+
exposes both the detection flag and the raw scalar type so the packed
|
|
51
|
+
serialization paths can batch these values into whole-block / per-element
|
|
52
|
+
buffer writes. For any other type the primary template reports false.
|
|
53
|
+
*/
|
|
54
|
+
template<typename T>
|
|
55
|
+
struct PackedFixedTraits
|
|
56
|
+
{
|
|
57
|
+
static constexpr bool is_fixed_width = false;
|
|
58
|
+
using scalar_type = uint8_t;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
template<Field::FieldTypes F, typename V, WireFormatter::WireType W, uint32_t S>
|
|
62
|
+
struct PackedFixedTraits<::EmbeddedProto::FieldTemplate<F, V, W, S>>
|
|
63
|
+
{
|
|
64
|
+
static constexpr bool is_fixed_width =
|
|
65
|
+
(::EmbeddedProto::WireFormatter::WireType::FIXED32 == W)
|
|
66
|
+
|| (::EmbeddedProto::WireFormatter::WireType::FIXED64 == W);
|
|
67
|
+
using scalar_type = V;
|
|
68
|
+
};
|
|
69
|
+
} // namespace internal
|
|
70
|
+
|
|
71
|
+
//! Class template that specifies the interface of an arry with the data type.
|
|
72
|
+
template<class DATA_TYPE>
|
|
73
|
+
class RepeatedField : public Field
|
|
74
|
+
{
|
|
75
|
+
|
|
76
|
+
//! Definition of a trait to check if DATA_TYPE is NOT a specialization of the FieldTemplate.
|
|
77
|
+
template<typename>
|
|
78
|
+
struct is_specialization_of_FieldTemplate : std::false_type {};
|
|
79
|
+
|
|
80
|
+
//! Definition of a trait to check if DATA_TYPE is a specialization of the FieldTemplate.
|
|
81
|
+
template<Field::FieldTypes F, typename V, WireFormatter::WireType W, uint32_t S>
|
|
82
|
+
struct is_specialization_of_FieldTemplate<::EmbeddedProto::FieldTemplate<F,V,W,S>> : std::true_type {};
|
|
83
|
+
|
|
84
|
+
//! Helper trait to extract wire type from a FieldTemplate specialization.
|
|
85
|
+
template<typename>
|
|
86
|
+
struct fieldtemplate_wire_type;
|
|
87
|
+
|
|
88
|
+
template<Field::FieldTypes F, typename V, WireFormatter::WireType W, uint32_t S>
|
|
89
|
+
struct fieldtemplate_wire_type<::EmbeddedProto::FieldTemplate<F, V, W, S>>
|
|
90
|
+
{
|
|
91
|
+
static constexpr ::EmbeddedProto::WireFormatter::WireType value = W;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
//! Helper trait to extract the field type from a FieldTemplate specialization.
|
|
95
|
+
template<typename>
|
|
96
|
+
struct fieldtemplate_field_type;
|
|
97
|
+
|
|
98
|
+
template<Field::FieldTypes F, typename V, WireFormatter::WireType W, uint32_t S>
|
|
99
|
+
struct fieldtemplate_field_type<::EmbeddedProto::FieldTemplate<F, V, W, S>>
|
|
100
|
+
{
|
|
101
|
+
static constexpr Field::FieldTypes value = F;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
//! Helper trait telling if DATA_TYPE is a scalar or enum which goes on the wire as a varint.
|
|
105
|
+
template<typename>
|
|
106
|
+
struct is_varint_field : std::false_type {};
|
|
107
|
+
|
|
108
|
+
template<Field::FieldTypes F, typename V, WireFormatter::WireType W, uint32_t S>
|
|
109
|
+
struct is_varint_field<::EmbeddedProto::FieldTemplate<F, V, W, S>>
|
|
110
|
+
: std::integral_constant<bool, WireFormatter::WireType::VARINT == W> {};
|
|
111
|
+
|
|
112
|
+
//! Whether a packed block of this field holds varints, the case the windowed decode covers.
|
|
113
|
+
static constexpr bool PACKED_VARINT_ELEMENTS = is_varint_field<DATA_TYPE>::value;
|
|
114
|
+
|
|
115
|
+
//! The number of bytes peeked at once when decoding packed varint elements.
|
|
116
|
+
static constexpr uint32_t PACKED_VARINT_WINDOW_N_BYTES = 32U;
|
|
117
|
+
|
|
118
|
+
// A window holds at least one whole varint, so an element cut by the window end always
|
|
119
|
+
// follows decoded bytes and the next window starts with it.
|
|
120
|
+
static_assert(WireFormatter::VARINT_MAX_N_BYTES <= PACKED_VARINT_WINDOW_N_BYTES,
|
|
121
|
+
"The packed varint window must hold the largest varint.");
|
|
122
|
+
|
|
123
|
+
//! This class only supports Field and FieldTemplate classes as template parameter.
|
|
124
|
+
static_assert(std::is_base_of<::EmbeddedProto::Field, DATA_TYPE>::value || is_specialization_of_FieldTemplate<DATA_TYPE>::value,
|
|
125
|
+
"A Field can only be used as template paramter.");
|
|
126
|
+
|
|
127
|
+
public:
|
|
128
|
+
|
|
129
|
+
//! Check how this field shoeld be serialized, packed or not.
|
|
130
|
+
static constexpr bool REPEATED_FIELD_IS_PACKED =
|
|
131
|
+
!(std::is_base_of<MessageInterface, DATA_TYPE>::value
|
|
132
|
+
|| std::is_base_of<internal::BaseStringBytes, DATA_TYPE>::value);
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
RepeatedField() = default;
|
|
136
|
+
~RepeatedField() = default;
|
|
137
|
+
|
|
138
|
+
//! Obtain the total number of DATA_TYPE items in the array.
|
|
139
|
+
virtual uint32_t get_length() const = 0;
|
|
140
|
+
|
|
141
|
+
//! Obtain the maximum number of DATA_TYPE items which can at most be stored in the array.
|
|
142
|
+
virtual uint32_t get_max_length() const = 0;
|
|
143
|
+
|
|
144
|
+
//! Obtain the total number of bytes currently stored in the array.
|
|
145
|
+
virtual uint32_t get_size() const = 0;
|
|
146
|
+
|
|
147
|
+
//! Obtain the maximum number of bytes which can at most be stored in the array.
|
|
148
|
+
virtual uint32_t get_max_size() const = 0;
|
|
149
|
+
|
|
150
|
+
//! Get a reference to the value at the given index.
|
|
151
|
+
/*!
|
|
152
|
+
\param[in] index The desired index to return.
|
|
153
|
+
\return The reference to the value at the given index.
|
|
154
|
+
*/
|
|
155
|
+
virtual DATA_TYPE& get(uint32_t index) = 0;
|
|
156
|
+
|
|
157
|
+
//! Get a constant reference to the value at the given index.
|
|
158
|
+
/*!
|
|
159
|
+
\param[in] index The desired index to return.
|
|
160
|
+
\return The constant reference to the value at the given index.
|
|
161
|
+
*/
|
|
162
|
+
virtual const DATA_TYPE& get_const(uint32_t index) const = 0;
|
|
163
|
+
|
|
164
|
+
//! Get a constant reference to the value at the given index.
|
|
165
|
+
/*!
|
|
166
|
+
\param[in] index The desired index to return.
|
|
167
|
+
\param[out] value The value of the desired index is set in this reference.
|
|
168
|
+
\return An error incase of an index out of bound situation.
|
|
169
|
+
*/
|
|
170
|
+
virtual Error get_const(const uint32_t index, DATA_TYPE& value) const = 0;
|
|
171
|
+
|
|
172
|
+
//! Get a reference to the value at the given index.
|
|
173
|
+
/*!
|
|
174
|
+
\param[in] index The desired index to return.
|
|
175
|
+
\return The reference to the value at the given index.
|
|
176
|
+
*/
|
|
177
|
+
DATA_TYPE& operator[](uint32_t index) { return this->get(index); }
|
|
178
|
+
|
|
179
|
+
//! Get a reference to the value at the given index. But constant.
|
|
180
|
+
/*!
|
|
181
|
+
\param[in] index The desired index to return.
|
|
182
|
+
\return The constant reference to the value at the given index.
|
|
183
|
+
*/
|
|
184
|
+
const DATA_TYPE& operator[](uint32_t index) const { return this->get_const(index); }
|
|
185
|
+
|
|
186
|
+
//! Set the value at the given index.
|
|
187
|
+
/*!
|
|
188
|
+
\param[in] index The desired index to change.
|
|
189
|
+
\param[in] value The value we would like to set.
|
|
190
|
+
*/
|
|
191
|
+
virtual void set(uint32_t index, const DATA_TYPE& value) = 0;
|
|
192
|
+
|
|
193
|
+
//! Given a view on a different array copy that data into this object.
|
|
194
|
+
/*!
|
|
195
|
+
\param[in] data A view on the array to copy from, data.size values of DATA_TYPE are copied.
|
|
196
|
+
\return Error::NO_ERRORS when every was successful. Error::ARRAY_FULL when there is no space left.
|
|
197
|
+
*/
|
|
198
|
+
virtual Error set_data(const array_view<const DATA_TYPE>& data) = 0;
|
|
199
|
+
|
|
200
|
+
//! Copy an array into this object, pointer and length form of set_data(const array_view<const DATA_TYPE>&).
|
|
201
|
+
/*!
|
|
202
|
+
\deprecated Use the array_view overload set_data(const array_view<const DATA_TYPE>&), a
|
|
203
|
+
view keeps the pointer and its bound together.
|
|
204
|
+
\param[in] data A pointer the array to copy from.
|
|
205
|
+
\param[in] length The number of value of DATA_TYPE in the array.
|
|
206
|
+
\return Error::NO_ERRORS when every was successful. Error::ARRAY_FULL when there is no space left.
|
|
207
|
+
*/
|
|
208
|
+
[[deprecated("use the array_view overload set_data(const array_view<const DATA_TYPE>&)")]]
|
|
209
|
+
virtual Error set_data(const DATA_TYPE* data, const uint32_t length)
|
|
210
|
+
{
|
|
211
|
+
return set_data(array_view<const DATA_TYPE>{data, length});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
//! Append a value to the end of the array.
|
|
215
|
+
/*!
|
|
216
|
+
\param[in] value The data to add.
|
|
217
|
+
\return Error::NO_ERRORS when every was successful. Error::ARRAY_FULL when there is no space left.
|
|
218
|
+
*/
|
|
219
|
+
virtual Error add(const DATA_TYPE& value) = 0;
|
|
220
|
+
|
|
221
|
+
//! Remove the element at the given index, moving the elements behind it one place forward.
|
|
222
|
+
/*!
|
|
223
|
+
The default implementation reports INDEX_OUT_OF_BOUND. Storage types which hold no
|
|
224
|
+
resident collection, like the streaming callback storage, keep that behaviour; storage
|
|
225
|
+
types which can shrink override this function. Used among others to remove a key from a
|
|
226
|
+
map field.
|
|
227
|
+
|
|
228
|
+
\param[in] index The index of the element to remove.
|
|
229
|
+
\return Error::NO_ERRORS when the element was removed. Error::INDEX_OUT_OF_BOUND when the
|
|
230
|
+
index is outside of the data held or this storage type can not remove elements.
|
|
231
|
+
*/
|
|
232
|
+
virtual Error erase(const uint32_t index)
|
|
233
|
+
{
|
|
234
|
+
static_cast<void>(index);
|
|
235
|
+
return Error::INDEX_OUT_OF_BOUND;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
//! Remove all data in the array and set it to the default value.
|
|
239
|
+
virtual void clear() override = 0;
|
|
240
|
+
|
|
241
|
+
//! Serialize all elements in the array (used for packed serialization).
|
|
242
|
+
/*!
|
|
243
|
+
Not final: RepeatedFieldFixedSize overrides this to batch packed
|
|
244
|
+
fixed-width payloads into a single whole-block buffer write.
|
|
245
|
+
*/
|
|
246
|
+
Error serialize(WriteBufferInterface& buffer) const override
|
|
247
|
+
{
|
|
248
|
+
Error return_value = Error::NO_ERRORS;
|
|
249
|
+
for(uint32_t i = 0; (i < this->get_length()) && (Error::NO_ERRORS == return_value); ++i)
|
|
250
|
+
{
|
|
251
|
+
return_value = this->get_const(i).serialize(buffer);
|
|
252
|
+
}
|
|
253
|
+
return return_value;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
//! Function to deserialize this array.
|
|
257
|
+
/*!
|
|
258
|
+
From a buffer of data fill this array with data.
|
|
259
|
+
Not final: RepeatedFieldFixedSize overrides this to read a packed
|
|
260
|
+
fixed-width payload out of the buffer in a single batched block read
|
|
261
|
+
instead of one virtual call per byte.
|
|
262
|
+
\param buffer [in] The memory from which the message is obtained.
|
|
263
|
+
\return Error::NO_ERRORS when every was successful.
|
|
264
|
+
*/
|
|
265
|
+
Error deserialize(::EmbeddedProto::ReadBufferInterface& buffer) override
|
|
266
|
+
{
|
|
267
|
+
Error return_value = Error::NO_ERRORS;
|
|
268
|
+
if(REPEATED_FIELD_IS_PACKED)
|
|
269
|
+
{
|
|
270
|
+
return_value = deserialize_packed(buffer);
|
|
271
|
+
}
|
|
272
|
+
else
|
|
273
|
+
{
|
|
274
|
+
return_value = deserialize_unpacked(buffer);
|
|
275
|
+
}
|
|
276
|
+
return return_value;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
//! Not final: RepeatedFieldCallback overrides this so expanded
|
|
280
|
+
//! (one-tag-per-element) scalar input is funnelled through the virtual
|
|
281
|
+
//! add() hook instead of the random-access get(index) slot it lacks.
|
|
282
|
+
Error deserialize_check_type(::EmbeddedProto::ReadBufferInterface& buffer,
|
|
283
|
+
const ::EmbeddedProto::WireFormatter::WireType& wire_type) override
|
|
284
|
+
{
|
|
285
|
+
const bool is_length_delimited =
|
|
286
|
+
::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED == wire_type;
|
|
287
|
+
Error return_value = Error::NO_ERRORS;
|
|
288
|
+
|
|
289
|
+
if(REPEATED_FIELD_IS_PACKED)
|
|
290
|
+
{
|
|
291
|
+
// Scalar / enum elements may be received either as a single packed block
|
|
292
|
+
// (length-delimited) or as expanded one-tag-per-element values (the
|
|
293
|
+
// element's own wire type). Both forms are accepted regardless of which
|
|
294
|
+
// form this side emits (repeated_field_encoding feature).
|
|
295
|
+
if(is_length_delimited)
|
|
296
|
+
{
|
|
297
|
+
// Route through the virtual deserialize() so RepeatedFieldFixedSize's
|
|
298
|
+
// whole-block fast path is reached on the generated receive path.
|
|
299
|
+
return_value = this->deserialize(buffer);
|
|
300
|
+
}
|
|
301
|
+
else
|
|
302
|
+
{
|
|
303
|
+
return_value = deserialize_unpacked(buffer);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else
|
|
307
|
+
{
|
|
308
|
+
// Message / string / bytes elements are always length-delimited, one per
|
|
309
|
+
// tag.
|
|
310
|
+
return_value = is_length_delimited ? deserialize_unpacked(buffer)
|
|
311
|
+
: Error::INVALID_WIRETYPE;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return return_value;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
#ifdef PARTIAL_SERIALIZATION_ENABLED
|
|
318
|
+
Error deserialize_partial_as_field(ReadBufferInterface& buffer,
|
|
319
|
+
MessageState& state) override
|
|
320
|
+
{
|
|
321
|
+
Error return_value = Error::NO_ERRORS;
|
|
322
|
+
|
|
323
|
+
if(REPEATED_FIELD_IS_PACKED)
|
|
324
|
+
{
|
|
325
|
+
if((::EmbeddedProto::FieldProcessingPhase::SIZE != state.phase) && (::EmbeddedProto::FieldProcessingPhase::DATA != state.phase))
|
|
326
|
+
{
|
|
327
|
+
return_value = Error::STATE_MISMATCH;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if((Error::NO_ERRORS == return_value) && (::EmbeddedProto::FieldProcessingPhase::SIZE == state.phase))
|
|
331
|
+
{
|
|
332
|
+
return_value = deserialize_partial_size_phase(buffer, state);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if((Error::NO_ERRORS == return_value) && (::EmbeddedProto::FieldProcessingPhase::DATA == state.phase))
|
|
336
|
+
{
|
|
337
|
+
ReadBufferSection section(buffer, state.bytes_remaining);
|
|
338
|
+
const uint32_t section_size_before = section.get_size();
|
|
339
|
+
Error element_result = Error::NO_ERRORS;
|
|
340
|
+
|
|
341
|
+
if constexpr(PACKED_VARINT_ELEMENTS)
|
|
342
|
+
{
|
|
343
|
+
Error add_result = Error::NO_ERRORS;
|
|
344
|
+
element_result = deserialize_packed_varints(section, state.element_index, add_result);
|
|
345
|
+
if(Error::NO_ERRORS != add_result)
|
|
346
|
+
{
|
|
347
|
+
return_value = Error::ARRAY_FULL;
|
|
348
|
+
element_result = Error::ARRAY_FULL;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else
|
|
352
|
+
{
|
|
353
|
+
DATA_TYPE element;
|
|
354
|
+
element_result = deserialize_packed_partial_element(element, section);
|
|
355
|
+
|
|
356
|
+
while(Error::NO_ERRORS == element_result)
|
|
357
|
+
{
|
|
358
|
+
return_value = this->add(element);
|
|
359
|
+
if(Error::NO_ERRORS == return_value)
|
|
360
|
+
{
|
|
361
|
+
++state.element_index;
|
|
362
|
+
element_result = deserialize_packed_partial_element(element, section);
|
|
363
|
+
}
|
|
364
|
+
else
|
|
365
|
+
{
|
|
366
|
+
return_value = Error::ARRAY_FULL;
|
|
367
|
+
element_result = Error::ARRAY_FULL;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const uint32_t section_size_after = section.get_size();
|
|
373
|
+
const uint32_t bytes_consumed = section_size_before - section_size_after;
|
|
374
|
+
state.bytes_remaining -= bytes_consumed;
|
|
375
|
+
|
|
376
|
+
if(Error::NO_ERRORS == return_value)
|
|
377
|
+
{
|
|
378
|
+
if(0U == state.bytes_remaining)
|
|
379
|
+
{
|
|
380
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
381
|
+
return_value = Error::NO_ERRORS;
|
|
382
|
+
}
|
|
383
|
+
else if(Error::END_OF_BUFFER == element_result)
|
|
384
|
+
{
|
|
385
|
+
return_value = Error::END_OF_BUFFER;
|
|
386
|
+
}
|
|
387
|
+
else
|
|
388
|
+
{
|
|
389
|
+
return_value = element_result;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
else
|
|
395
|
+
{
|
|
396
|
+
if((::EmbeddedProto::FieldProcessingPhase::SIZE != state.phase) && (::EmbeddedProto::FieldProcessingPhase::DATA != state.phase))
|
|
397
|
+
{
|
|
398
|
+
return_value = Error::STATE_MISMATCH;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if(Error::NO_ERRORS == return_value)
|
|
402
|
+
{
|
|
403
|
+
if constexpr(std::is_base_of<Field, DATA_TYPE>::value)
|
|
404
|
+
{
|
|
405
|
+
// Non-packed repeated string/bytes/message element. Each wire
|
|
406
|
+
// occurrence is a separate tag/size/data cycle, and the message loop
|
|
407
|
+
// resets element_index to zero between occurrences. Elements are
|
|
408
|
+
// therefore accumulated based on the current array length rather than
|
|
409
|
+
// element_index. element_index is reused purely as a per-occurrence
|
|
410
|
+
// flag marking that the slot for the current element has already been
|
|
411
|
+
// reserved, so an element split across buffers is not appended twice.
|
|
412
|
+
if(0U == state.element_index)
|
|
413
|
+
{
|
|
414
|
+
if(this->get_max_length() <= this->get_length())
|
|
415
|
+
{
|
|
416
|
+
return_value = Error::ARRAY_FULL;
|
|
417
|
+
}
|
|
418
|
+
else
|
|
419
|
+
{
|
|
420
|
+
// Reserve a slot for this new element.
|
|
421
|
+
(void)this->get(this->get_length());
|
|
422
|
+
state.element_index = 1U;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if(Error::NO_ERRORS == return_value)
|
|
427
|
+
{
|
|
428
|
+
return_value = this->get(this->get_length() - 1U).deserialize_partial_as_field(buffer, state);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
else
|
|
432
|
+
{
|
|
433
|
+
if(::EmbeddedProto::FieldProcessingPhase::DATA != state.phase)
|
|
434
|
+
{
|
|
435
|
+
return_value = Error::STATE_MISMATCH;
|
|
436
|
+
}
|
|
437
|
+
else
|
|
438
|
+
{
|
|
439
|
+
DATA_TYPE value;
|
|
440
|
+
return_value = value.deserialize_partial_check_type(
|
|
441
|
+
buffer,
|
|
442
|
+
state,
|
|
443
|
+
fieldtemplate_wire_type<DATA_TYPE>::value);
|
|
444
|
+
if(Error::NO_ERRORS == return_value)
|
|
445
|
+
{
|
|
446
|
+
return_value = this->add(value);
|
|
447
|
+
if(Error::NO_ERRORS != return_value)
|
|
448
|
+
{
|
|
449
|
+
return_value = Error::ARRAY_FULL;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return return_value;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
Error serialize_partial_as_field(uint32_t field_number,
|
|
461
|
+
WriteBufferInterface& buffer,
|
|
462
|
+
MessageState& state,
|
|
463
|
+
bool optional) const override
|
|
464
|
+
{
|
|
465
|
+
// Skip serializing empty non-optional repeated fields (proto3 default behavior).
|
|
466
|
+
if((!optional) && (0U == this->get_length()))
|
|
467
|
+
{
|
|
468
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
469
|
+
return Error::NO_ERRORS;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return REPEATED_FIELD_IS_PACKED
|
|
473
|
+
? serialize_partial_packed(field_number, buffer, state, optional)
|
|
474
|
+
: serialize_partial_unpacked(field_number, buffer, state);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
//! Serialize a repeated scalar/enum field in EXPANDED form with partial state
|
|
478
|
+
//! support, regardless of the element type's default packing.
|
|
479
|
+
/*!
|
|
480
|
+
Used for the editions repeated_field_encoding = EXPANDED feature so that
|
|
481
|
+
chunked (partial) serialization emits the same one-tag-per-element bytes
|
|
482
|
+
as full serialization instead of a single packed block.
|
|
483
|
+
*/
|
|
484
|
+
Error serialize_partial_as_field_expanded(uint32_t field_number,
|
|
485
|
+
WriteBufferInterface& buffer,
|
|
486
|
+
MessageState& state,
|
|
487
|
+
bool optional) const
|
|
488
|
+
{
|
|
489
|
+
// Skip serializing empty non-optional repeated fields (proto3 default behavior).
|
|
490
|
+
if((!optional) && (0U == this->get_length()))
|
|
491
|
+
{
|
|
492
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
493
|
+
return Error::NO_ERRORS;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return serialize_partial_unpacked(field_number, buffer, state);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
private:
|
|
500
|
+
//! Serialize a single packed element with one all-or-nothing push.
|
|
501
|
+
/*!
|
|
502
|
+
Every scalar element is written with a single push(const_bytes_view) call.
|
|
503
|
+
Fixed-width values push their little-endian bytes directly, varint values
|
|
504
|
+
(integers, bools and enums) are first encoded into a local array. This
|
|
505
|
+
keeps the resumable partial path correct: when the element does not fit,
|
|
506
|
+
nothing is written so bytes_remaining / element_index stay untouched and
|
|
507
|
+
the element is retried cleanly on the next call. Message and string
|
|
508
|
+
elements are never packed and keep their own serialization.
|
|
509
|
+
*/
|
|
510
|
+
Error serialize_packed_element(uint32_t index, WriteBufferInterface& buffer) const
|
|
511
|
+
{
|
|
512
|
+
return serialize_packed_element_(index, buffer,
|
|
513
|
+
std::integral_constant<bool, internal::PackedFixedTraits<DATA_TYPE>::is_fixed_width>{});
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
Error serialize_packed_element_(uint32_t index, WriteBufferInterface& buffer,
|
|
517
|
+
std::true_type) const
|
|
518
|
+
{
|
|
519
|
+
using VAR = typename internal::PackedFixedTraits<DATA_TYPE>::scalar_type;
|
|
520
|
+
const VAR value = this->get_const(index).get();
|
|
521
|
+
return WireFormatter::SerializeFixedArrayNoTag(array_view<const VAR>{&value, 1U}, buffer);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
Error serialize_packed_element_(uint32_t index, WriteBufferInterface& buffer,
|
|
525
|
+
std::false_type) const
|
|
526
|
+
{
|
|
527
|
+
Error return_value = Error::NO_ERRORS;
|
|
528
|
+
if constexpr(is_specialization_of_FieldTemplate<DATA_TYPE>::value)
|
|
529
|
+
{
|
|
530
|
+
std::array<uint8_t, WireFormatter::VARINT_MAX_N_BYTES> bytes = {0};
|
|
531
|
+
const uint32_t n_bytes = WireFormatter::EncodeVarint(
|
|
532
|
+
packed_varint_value(this->get_const(index)), bytes);
|
|
533
|
+
return_value = buffer.push(const_bytes_view{bytes.data(), n_bytes}) ? Error::NO_ERRORS
|
|
534
|
+
: Error::BUFFER_FULL;
|
|
535
|
+
}
|
|
536
|
+
else
|
|
537
|
+
{
|
|
538
|
+
return_value = this->get_const(index).serialize(buffer);
|
|
539
|
+
}
|
|
540
|
+
return return_value;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
//! Return the value of a varint element as it goes on the wire, zero extended to 64 bits.
|
|
544
|
+
/*!
|
|
545
|
+
Mirrors the conversions of the matching FieldTemplate::serialize(): int32 and
|
|
546
|
+
enum values are truncated to 32 bits, sint32 and sint64 values are zig-zag
|
|
547
|
+
encoded and a bool becomes 0 or 1. This way one encoder produces the same
|
|
548
|
+
bytes for every varint element type as full serialization does.
|
|
549
|
+
*/
|
|
550
|
+
static uint64_t packed_varint_value(const DATA_TYPE& element)
|
|
551
|
+
{
|
|
552
|
+
constexpr Field::FieldTypes FIELD_TYPE = fieldtemplate_field_type<DATA_TYPE>::value;
|
|
553
|
+
uint64_t value = 0U;
|
|
554
|
+
if constexpr((Field::FieldTypes::sint32 == FIELD_TYPE)
|
|
555
|
+
|| (Field::FieldTypes::sint64 == FIELD_TYPE))
|
|
556
|
+
{
|
|
557
|
+
value = static_cast<uint64_t>(WireFormatter::ZigZagEncode(element.get()));
|
|
558
|
+
}
|
|
559
|
+
else if constexpr(Field::FieldTypes::boolean == FIELD_TYPE)
|
|
560
|
+
{
|
|
561
|
+
value = element.get() ? 1U : 0U;
|
|
562
|
+
}
|
|
563
|
+
else if constexpr((Field::FieldTypes::int32 == FIELD_TYPE)
|
|
564
|
+
|| (Field::FieldTypes::enumeration == FIELD_TYPE))
|
|
565
|
+
{
|
|
566
|
+
value = static_cast<uint64_t>(static_cast<uint32_t>(element.get()));
|
|
567
|
+
}
|
|
568
|
+
else
|
|
569
|
+
{
|
|
570
|
+
// int64, uint32 and uint64 convert directly.
|
|
571
|
+
value = static_cast<uint64_t>(element.get());
|
|
572
|
+
}
|
|
573
|
+
return value;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
//! Packed partial serialization: TAG->SIZE->DATA over one length-delimited block.
|
|
577
|
+
Error serialize_partial_packed(uint32_t field_number,
|
|
578
|
+
WriteBufferInterface& buffer,
|
|
579
|
+
MessageState& state,
|
|
580
|
+
bool optional) const
|
|
581
|
+
{
|
|
582
|
+
Error return_value = Error::NO_ERRORS;
|
|
583
|
+
|
|
584
|
+
if(::EmbeddedProto::FieldProcessingPhase::DATA != state.phase)
|
|
585
|
+
{
|
|
586
|
+
// Calculate total packed size
|
|
587
|
+
const uint32_t total_size = serialized_size_packed();
|
|
588
|
+
return_value = serialize_partial_tag_and_size(field_number, total_size, buffer, state, optional);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if((Error::NO_ERRORS == return_value) && (::EmbeddedProto::FieldProcessingPhase::DATA == state.phase))
|
|
592
|
+
{
|
|
593
|
+
// Serialize elements sequentially
|
|
594
|
+
if(state.element_index < this->get_length())
|
|
595
|
+
{
|
|
596
|
+
const uint32_t initial_size = buffer.get_size();
|
|
597
|
+
return_value = serialize_packed_element(state.element_index, buffer);
|
|
598
|
+
const uint32_t bytes_written = buffer.get_size() - initial_size;
|
|
599
|
+
state.bytes_remaining -= bytes_written;
|
|
600
|
+
|
|
601
|
+
if(Error::NO_ERRORS == return_value)
|
|
602
|
+
{
|
|
603
|
+
++state.element_index;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if(0 == state.bytes_remaining)
|
|
607
|
+
{
|
|
608
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
else
|
|
612
|
+
{
|
|
613
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return return_value;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
//! Unpacked (expanded) partial serialization: each element gets its own tag.
|
|
621
|
+
Error serialize_partial_unpacked(uint32_t field_number,
|
|
622
|
+
WriteBufferInterface& buffer,
|
|
623
|
+
MessageState& state) const
|
|
624
|
+
{
|
|
625
|
+
Error return_value = Error::NO_ERRORS;
|
|
626
|
+
|
|
627
|
+
if(state.phase == ::EmbeddedProto::FieldProcessingPhase::COMPLETE)
|
|
628
|
+
{
|
|
629
|
+
// All elements serialized
|
|
630
|
+
return return_value;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Handle current element
|
|
634
|
+
if(state.element_index < this->get_length())
|
|
635
|
+
{
|
|
636
|
+
const auto& element = this->get_const(state.element_index);
|
|
637
|
+
|
|
638
|
+
// Check if element is a Field-derived type (messages, strings, bytes) or scalar type
|
|
639
|
+
if constexpr(std::is_base_of<Field, DATA_TYPE>::value)
|
|
640
|
+
{
|
|
641
|
+
// Field-derived types (messages, strings, bytes) use serialize_partial_as_field
|
|
642
|
+
return_value = element.serialize_partial_as_field(field_number, buffer, state, true);
|
|
643
|
+
}
|
|
644
|
+
else
|
|
645
|
+
{
|
|
646
|
+
// Scalar types use serialize_partial_with_id
|
|
647
|
+
return_value = element.serialize_partial_with_id(field_number, buffer, state, true);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if((Error::NO_ERRORS == return_value) && (state.phase == ::EmbeddedProto::FieldProcessingPhase::COMPLETE))
|
|
651
|
+
{
|
|
652
|
+
// Element complete, move to next
|
|
653
|
+
++state.element_index;
|
|
654
|
+
// Reset child state for next element to avoid stale COMPLETE phase
|
|
655
|
+
// in nested message serialization.
|
|
656
|
+
if(nullptr != state.child)
|
|
657
|
+
{
|
|
658
|
+
state.child->reset();
|
|
659
|
+
}
|
|
660
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::TAG; // Reset for next element
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
else
|
|
664
|
+
{
|
|
665
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return return_value;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
public:
|
|
672
|
+
#endif
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
//! Calculate the size of this field when serialized.
|
|
676
|
+
/*!
|
|
677
|
+
The calculation only includes the data, not the size required by the tag and
|
|
678
|
+
\return The number of bytes this field will require once serialized.
|
|
679
|
+
*/
|
|
680
|
+
uint32_t serialized_size_packed() const
|
|
681
|
+
{
|
|
682
|
+
::EmbeddedProto::MessageSizeCalculator calcBuffer;
|
|
683
|
+
serialize(calcBuffer);
|
|
684
|
+
return calcBuffer.get_size();
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
//! Calculate the size of this field when serialized.
|
|
688
|
+
/*!
|
|
689
|
+
\return The number of bytes this field will require once serialized.
|
|
690
|
+
*/
|
|
691
|
+
uint32_t serialized_size_unpacked(int32_t field_number) const
|
|
692
|
+
{
|
|
693
|
+
::EmbeddedProto::MessageSizeCalculator calcBuffer;
|
|
694
|
+
serialize_unpacked(field_number, calcBuffer);
|
|
695
|
+
return calcBuffer.get_size();
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
#ifdef MSG_TO_STRING
|
|
699
|
+
|
|
700
|
+
::EmbeddedProto::string_view to_string(::EmbeddedProto::string_view& str, const uint32_t indent_level, char const* name, const bool first_field) const override
|
|
701
|
+
{
|
|
702
|
+
::EmbeddedProto::string_view left_chars = str;
|
|
703
|
+
int32_t n_chars_used = 0;
|
|
704
|
+
|
|
705
|
+
if(!first_field)
|
|
706
|
+
{
|
|
707
|
+
// Add a comma behind the previous field.
|
|
708
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, ",\n");
|
|
709
|
+
if(0 < n_chars_used)
|
|
710
|
+
{
|
|
711
|
+
// Update the character pointer and characters left in the array.
|
|
712
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
713
|
+
left_chars.data += actual_chars_used;
|
|
714
|
+
left_chars.size -= actual_chars_used;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "%*s\"%s\": [\n", indent_level, " ", name );
|
|
719
|
+
|
|
720
|
+
if(0 < n_chars_used)
|
|
721
|
+
{
|
|
722
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
723
|
+
left_chars.data += actual_chars_used;
|
|
724
|
+
left_chars.size -= actual_chars_used;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
for(uint32_t i = 0; i < this->get_length(); ++i)
|
|
728
|
+
{
|
|
729
|
+
left_chars = this->get_const(i).to_string(left_chars, n_chars_used, nullptr, (0 == i));
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "\n%*s]", n_chars_used - 2, " ");
|
|
733
|
+
|
|
734
|
+
if(0 < n_chars_used)
|
|
735
|
+
{
|
|
736
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
737
|
+
left_chars.data += actual_chars_used;
|
|
738
|
+
left_chars.size -= actual_chars_used;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
return left_chars;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
#endif // End of MSG_TO_STRING
|
|
745
|
+
|
|
746
|
+
private:
|
|
747
|
+
|
|
748
|
+
Error serialize_unpacked(uint32_t field_number, WriteBufferInterface& buffer) const
|
|
749
|
+
{
|
|
750
|
+
Error return_value = Error::NO_ERRORS;
|
|
751
|
+
for(uint32_t i = 0; (i < this->get_length()) && (Error::NO_ERRORS == return_value); ++i)
|
|
752
|
+
{
|
|
753
|
+
// Each element gets its own [tag][size][data]
|
|
754
|
+
// Note: serialize_len() is only available on Field-derived types (messages, strings, bytes)
|
|
755
|
+
// which is exactly what unpacked mode is used for.
|
|
756
|
+
const uint32_t size_x = this->get_const(i).serialized_size();
|
|
757
|
+
uint32_t tag = WireFormatter::MakeTag(field_number,
|
|
758
|
+
WireFormatter::WireType::LENGTH_DELIMITED);
|
|
759
|
+
return_value = WireFormatter::SerializeVarint(tag, buffer);
|
|
760
|
+
if(Error::NO_ERRORS == return_value)
|
|
761
|
+
{
|
|
762
|
+
return_value = WireFormatter::SerializeVarint(size_x, buffer);
|
|
763
|
+
if((Error::NO_ERRORS == return_value) && (0 < size_x))
|
|
764
|
+
{
|
|
765
|
+
return_value = this->get_const(i).serialize(buffer);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return return_value;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
protected:
|
|
773
|
+
|
|
774
|
+
//! Deserialize one packed length-delimited block into this array.
|
|
775
|
+
/*!
|
|
776
|
+
Non-virtual helper (no vtable slot): the fixed-width whole-block fast
|
|
777
|
+
path lives in RepeatedFieldFixedSize's deserialize() override, which
|
|
778
|
+
reuses the existing Field::deserialize slot.
|
|
779
|
+
*/
|
|
780
|
+
Error deserialize_packed(ReadBufferInterface& buffer)
|
|
781
|
+
{
|
|
782
|
+
uint32_t size = 0;
|
|
783
|
+
Error return_value = WireFormatter::DeserializeVarint(buffer, size);
|
|
784
|
+
ReadBufferSection bufferSection(buffer, size);
|
|
785
|
+
return_value = deserialize_packed_section(bufferSection);
|
|
786
|
+
return return_value;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
//! Element-by-element loop over an already length-bounded packed section.
|
|
790
|
+
/*!
|
|
791
|
+
The caller must pass a buffer bounded to the packed block (a
|
|
792
|
+
ReadBufferSection); the loop reads elements until it is exhausted
|
|
793
|
+
(END_OF_BUFFER, the expected clean end, mapped back to NO_ERRORS) or an
|
|
794
|
+
error occurs. Takes the base ReadBufferInterface: the boundary is
|
|
795
|
+
enforced by the section object through virtual dispatch, so the concrete
|
|
796
|
+
type is not needed here. Shared with the fixed-width override for its
|
|
797
|
+
fall-back cases. Varint elements are decoded through a local window, see
|
|
798
|
+
deserialize_packed_varints().
|
|
799
|
+
*/
|
|
800
|
+
Error deserialize_packed_section(ReadBufferInterface& buffer)
|
|
801
|
+
{
|
|
802
|
+
Error return_value = Error::NO_ERRORS;
|
|
803
|
+
|
|
804
|
+
if constexpr(PACKED_VARINT_ELEMENTS)
|
|
805
|
+
{
|
|
806
|
+
uint32_t n_elements = 0U;
|
|
807
|
+
Error add_result = Error::NO_ERRORS;
|
|
808
|
+
return_value = deserialize_packed_varints(buffer, n_elements, add_result);
|
|
809
|
+
if(Error::NO_ERRORS != add_result)
|
|
810
|
+
{
|
|
811
|
+
return_value = add_result;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else
|
|
815
|
+
{
|
|
816
|
+
DATA_TYPE x;
|
|
817
|
+
|
|
818
|
+
return_value = x.deserialize(buffer);
|
|
819
|
+
while(Error::NO_ERRORS == return_value)
|
|
820
|
+
{
|
|
821
|
+
return_value = this->add(x);
|
|
822
|
+
if(Error::NO_ERRORS == return_value)
|
|
823
|
+
{
|
|
824
|
+
return_value = x.deserialize(buffer);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// We expect the buffersection to be empty, in that case everything is fine..
|
|
830
|
+
if(Error::END_OF_BUFFER == return_value)
|
|
831
|
+
{
|
|
832
|
+
return_value = Error::NO_ERRORS;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
return return_value;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
private:
|
|
839
|
+
|
|
840
|
+
Error deserialize_unpacked(ReadBufferInterface& buffer)
|
|
841
|
+
{
|
|
842
|
+
Error return_value = Error::NO_ERRORS;
|
|
843
|
+
|
|
844
|
+
// For repeated messages, strings or bytes
|
|
845
|
+
// First allocate an element in the array.
|
|
846
|
+
const uint32_t index = this->get_length();
|
|
847
|
+
if(this->get_max_length() > index)
|
|
848
|
+
{
|
|
849
|
+
// For messages read the size here, with strings and byte arrays this is include in
|
|
850
|
+
// deserialize.
|
|
851
|
+
if(std::is_base_of<MessageInterface, DATA_TYPE>::value)
|
|
852
|
+
{
|
|
853
|
+
uint32_t size;
|
|
854
|
+
return_value = WireFormatter::DeserializeVarint(buffer, size);
|
|
855
|
+
if(Error::NO_ERRORS == return_value)
|
|
856
|
+
{
|
|
857
|
+
ReadBufferSection bufferSection(buffer, size);
|
|
858
|
+
return_value = this->get(index).deserialize(bufferSection);
|
|
859
|
+
if((Error::END_OF_BUFFER == return_value) && (0U == size))
|
|
860
|
+
{
|
|
861
|
+
// An element of size zero is a valid empty message, see
|
|
862
|
+
// MessageInterface::deserialize_check_type.
|
|
863
|
+
return_value = Error::NO_ERRORS;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
else
|
|
868
|
+
{
|
|
869
|
+
return_value = this->get(index).deserialize(buffer);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
else
|
|
873
|
+
{
|
|
874
|
+
return_value = Error::ARRAY_FULL;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
return return_value;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
//! Decode the packed varint elements of a section through a local window and add them.
|
|
881
|
+
/*!
|
|
882
|
+
The section is peeked in blocks of up to PACKED_VARINT_WINDOW_N_BYTES, one
|
|
883
|
+
buffer call for several elements instead of one per byte. The elements are
|
|
884
|
+
decoded from the local copy and the section is advanced by the bytes they took.
|
|
885
|
+
An element cut by the window end is decoded from the next window. An element
|
|
886
|
+
cut by the section end consumes nothing, so a partial deserialization resumes
|
|
887
|
+
at that element once more data arrived. An element which does not fit the
|
|
888
|
+
array is consumed, as it is when read element by element.
|
|
889
|
+
|
|
890
|
+
\param[in] buffer The section holding the packed block.
|
|
891
|
+
\param[out] n_elements Incremented for every element added.
|
|
892
|
+
\param[out] add_result The result of the add() which stopped the loop, NO_ERRORS when none did.
|
|
893
|
+
\return END_OF_BUFFER when the section is exhausted or ends inside an element, a
|
|
894
|
+
decoding error, or NO_ERRORS when add() stopped the loop.
|
|
895
|
+
*/
|
|
896
|
+
Error deserialize_packed_varints(ReadBufferInterface& buffer, uint32_t& n_elements, Error& add_result)
|
|
897
|
+
{
|
|
898
|
+
std::array<uint8_t, PACKED_VARINT_WINDOW_N_BYTES> window = {0};
|
|
899
|
+
DATA_TYPE element;
|
|
900
|
+
Error return_value = Error::NO_ERRORS;
|
|
901
|
+
add_result = Error::NO_ERRORS;
|
|
902
|
+
|
|
903
|
+
while((Error::NO_ERRORS == return_value) && (Error::NO_ERRORS == add_result))
|
|
904
|
+
{
|
|
905
|
+
const uint32_t n_section = buffer.get_size();
|
|
906
|
+
const uint32_t n_window = EmbeddedProto::min(PACKED_VARINT_WINDOW_N_BYTES, n_section);
|
|
907
|
+
|
|
908
|
+
if((0U < n_window) && buffer.peek(bytes_view{window.data(), n_window}))
|
|
909
|
+
{
|
|
910
|
+
uint32_t offset = 0U;
|
|
911
|
+
bool window_done = false;
|
|
912
|
+
while(!window_done)
|
|
913
|
+
{
|
|
914
|
+
uint32_t n_used = 0U;
|
|
915
|
+
const Error element_result = decode_packed_varint(
|
|
916
|
+
const_bytes_view{&window[offset], n_window - offset}, element, n_used);
|
|
917
|
+
|
|
918
|
+
if(Error::NO_ERRORS == element_result)
|
|
919
|
+
{
|
|
920
|
+
offset += n_used;
|
|
921
|
+
add_result = this->add(element);
|
|
922
|
+
if(Error::NO_ERRORS == add_result)
|
|
923
|
+
{
|
|
924
|
+
++n_elements;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
else if((Error::END_OF_BUFFER == element_result) && (n_window < n_section))
|
|
928
|
+
{
|
|
929
|
+
// Cut by the window end, not by the section end: the next window starts with it.
|
|
930
|
+
}
|
|
931
|
+
else
|
|
932
|
+
{
|
|
933
|
+
// The section ends inside the element, which then consumed nothing, or the
|
|
934
|
+
// varint is overlong, which consumed its bytes as DeserializeVarint() does.
|
|
935
|
+
offset += n_used;
|
|
936
|
+
return_value = element_result;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
window_done = (Error::NO_ERRORS != element_result) || (Error::NO_ERRORS != add_result)
|
|
940
|
+
|| (offset >= n_window);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if(0U < offset)
|
|
944
|
+
{
|
|
945
|
+
static_cast<void>(buffer.advance(offset));
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
else
|
|
949
|
+
{
|
|
950
|
+
return_value = Error::END_OF_BUFFER;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
return return_value;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
//! Decode one packed varint element from a local array, the counterpart of packed_varint_value().
|
|
958
|
+
/*!
|
|
959
|
+
Mirrors the conversions of the matching FieldTemplate::deserialize(): uint32 and
|
|
960
|
+
enum values are decoded as 32-bit varints, int32, int64, sint32, sint64 and
|
|
961
|
+
uint64 values as 64-bit ones since some implementations serialize 32-bit values
|
|
962
|
+
with ten bytes, sint values are zig-zag decoded and a bool is one byte.
|
|
963
|
+
|
|
964
|
+
\param[in] bytes The bytes to decode, the element starts at the first one.
|
|
965
|
+
\param[out] element The element receiving the value, only set when NO_ERRORS is returned.
|
|
966
|
+
\param[out] n_used The number of bytes the element took, zero when the array ended before it closed.
|
|
967
|
+
\return As WireFormatter::DecodeVarint().
|
|
968
|
+
*/
|
|
969
|
+
static Error decode_packed_varint(const const_bytes_view& bytes, DATA_TYPE& element, uint32_t& n_used)
|
|
970
|
+
{
|
|
971
|
+
constexpr Field::FieldTypes FIELD_TYPE = fieldtemplate_field_type<DATA_TYPE>::value;
|
|
972
|
+
using VALUE_TYPE = typename DATA_TYPE::TYPE;
|
|
973
|
+
Error return_value = Error::NO_ERRORS;
|
|
974
|
+
|
|
975
|
+
if constexpr(Field::FieldTypes::boolean == FIELD_TYPE)
|
|
976
|
+
{
|
|
977
|
+
n_used = 0U;
|
|
978
|
+
if(0U < bytes.size)
|
|
979
|
+
{
|
|
980
|
+
element.set(0U != bytes.data[0]);
|
|
981
|
+
n_used = 1U;
|
|
982
|
+
}
|
|
983
|
+
else
|
|
984
|
+
{
|
|
985
|
+
return_value = Error::END_OF_BUFFER;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
else if constexpr((Field::FieldTypes::uint32 == FIELD_TYPE)
|
|
989
|
+
|| (Field::FieldTypes::enumeration == FIELD_TYPE))
|
|
990
|
+
{
|
|
991
|
+
uint32_t value = 0U;
|
|
992
|
+
return_value = WireFormatter::DecodeVarint(bytes, value, n_used);
|
|
993
|
+
if(Error::NO_ERRORS == return_value)
|
|
994
|
+
{
|
|
995
|
+
element.set(static_cast<VALUE_TYPE>(value));
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
else if constexpr((Field::FieldTypes::sint32 == FIELD_TYPE)
|
|
999
|
+
|| (Field::FieldTypes::sint64 == FIELD_TYPE))
|
|
1000
|
+
{
|
|
1001
|
+
using UINT_TYPE = typename std::make_unsigned<VALUE_TYPE>::type;
|
|
1002
|
+
uint64_t value = 0U;
|
|
1003
|
+
return_value = WireFormatter::DecodeVarint(bytes, value, n_used);
|
|
1004
|
+
if(Error::NO_ERRORS == return_value)
|
|
1005
|
+
{
|
|
1006
|
+
element.set(WireFormatter::ZigZagDecode(static_cast<UINT_TYPE>(value)));
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
else
|
|
1010
|
+
{
|
|
1011
|
+
// int32, int64 and uint64.
|
|
1012
|
+
uint64_t value = 0U;
|
|
1013
|
+
return_value = WireFormatter::DecodeVarint(bytes, value, n_used);
|
|
1014
|
+
if(Error::NO_ERRORS == return_value)
|
|
1015
|
+
{
|
|
1016
|
+
element.set(static_cast<VALUE_TYPE>(value));
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
return return_value;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
#ifdef PARTIAL_SERIALIZATION_ENABLED
|
|
1024
|
+
//! Read one packed element, batching fixed-width scalars into a single read.
|
|
1025
|
+
/*!
|
|
1026
|
+
For fixed-width scalar element types the whole element is read with one
|
|
1027
|
+
batched pop (via DeserializeFixedArrayNoTag) instead of a per-byte peek
|
|
1028
|
+
loop. The read is all-or-nothing against the section boundary: an element
|
|
1029
|
+
that is not fully present in the current section leaves the element and
|
|
1030
|
+
the section untouched and returns END_OF_BUFFER, so the resumable partial
|
|
1031
|
+
path continues at the same element/bytes_remaining on the next buffer
|
|
1032
|
+
refill. All other element types keep their existing deserialization.
|
|
1033
|
+
*/
|
|
1034
|
+
Error deserialize_packed_partial_element(DATA_TYPE& element, ReadBufferSection& section)
|
|
1035
|
+
{
|
|
1036
|
+
if constexpr(internal::PackedFixedTraits<DATA_TYPE>::is_fixed_width)
|
|
1037
|
+
{
|
|
1038
|
+
using VAR = typename internal::PackedFixedTraits<DATA_TYPE>::scalar_type;
|
|
1039
|
+
return WireFormatter::DeserializeFixedArrayNoTag(array_view<VAR>{&element.get(), 1U}, section);
|
|
1040
|
+
}
|
|
1041
|
+
else
|
|
1042
|
+
{
|
|
1043
|
+
return element.deserialize(section);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
#endif // PARTIAL_SERIALIZATION_ENABLED
|
|
1047
|
+
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
} // End of namespace EmbeddedProto
|
|
1052
|
+
|
|
1053
|
+
#endif // End of _REPEATED_FIELD_H_
|