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,793 @@
|
|
|
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 _FIELD_STRING_BYTES_H_
|
|
25
|
+
#define _FIELD_STRING_BYTES_H_
|
|
26
|
+
|
|
27
|
+
#include "Defines.h"
|
|
28
|
+
#include "Fields.h"
|
|
29
|
+
#include "EmptyArray.h"
|
|
30
|
+
#include "Errors.h"
|
|
31
|
+
|
|
32
|
+
#include <cstdint>
|
|
33
|
+
#include <cstring>
|
|
34
|
+
#include <type_traits>
|
|
35
|
+
#include <array>
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
namespace EmbeddedProto
|
|
39
|
+
{
|
|
40
|
+
|
|
41
|
+
namespace internal
|
|
42
|
+
{
|
|
43
|
+
|
|
44
|
+
class BaseStringBytes : public Field {};
|
|
45
|
+
|
|
46
|
+
template<uint32_t MAX_LENGTH, class DATA_TYPE>
|
|
47
|
+
class FieldStringBytes : public BaseStringBytes
|
|
48
|
+
{
|
|
49
|
+
static_assert(std::is_same<uint8_t, DATA_TYPE>::value || std::is_same<char, DATA_TYPE>::value,
|
|
50
|
+
"This class only supports unit8_t or chars.");
|
|
51
|
+
|
|
52
|
+
public:
|
|
53
|
+
|
|
54
|
+
FieldStringBytes() = default;
|
|
55
|
+
|
|
56
|
+
~FieldStringBytes() = default;
|
|
57
|
+
|
|
58
|
+
//! Obtain the number of characters in the string right now.
|
|
59
|
+
uint32_t get_length() const { return current_length_; }
|
|
60
|
+
|
|
61
|
+
//! Obtain the maximum number characters in the string.
|
|
62
|
+
uint32_t get_max_length() const { return MAX_LENGTH; }
|
|
63
|
+
|
|
64
|
+
//! Get a constant pointer to the first element in the array.
|
|
65
|
+
const DATA_TYPE* get_const() const { return data_.data(); }
|
|
66
|
+
|
|
67
|
+
//! Get a reference to the value at the given index.
|
|
68
|
+
/*!
|
|
69
|
+
This function will update the number of elements used in the array/string.
|
|
70
|
+
|
|
71
|
+
\param[in] index The desired index to return.
|
|
72
|
+
\return The reference to the value at the given index. Will return the last element if the
|
|
73
|
+
index is out of bounds
|
|
74
|
+
*/
|
|
75
|
+
DATA_TYPE& get(uint32_t index)
|
|
76
|
+
{
|
|
77
|
+
uint32_t limited_index = clamp_index(index);
|
|
78
|
+
// Check if we need to update the number of elements in the array.
|
|
79
|
+
if(limited_index >= current_length_) {
|
|
80
|
+
current_length_ = std::min(limited_index + 1U, MAX_LENGTH);
|
|
81
|
+
}
|
|
82
|
+
return element(limited_index);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//! Get a constant reference to the value at the given index.
|
|
86
|
+
/*!
|
|
87
|
+
\param[in] index The desired index to return.
|
|
88
|
+
\return The reference to the value at the given index. Will return the last element if the
|
|
89
|
+
index is out of bounds
|
|
90
|
+
*/
|
|
91
|
+
const DATA_TYPE& get_const(uint32_t index) const
|
|
92
|
+
{
|
|
93
|
+
return element(clamp_index(index));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//! Get a constant reference to the value at the given index.
|
|
97
|
+
/*!
|
|
98
|
+
\param[in] index The desired index to return.
|
|
99
|
+
\param[out] value The value of the desired index is set in this reference.
|
|
100
|
+
\return An error incase of an index out of bound situation.
|
|
101
|
+
*/
|
|
102
|
+
Error get_const(const uint32_t index, DATA_TYPE& value) const
|
|
103
|
+
{
|
|
104
|
+
Error result = Error::NO_ERRORS;
|
|
105
|
+
if(index < current_length_)
|
|
106
|
+
{
|
|
107
|
+
value = data_[index];
|
|
108
|
+
}
|
|
109
|
+
else
|
|
110
|
+
{
|
|
111
|
+
result = Error::INDEX_OUT_OF_BOUND;
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
//! Get a reference to the value at the given index.
|
|
117
|
+
/*!
|
|
118
|
+
This function will update the number of elements used in the array/string.
|
|
119
|
+
|
|
120
|
+
\param[in] index The desired index to return.
|
|
121
|
+
\return The reference to the value at the given index. Will return the last element if the
|
|
122
|
+
index is out of bounds
|
|
123
|
+
*/
|
|
124
|
+
DATA_TYPE& operator[](uint32_t index) { return this->get(index); }
|
|
125
|
+
|
|
126
|
+
//! Get a constant reference to the value at the given index.
|
|
127
|
+
/*!
|
|
128
|
+
\param[in] index The desired index to return.
|
|
129
|
+
\return The reference to the value at the given index. Will return the last element if the
|
|
130
|
+
index is out of bounds
|
|
131
|
+
*/
|
|
132
|
+
const DATA_TYPE& operator[](uint32_t index) const { return this->get_const(index); }
|
|
133
|
+
|
|
134
|
+
//! Assign the values in the right hand side FieldStringBytes object to this object.
|
|
135
|
+
/*!
|
|
136
|
+
This is only compatible with the same data type and length.
|
|
137
|
+
\param[in] rhs The object from which to copy the data.
|
|
138
|
+
\return Always return NO_ERRORS, this was added to be compadible with the other set function.
|
|
139
|
+
*/
|
|
140
|
+
template<uint32_t RHS_LENGTH>
|
|
141
|
+
Error set(const FieldStringBytes<RHS_LENGTH, DATA_TYPE>& rhs)
|
|
142
|
+
{
|
|
143
|
+
return this->set(array_view<const DATA_TYPE>{rhs.get_const(), rhs.get_length()});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//! Assign the data in the given view to this object.
|
|
147
|
+
/*!
|
|
148
|
+
\param[in] data A view on an array with data, data.size bytes/chars are copied.
|
|
149
|
+
\return Will return ARRAY_FULL when data.size exceeds the number of bytes/chars in this object.
|
|
150
|
+
*/
|
|
151
|
+
Error set(const array_view<const DATA_TYPE>& data)
|
|
152
|
+
{
|
|
153
|
+
Error return_value = Error::NO_ERRORS;
|
|
154
|
+
if(MAX_LENGTH >= data.size)
|
|
155
|
+
{
|
|
156
|
+
current_length_ = data.size;
|
|
157
|
+
memcpy(data_.data(), data.data, data.size);
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
{
|
|
161
|
+
return_value = Error::ARRAY_FULL;
|
|
162
|
+
}
|
|
163
|
+
return return_value;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//! Assign data in the given array to this object, pointer and length form of set(const array_view<const DATA_TYPE>&).
|
|
167
|
+
/*!
|
|
168
|
+
\deprecated Use the array_view overload set(const array_view<const DATA_TYPE>&), a
|
|
169
|
+
view keeps the pointer and its bound together.
|
|
170
|
+
\param[in] data A pointer to an array with data.
|
|
171
|
+
\param[in] length The number of bytes/chars in the data array.
|
|
172
|
+
\return Will return ARRAY_FULL when length exceeds the number of bytes/chars in this object.
|
|
173
|
+
*/
|
|
174
|
+
[[deprecated("use the array_view overload set(const array_view<const DATA_TYPE>&)")]]
|
|
175
|
+
Error set(const DATA_TYPE* data, const uint32_t length)
|
|
176
|
+
{
|
|
177
|
+
return set(array_view<const DATA_TYPE>{data, length});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
//! Compare the data held by this object with that of another string or bytes field.
|
|
181
|
+
/*!
|
|
182
|
+
The maximum lengths of the two objects may differ, only the data actually held is
|
|
183
|
+
compared. Used among others to look up a key in a map field.
|
|
184
|
+
|
|
185
|
+
\param[in] rhs The object to compare this one with.
|
|
186
|
+
\return True when both hold the same number of bytes and all of them are equal.
|
|
187
|
+
*/
|
|
188
|
+
template<uint32_t RHS_LENGTH>
|
|
189
|
+
bool operator==(const FieldStringBytes<RHS_LENGTH, DATA_TYPE>& rhs) const
|
|
190
|
+
{
|
|
191
|
+
return (current_length_ == rhs.get_length()) &&
|
|
192
|
+
(0 == memcmp(data_.data(), rhs.get_const(), current_length_));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//! Compare the data held by this object with that of another string or bytes field.
|
|
196
|
+
/*!
|
|
197
|
+
\param[in] rhs The object to compare this one with.
|
|
198
|
+
\return True when the two differ in length or in any of the bytes held.
|
|
199
|
+
*/
|
|
200
|
+
template<uint32_t RHS_LENGTH>
|
|
201
|
+
bool operator!=(const FieldStringBytes<RHS_LENGTH, DATA_TYPE>& rhs) const
|
|
202
|
+
{
|
|
203
|
+
return !(*this == rhs);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
Error serialize(WriteBufferInterface& buffer) const override
|
|
207
|
+
{
|
|
208
|
+
Error return_value = Error::NO_ERRORS;
|
|
209
|
+
const auto* void_pointer = static_cast<const void*>(&(data_[0]));
|
|
210
|
+
const auto* byte_pointer = static_cast<const uint8_t*>(void_pointer);
|
|
211
|
+
if(!buffer.push(const_bytes_view{byte_pointer, current_length_}))
|
|
212
|
+
{
|
|
213
|
+
return_value = Error::BUFFER_FULL;
|
|
214
|
+
}
|
|
215
|
+
return return_value;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
Error deserialize(ReadBufferInterface& buffer) override
|
|
219
|
+
{
|
|
220
|
+
uint32_t availiable = 0;
|
|
221
|
+
Error return_value = WireFormatter::DeserializeVarint(buffer, availiable);
|
|
222
|
+
if(Error::NO_ERRORS == return_value)
|
|
223
|
+
{
|
|
224
|
+
if(MAX_LENGTH >= availiable)
|
|
225
|
+
{
|
|
226
|
+
clear();
|
|
227
|
+
|
|
228
|
+
// Read what the buffer holds in one batched pop instead of one virtual call per
|
|
229
|
+
// byte. A truncated buffer still yields the leading bytes, as before.
|
|
230
|
+
const uint32_t bytes_to_read = std::min(availiable, buffer.get_size());
|
|
231
|
+
if(buffer.pop(bytes_view{data_as_bytes(), bytes_to_read}))
|
|
232
|
+
{
|
|
233
|
+
current_length_ = bytes_to_read;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if(current_length_ != availiable)
|
|
237
|
+
{
|
|
238
|
+
// If at the end we did not read the same number of characters something went wrong.
|
|
239
|
+
return_value = Error::END_OF_BUFFER;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else
|
|
243
|
+
{
|
|
244
|
+
return_value = Error::ARRAY_FULL;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return return_value;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
Error deserialize_check_type(::EmbeddedProto::ReadBufferInterface& buffer,
|
|
252
|
+
const ::EmbeddedProto::WireFormatter::WireType& wire_type) final
|
|
253
|
+
{
|
|
254
|
+
Error return_value = ::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED == wire_type
|
|
255
|
+
? Error::NO_ERRORS : Error::INVALID_WIRETYPE;
|
|
256
|
+
if(Error::NO_ERRORS == return_value)
|
|
257
|
+
{
|
|
258
|
+
return_value = this->deserialize(buffer);
|
|
259
|
+
}
|
|
260
|
+
return return_value;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
#ifdef PARTIAL_SERIALIZATION_ENABLED
|
|
264
|
+
Error deserialize_partial_as_field(ReadBufferInterface& buffer,
|
|
265
|
+
MessageState& state) override
|
|
266
|
+
{
|
|
267
|
+
Error return_value = Error::NO_ERRORS;
|
|
268
|
+
bool size_phase_processed = false;
|
|
269
|
+
|
|
270
|
+
if((::EmbeddedProto::FieldProcessingPhase::SIZE != state.phase) && (::EmbeddedProto::FieldProcessingPhase::DATA != state.phase))
|
|
271
|
+
{
|
|
272
|
+
return_value = Error::STATE_MISMATCH;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if((Error::NO_ERRORS == return_value) && (::EmbeddedProto::FieldProcessingPhase::SIZE == state.phase))
|
|
276
|
+
{
|
|
277
|
+
return_value = deserialize_partial_size_phase(buffer, state);
|
|
278
|
+
if(Error::NO_ERRORS == return_value)
|
|
279
|
+
{
|
|
280
|
+
size_phase_processed = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if((Error::NO_ERRORS == return_value) && size_phase_processed)
|
|
285
|
+
{
|
|
286
|
+
clear();
|
|
287
|
+
if(MAX_LENGTH < state.bytes_remaining)
|
|
288
|
+
{
|
|
289
|
+
return_value = Error::ARRAY_FULL;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if((Error::NO_ERRORS == return_value) && (::EmbeddedProto::FieldProcessingPhase::DATA == state.phase))
|
|
294
|
+
{
|
|
295
|
+
const uint32_t bytes_to_read = std::min(state.bytes_remaining, buffer.get_size());
|
|
296
|
+
if(buffer.pop(bytes_view{data_as_bytes() + current_length_, bytes_to_read}))
|
|
297
|
+
{
|
|
298
|
+
current_length_ += bytes_to_read;
|
|
299
|
+
}
|
|
300
|
+
else
|
|
301
|
+
{
|
|
302
|
+
return_value = Error::END_OF_BUFFER;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if(Error::NO_ERRORS == return_value)
|
|
306
|
+
{
|
|
307
|
+
state.bytes_remaining -= bytes_to_read;
|
|
308
|
+
if(0U == state.bytes_remaining)
|
|
309
|
+
{
|
|
310
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
311
|
+
}
|
|
312
|
+
else
|
|
313
|
+
{
|
|
314
|
+
return_value = Error::END_OF_BUFFER;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return return_value;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
Error serialize_partial_as_field(uint32_t field_number,
|
|
323
|
+
WriteBufferInterface& buffer,
|
|
324
|
+
MessageState& state,
|
|
325
|
+
bool optional) const override
|
|
326
|
+
{
|
|
327
|
+
Error return_value = Error::NO_ERRORS;
|
|
328
|
+
|
|
329
|
+
// Handle TAG and SIZE phases using helper method
|
|
330
|
+
if(::EmbeddedProto::FieldProcessingPhase::DATA != state.phase)
|
|
331
|
+
{
|
|
332
|
+
return_value = serialize_partial_tag_and_size(field_number, get_length(), buffer, state, optional);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Handle DATA phase
|
|
336
|
+
if((Error::NO_ERRORS == return_value) && (::EmbeddedProto::FieldProcessingPhase::DATA == state.phase))
|
|
337
|
+
{
|
|
338
|
+
// Calculate how many bytes we can write (limited by buffer space and remaining data)
|
|
339
|
+
const uint32_t bytes_to_write = std::min(state.bytes_remaining, buffer.get_available_size());
|
|
340
|
+
|
|
341
|
+
if(bytes_to_write > 0)
|
|
342
|
+
{
|
|
343
|
+
// Calculate starting position in data array
|
|
344
|
+
const uint32_t start_offset = get_length() - state.bytes_remaining;
|
|
345
|
+
const auto* void_pointer = static_cast<const void*>(&(data_[start_offset]));
|
|
346
|
+
const auto* byte_pointer = static_cast<const uint8_t*>(void_pointer);
|
|
347
|
+
|
|
348
|
+
// Try to write all bytes at once first
|
|
349
|
+
if(buffer.push(const_bytes_view{byte_pointer, bytes_to_write}))
|
|
350
|
+
{
|
|
351
|
+
state.bytes_remaining -= bytes_to_write;
|
|
352
|
+
if(0 == state.bytes_remaining)
|
|
353
|
+
{
|
|
354
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
355
|
+
return_value = Error::NO_ERRORS;
|
|
356
|
+
}
|
|
357
|
+
else
|
|
358
|
+
{
|
|
359
|
+
return_value = Error::BUFFER_FULL;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
else
|
|
363
|
+
{
|
|
364
|
+
// Buffer push failed - this can happen when the buffer's push method
|
|
365
|
+
// uses > instead of >=, so we can't fill the buffer completely.
|
|
366
|
+
// In this case, try to write bytes one at a time.
|
|
367
|
+
uint32_t bytes_written = 0;
|
|
368
|
+
bool push_more = true;
|
|
369
|
+
for(uint32_t i = 0; (i < bytes_to_write) && push_more; ++i)
|
|
370
|
+
{
|
|
371
|
+
push_more = buffer.push(byte_pointer[i]);
|
|
372
|
+
if(push_more)
|
|
373
|
+
{
|
|
374
|
+
bytes_written++;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if(bytes_written > 0)
|
|
379
|
+
{
|
|
380
|
+
state.bytes_remaining -= bytes_written;
|
|
381
|
+
if(0 == state.bytes_remaining)
|
|
382
|
+
{
|
|
383
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
384
|
+
return_value = Error::NO_ERRORS;
|
|
385
|
+
}
|
|
386
|
+
else
|
|
387
|
+
{
|
|
388
|
+
return_value = Error::BUFFER_FULL;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else
|
|
392
|
+
{
|
|
393
|
+
// Couldn't write any bytes - this should not happen unless buffer is completely full
|
|
394
|
+
// To prevent infinite loops, we need to ensure progress is made
|
|
395
|
+
// If we can't write any bytes and there are still bytes remaining, we have a problem
|
|
396
|
+
if(state.bytes_remaining > 0)
|
|
397
|
+
{
|
|
398
|
+
// This is the infinite loop scenario - buffer is full but we can't write any bytes
|
|
399
|
+
// We need to return BUFFER_FULL to indicate we need a new buffer
|
|
400
|
+
return_value = Error::BUFFER_FULL;
|
|
401
|
+
}
|
|
402
|
+
else
|
|
403
|
+
{
|
|
404
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
405
|
+
return_value = Error::NO_ERRORS;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else
|
|
411
|
+
{
|
|
412
|
+
// No space available in buffer - this can happen if buffer is completely full
|
|
413
|
+
// In this case, we need to ensure we don't get stuck in an infinite loop
|
|
414
|
+
// by checking if we've made any progress
|
|
415
|
+
if(state.bytes_remaining > 0)
|
|
416
|
+
{
|
|
417
|
+
return_value = Error::BUFFER_FULL;
|
|
418
|
+
}
|
|
419
|
+
else
|
|
420
|
+
{
|
|
421
|
+
state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
|
|
422
|
+
return_value = Error::NO_ERRORS;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return return_value;
|
|
428
|
+
}
|
|
429
|
+
#endif
|
|
430
|
+
|
|
431
|
+
//! Reset the field to it's initial value.
|
|
432
|
+
void clear() override
|
|
433
|
+
{
|
|
434
|
+
data_.fill(0);
|
|
435
|
+
current_length_ = 0;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
//! When serialized with the all elements set, how much bytes are then required.
|
|
439
|
+
/*!
|
|
440
|
+
This function takes into account the field number and tag combination.
|
|
441
|
+
\param[in] field_number We need to include the field number. This because large field numbers require more bytes.
|
|
442
|
+
\return The number of bytes required at most.
|
|
443
|
+
*/
|
|
444
|
+
static constexpr uint32_t max_serialized_size(const uint32_t field_number)
|
|
445
|
+
{
|
|
446
|
+
return MAX_LENGTH // The number of bytes of the data.
|
|
447
|
+
+ WireFormatter::VarintSize(MAX_LENGTH) // The varint indicating the actual number of bytes.
|
|
448
|
+
+ WireFormatter::VarintSize(WireFormatter::MakeTag(field_number,
|
|
449
|
+
WireFormatter::WireType::LENGTH_DELIMITED)); // The field and tag comby
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
//! When serialized with the all elements set, how much bytes are then required.
|
|
453
|
+
/*!
|
|
454
|
+
This function is used when the field bytes or string is serialized packed. Think in a repeated field.
|
|
455
|
+
\return The number of bytes required at most.
|
|
456
|
+
*/
|
|
457
|
+
static constexpr uint32_t max_serialized_size()
|
|
458
|
+
{
|
|
459
|
+
return MAX_LENGTH // The number of bytes of the data.
|
|
460
|
+
+ WireFormatter::VarintSize(MAX_LENGTH); // The varint indicating the actual number of bytes.
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
protected:
|
|
464
|
+
|
|
465
|
+
//! Set the current number of items in the array. Only for internal usage.
|
|
466
|
+
/*!
|
|
467
|
+
The value is limited to the maximum lenght of the array.
|
|
468
|
+
*/
|
|
469
|
+
void set_length(uint32_t length) { current_length_ = std::min(length, MAX_LENGTH); }
|
|
470
|
+
|
|
471
|
+
//! Get a non constant pointer to the first element in the array. Only for internal usage.
|
|
472
|
+
DATA_TYPE* get() { return data_.data(); }
|
|
473
|
+
|
|
474
|
+
private:
|
|
475
|
+
|
|
476
|
+
//! The number of characters reserved behind MAX_LENGTH for a null terminator.
|
|
477
|
+
/*!
|
|
478
|
+
Define NULL_TERMINATED_STRINGS to reserve one character per string. It is zero from
|
|
479
|
+
construction on and no write path ever reaches it, every one of them stops at
|
|
480
|
+
MAX_LENGTH, so get_const() of a completely full string is a valid c style string
|
|
481
|
+
without any bookkeeping. The cost is one byte of RAM per string field. A bytes field
|
|
482
|
+
never reserves it, a byte array has no terminator. The default is to reserve nothing,
|
|
483
|
+
which keeps the memory layout of earlier versions.
|
|
484
|
+
*/
|
|
485
|
+
#ifdef NULL_TERMINATED_STRINGS
|
|
486
|
+
static constexpr uint32_t TERMINATOR_LENGTH = std::is_same<char, DATA_TYPE>::value ? 1U : 0U;
|
|
487
|
+
#else
|
|
488
|
+
static constexpr uint32_t TERMINATOR_LENGTH = 0U;
|
|
489
|
+
#endif
|
|
490
|
+
|
|
491
|
+
//! Number of item in the data array.
|
|
492
|
+
uint32_t current_length_ = 0;
|
|
493
|
+
|
|
494
|
+
//! Storage type, an empty stand-in when there is nothing to store, see EmptyArray.
|
|
495
|
+
using Storage = typename std::conditional<(0U < (MAX_LENGTH + TERMINATOR_LENGTH)),
|
|
496
|
+
std::array<DATA_TYPE, MAX_LENGTH + TERMINATOR_LENGTH>,
|
|
497
|
+
internal::EmptyArray<DATA_TYPE>>::type;
|
|
498
|
+
|
|
499
|
+
//! The text, plus the reserved terminator when enabled.
|
|
500
|
+
Storage data_ = {};
|
|
501
|
+
|
|
502
|
+
//! Clamp an index to the last element, zero when there is no element at all.
|
|
503
|
+
static constexpr uint32_t clamp_index(const uint32_t index)
|
|
504
|
+
{
|
|
505
|
+
return (0U < MAX_LENGTH) ? std::min(index, MAX_LENGTH - 1U) : 0U;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
//! View the storage as raw bytes, the form the read buffer copies into.
|
|
509
|
+
uint8_t* data_as_bytes()
|
|
510
|
+
{
|
|
511
|
+
return static_cast<uint8_t*>(static_cast<void*>(data_.data()));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
//! The element at a clamped index, or the scratch element when there is no element at all.
|
|
515
|
+
/*!
|
|
516
|
+
With a maximum length of zero the storage may still hold the reserved terminator. That
|
|
517
|
+
slot must never be handed out, so index access goes to the EmptyArray scratch element.
|
|
518
|
+
*/
|
|
519
|
+
DATA_TYPE& element(const uint32_t index)
|
|
520
|
+
{
|
|
521
|
+
if constexpr(0U < MAX_LENGTH)
|
|
522
|
+
{
|
|
523
|
+
return data_[index];
|
|
524
|
+
}
|
|
525
|
+
else
|
|
526
|
+
{
|
|
527
|
+
return internal::EmptyArray<DATA_TYPE>()[index];
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const DATA_TYPE& element(const uint32_t index) const
|
|
532
|
+
{
|
|
533
|
+
if constexpr(0U < MAX_LENGTH)
|
|
534
|
+
{
|
|
535
|
+
return data_[index];
|
|
536
|
+
}
|
|
537
|
+
else
|
|
538
|
+
{
|
|
539
|
+
return internal::EmptyArray<DATA_TYPE>()[index];
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
}; // End of class FieldStringBytes
|
|
544
|
+
|
|
545
|
+
} // End of namespace internal
|
|
546
|
+
|
|
547
|
+
//! The class definition used in messages for String fields.
|
|
548
|
+
template<uint32_t MAX_LENGTH>
|
|
549
|
+
class FieldString : public internal::FieldStringBytes<MAX_LENGTH, char>
|
|
550
|
+
{
|
|
551
|
+
public:
|
|
552
|
+
|
|
553
|
+
using internal::FieldStringBytes<MAX_LENGTH, char>::set;
|
|
554
|
+
|
|
555
|
+
FieldString() = default;
|
|
556
|
+
~FieldString() = default;
|
|
557
|
+
|
|
558
|
+
//! Assign the values in the right hand side FieldStringBytes object to this object.
|
|
559
|
+
/*!
|
|
560
|
+
This is only compatible with the same data type and length.
|
|
561
|
+
\param[in] rhs The object from which to copy the data.
|
|
562
|
+
\return A reference to this object.
|
|
563
|
+
*/
|
|
564
|
+
template<uint32_t RHS_LENGTH>
|
|
565
|
+
FieldString<MAX_LENGTH>& operator=(const FieldString<RHS_LENGTH>& rhs)
|
|
566
|
+
{
|
|
567
|
+
this->set(::EmbeddedProto::const_string_view{rhs.get_const(), rhs.get_length()});
|
|
568
|
+
return *this;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
//! Assign a c style string to this object.
|
|
572
|
+
/*!
|
|
573
|
+
A short example:
|
|
574
|
+
char text[] = "Foo bar";
|
|
575
|
+
msg.mutable_txt() = text;
|
|
576
|
+
|
|
577
|
+
\param[in] rhs The c style string from which to take the characters and copy it to this object.
|
|
578
|
+
\return A reference to this object used for function chaining.
|
|
579
|
+
*/
|
|
580
|
+
FieldString<MAX_LENGTH>& operator=(const char* const rhs)
|
|
581
|
+
{
|
|
582
|
+
this->set(rhs);
|
|
583
|
+
return *this;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
//! Compare the characters in this object with a c style string.
|
|
587
|
+
/*!
|
|
588
|
+
A short example:
|
|
589
|
+
if(msg.get_name() == "Foo bar") { }
|
|
590
|
+
|
|
591
|
+
\param[in] rhs The c style string to compare the characters in this object with.
|
|
592
|
+
\return True when both hold the same number of characters and all of them are equal.
|
|
593
|
+
*/
|
|
594
|
+
bool operator==(const char* const rhs) const
|
|
595
|
+
{
|
|
596
|
+
bool result = false;
|
|
597
|
+
if(nullptr != rhs)
|
|
598
|
+
{
|
|
599
|
+
const uint32_t rhs_length = strnlen(rhs, MAX_LENGTH + 1);
|
|
600
|
+
result = (rhs_length == this->get_length()) &&
|
|
601
|
+
(0 == memcmp(this->get_const(), rhs, rhs_length));
|
|
602
|
+
}
|
|
603
|
+
return result;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
//! Compare the characters in this object with a c style string.
|
|
607
|
+
/*!
|
|
608
|
+
\param[in] rhs The c style string to compare the characters in this object with.
|
|
609
|
+
\return True when the two differ in length or in any of the characters held.
|
|
610
|
+
*/
|
|
611
|
+
bool operator!=(const char* const rhs) const
|
|
612
|
+
{
|
|
613
|
+
return !(*this == rhs);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
//! Does the given c style string fit in this object without being cut short?
|
|
617
|
+
/*!
|
|
618
|
+
set() stores at most MAX_LENGTH characters and drops the rest. Check first when a cut
|
|
619
|
+
short string would be wrong rather than merely shorter, as with a map key.
|
|
620
|
+
|
|
621
|
+
\param[in] str The c style string to check. A nullptr counts as an empty string.
|
|
622
|
+
\return True when the string is at most MAX_LENGTH characters long.
|
|
623
|
+
*/
|
|
624
|
+
static bool fits(const char* const str)
|
|
625
|
+
{
|
|
626
|
+
return (nullptr == str) || (MAX_LENGTH >= strnlen(str, MAX_LENGTH + 1));
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
//! Assign the data from the given c style string to this object.
|
|
630
|
+
/*!
|
|
631
|
+
\param[in] str The c style string from which to take the characters and copy it to this object.
|
|
632
|
+
*/
|
|
633
|
+
void set(const char* const str)
|
|
634
|
+
{
|
|
635
|
+
if(nullptr != str) {
|
|
636
|
+
const uint32_t str_MAX_LENGTH = strnlen(str, MAX_LENGTH + 1);
|
|
637
|
+
this->set_length(str_MAX_LENGTH);
|
|
638
|
+
uint32_t this_length = this->get_length();
|
|
639
|
+
// If it fits in this object copy the null terminator.
|
|
640
|
+
if(MAX_LENGTH > this_length) {
|
|
641
|
+
++this_length;
|
|
642
|
+
}
|
|
643
|
+
strncpy(this->get(), str, this_length);
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
this->clear();
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
#ifdef MSG_TO_STRING
|
|
651
|
+
|
|
652
|
+
::EmbeddedProto::string_view to_string(::EmbeddedProto::string_view& str, const uint32_t indent_level, char const* name, const bool first_field) const override
|
|
653
|
+
{
|
|
654
|
+
::EmbeddedProto::string_view left_chars = str;
|
|
655
|
+
int32_t n_chars_used = 0;
|
|
656
|
+
|
|
657
|
+
if(!first_field)
|
|
658
|
+
{
|
|
659
|
+
// Add a comma behind the previous field.
|
|
660
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, ",\n");
|
|
661
|
+
if(0 < n_chars_used)
|
|
662
|
+
{
|
|
663
|
+
// Update the character pointer and characters left in the array.
|
|
664
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
665
|
+
left_chars.data += actual_chars_used;
|
|
666
|
+
left_chars.size -= actual_chars_used;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if(nullptr != name)
|
|
671
|
+
{
|
|
672
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "%*s\"%s\": \"%s\"", indent_level, " ", name, this->get_const());
|
|
673
|
+
}
|
|
674
|
+
else
|
|
675
|
+
{
|
|
676
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "%*s\"%s\"", indent_level, " ", this->get_const());
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if(0 < n_chars_used)
|
|
680
|
+
{
|
|
681
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
682
|
+
left_chars.data += actual_chars_used;
|
|
683
|
+
left_chars.size -= actual_chars_used;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
return left_chars;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
#endif // End of MSG_TO_STRING
|
|
690
|
+
|
|
691
|
+
private:
|
|
692
|
+
//! Use our own implementation of limited string length function.
|
|
693
|
+
/*!
|
|
694
|
+
\param s The character array.
|
|
695
|
+
\param len The maximum length to search for a null terminator.
|
|
696
|
+
|
|
697
|
+
\return The length of this character array will be returned or the value of len.
|
|
698
|
+
*/
|
|
699
|
+
static uint32_t strnlen(const char* s, uint32_t len)
|
|
700
|
+
{
|
|
701
|
+
uint32_t i = 0;
|
|
702
|
+
for(; (i < len) && (s[i] != '\0'); ++i)
|
|
703
|
+
{
|
|
704
|
+
// Do nothing but the loop checks.
|
|
705
|
+
}
|
|
706
|
+
return i;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
//! The class definition used in messages for Bytes fields.
|
|
712
|
+
template<uint32_t MAX_LENGTH>
|
|
713
|
+
class FieldBytes : public internal::FieldStringBytes<MAX_LENGTH, uint8_t>
|
|
714
|
+
{
|
|
715
|
+
public:
|
|
716
|
+
FieldBytes() = default;
|
|
717
|
+
~FieldBytes() = default;
|
|
718
|
+
|
|
719
|
+
//! Assign the values in the right hand side FieldStringBytes object to this object.
|
|
720
|
+
/*!
|
|
721
|
+
This is only compatible with the same data type and length.
|
|
722
|
+
\param[in] rhs The object from which to copy the data.
|
|
723
|
+
\return A reference to this object.
|
|
724
|
+
*/
|
|
725
|
+
template<uint32_t RHS_LENGTH>
|
|
726
|
+
FieldBytes<MAX_LENGTH>& operator=(const FieldBytes<RHS_LENGTH>& rhs)
|
|
727
|
+
{
|
|
728
|
+
this->set(::EmbeddedProto::const_bytes_view{rhs.get_const(), rhs.get_length()});
|
|
729
|
+
return *this;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
#ifdef MSG_TO_STRING
|
|
733
|
+
|
|
734
|
+
::EmbeddedProto::string_view to_string(::EmbeddedProto::string_view& str, const uint32_t indent_level, char const* name, const bool first_field) const override
|
|
735
|
+
{
|
|
736
|
+
::EmbeddedProto::string_view left_chars = str;
|
|
737
|
+
int32_t n_chars_used = 0;
|
|
738
|
+
|
|
739
|
+
if(!first_field)
|
|
740
|
+
{
|
|
741
|
+
// Add a comma behind the previous field.
|
|
742
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, ",\n");
|
|
743
|
+
if(0 < n_chars_used)
|
|
744
|
+
{
|
|
745
|
+
// Update the character pointer and characters left in the array.
|
|
746
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
747
|
+
left_chars.data += actual_chars_used;
|
|
748
|
+
left_chars.size -= actual_chars_used;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if(nullptr != name)
|
|
753
|
+
{
|
|
754
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "%*s\"%s\": [\n", indent_level, " ", name );
|
|
755
|
+
}
|
|
756
|
+
else
|
|
757
|
+
{
|
|
758
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "%*s[\n", indent_level, " ");
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if(0 < n_chars_used)
|
|
762
|
+
{
|
|
763
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
764
|
+
left_chars.data += actual_chars_used;
|
|
765
|
+
left_chars.size -= actual_chars_used;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
uint32 field;
|
|
769
|
+
for(uint32_t i = 0; i < this->get_length(); ++i)
|
|
770
|
+
{
|
|
771
|
+
field = this->get_const(i);
|
|
772
|
+
left_chars = field.to_string(left_chars, n_chars_used, nullptr, (0 == i));
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
n_chars_used = snprintf(left_chars.data, left_chars.size, "\n%*s]", n_chars_used - 2, " ");
|
|
776
|
+
|
|
777
|
+
if(0 < n_chars_used)
|
|
778
|
+
{
|
|
779
|
+
const int32_t actual_chars_used = EmbeddedProto::min(n_chars_used, left_chars.size);
|
|
780
|
+
left_chars.data += actual_chars_used;
|
|
781
|
+
left_chars.size -= actual_chars_used;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
return left_chars;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
#endif // End of MSG_TO_STRING
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
} // End of namespace EmbeddedProto
|
|
792
|
+
|
|
793
|
+
#endif // End of _FIELD_STRING_BYTES_H_
|