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,688 @@
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 _MESSAGE_CALLBACK_H_
25
+ #define _MESSAGE_CALLBACK_H_
26
+
27
+ #include "MessageInterface.h"
28
+ #include "Functional.h"
29
+ #include "Errors.h"
30
+ #include "WireFormatter.h"
31
+ #include "MessageState.h"
32
+
33
+ #include <cstdint>
34
+ #include <type_traits>
35
+
36
+
37
+ namespace EmbeddedProto
38
+ {
39
+
40
+ //! A repeated message field whose elements are streamed to/from the user, not stored.
41
+ /*!
42
+ MessageCallback is a drop-in storage type for a repeated message field that
43
+ owns no element array. Instead of holding N sub-messages it moves one across
44
+ the interface seam at a time:
45
+
46
+ - on serialize, each element is pulled from a user *source*, filled into a
47
+ single transient sub-message and emitted;
48
+ - on deserialize, every parsed element lands in the transient and is pushed
49
+ to a user *sink*.
50
+
51
+ Two element framings are offered, the generator picks one at generation time:
52
+
53
+ - DELIMITED groups (serialize_expanded), a START_GROUP / END_GROUP pair per
54
+ element, used for a plain repeated message field with
55
+ features.message_encoding = DELIMITED;
56
+ - length delimited blocks (serialize_expanded_len), tag + size + body per
57
+ element, used for a map field so its entries stay readable by a standard
58
+ protoc peer.
59
+
60
+ Both are single pass: the element sits in the transient when it is written, so
61
+ even the length prefix is measured without pulling it a second time. What a
62
+ stream can not provide is a size for the *whole* field ahead of its elements,
63
+ which is why serialize() refuses with CALLBACK_SEQUENCE when placed under a
64
+ length prefixed ancestor. This lets a device relay arbitrarily many
65
+ sub-messages through a fixed, tiny RAM footprint: the two Functional handles
66
+ plus one transient sub-message (never the whole collection). It plugs in
67
+ through the callbackStorage generator option.
68
+
69
+ Only repeated message fields are supported here; a singular message callback
70
+ is a separate, later capability.
71
+
72
+ \tparam MSG_TYPE The generated message type streamed through this field (a
73
+ MessageInterface).
74
+ */
75
+ template<class MSG_TYPE>
76
+ class MessageCallback : public MessageInterface
77
+ {
78
+ static_assert(std::is_base_of<::EmbeddedProto::MessageInterface, MSG_TYPE>::value,
79
+ "MessageCallback streams a generated message type (a MessageInterface).");
80
+
81
+ public:
82
+
83
+ //! Pull callback used during serialize: fill \p element, return true when a value was produced, false to signal the end of the stream.
84
+ using SourceCallback = Functional<bool(MSG_TYPE&)>;
85
+
86
+ //! Push callback used during deserialize: consume one parsed \p element, return an Error (NO_ERRORS to continue).
87
+ using SinkCallback = Functional<Error(const MSG_TYPE&)>;
88
+
89
+ MessageCallback() = default;
90
+ ~MessageCallback() = default;
91
+
92
+ // --- Binding (reference-taking, no ownership) --------------------------
93
+
94
+ //! Bind the source used to pull elements during serialization.
95
+ void set_source(const SourceCallback& source) { source_ = source; }
96
+
97
+ //! Bind the sink used to push elements during deserialization.
98
+ void set_sink(const SinkCallback& sink) { sink_ = sink; }
99
+
100
+ //! Remove the bound source.
101
+ void clear_source() { source_.clear(); }
102
+
103
+ //! Remove the bound sink.
104
+ void clear_sink() { sink_.clear(); }
105
+
106
+ //! Check whether a source (pull) callback is bound.
107
+ bool is_source_set() const { return source_.is_set(); }
108
+
109
+ //! Check whether a sink (push) callback is bound.
110
+ bool is_sink_set() const { return sink_.is_set(); }
111
+
112
+ //! Require a binding for the direction being used.
113
+ /*!
114
+ When strict, streaming without the relevant callback bound returns
115
+ CALLBACK_NOT_SET instead of silently discarding (deserialize) or
116
+ emitting nothing (serialize).
117
+ */
118
+ void set_strict(bool strict) { strict_ = strict; }
119
+
120
+ //! Whether strict (require-binding) mode is enabled.
121
+ bool is_strict() const { return strict_; }
122
+
123
+ //! Copy the bindings from another callback field (used by the generated message copy/assignment).
124
+ /*!
125
+ A callback field owns no elements to copy, so copying it copies the source
126
+ and sink handles: the copy streams through the same user callbacks.
127
+
128
+ \return Always NO_ERRORS, for signature compatibility with a resident field's set().
129
+ */
130
+ Error set(const MessageCallback<MSG_TYPE>& rhs)
131
+ {
132
+ source_ = rhs.source_;
133
+ sink_ = rhs.sink_;
134
+ strict_ = rhs.strict_;
135
+ return Error::NO_ERRORS;
136
+ }
137
+
138
+ // --- Repeated-field-shaped interface -----------------------------------
139
+
140
+ //! Number of elements streamed so far (a running counter, not a capacity). Presence is get_length() > 0.
141
+ uint32_t get_length() const { return length_; }
142
+
143
+ //! Required of a callbackStorage message type.
144
+ /*!
145
+ A stream has no finite serialized size, so report the unbounded sentinel; a
146
+ message with a callback field therefore cannot be statically buffer-sized,
147
+ which is inherent to streaming.
148
+ */
149
+ static constexpr uint32_t max_serialized_size(const uint32_t field_number)
150
+ {
151
+ static_cast<void>(field_number);
152
+ return UINT32_MAX;
153
+ }
154
+
155
+ // --- MessageInterface / Field interface --------------------------------
156
+
157
+ //! Guard the LEN / size-pass serialization of a streaming field.
158
+ /*!
159
+ A callback message owns no element to write here and is emitted EXPANDED
160
+ as groups only (serialize_expanded). This method is what a size pass
161
+ reaches via Field::serialized_size(), and what serialize_as_group would
162
+ call. Any real call means the field was placed where a length-delimited
163
+ (LEN) framing is required (e.g. under a LEN ancestor), which is
164
+ unsupported for streaming storage: report CALLBACK_SEQUENCE instead of
165
+ draining the source.
166
+ */
167
+ Error serialize(WriteBufferInterface& buffer) const override
168
+ {
169
+ static_cast<void>(buffer);
170
+ return Error::CALLBACK_SEQUENCE;
171
+ }
172
+
173
+ //! Pull elements from the bound source and emit each as a DELIMITED group.
174
+ /*!
175
+ One START_GROUP / body / END_GROUP is written per element (the same wire
176
+ form as an EXPANDED repeated message field), so no field-level size prefix
177
+ is needed and the source is drained exactly once in a single pass.
178
+ Production ends when the source returns false. With no source bound
179
+ nothing is emitted (NO_ERRORS), unless strict mode is on, in which case
180
+ CALLBACK_NOT_SET is returned.
181
+
182
+ \param field_number The field number written in each element's group tags.
183
+ \param buffer The destination buffer.
184
+ */
185
+ Error serialize_expanded(uint32_t field_number, WriteBufferInterface& buffer) const
186
+ {
187
+ Error return_value = Error::NO_ERRORS;
188
+ if(!source_.is_set())
189
+ {
190
+ if(strict_)
191
+ {
192
+ return_value = Error::CALLBACK_NOT_SET;
193
+ }
194
+ // Not strict: no source bound, emit nothing.
195
+ }
196
+ else
197
+ {
198
+ bool more = true;
199
+ while(more && (Error::NO_ERRORS == return_value))
200
+ {
201
+ bool produced = false;
202
+ transient_.clear();
203
+ static_cast<void>(source_.invoke(produced, transient_));
204
+ if(produced)
205
+ {
206
+ return_value = transient_.serialize_as_group(field_number, buffer);
207
+ if(Error::NO_ERRORS == return_value)
208
+ {
209
+ ++length_;
210
+ }
211
+ }
212
+ else
213
+ {
214
+ more = false;
215
+ }
216
+ }
217
+ }
218
+ return return_value;
219
+ }
220
+
221
+ //! Pull elements from the bound source and emit each as a length delimited block.
222
+ /*!
223
+ The wire form a map field needs: one tag + size + body per element, identical to what a
224
+ resident repeated message field writes, so the bytes stay readable by a standard protoc
225
+ peer.
226
+
227
+ A per element length prefix costs no second pull. The element is sitting in the transient
228
+ when its size is measured, so serialized_size() walks the transient and not the user
229
+ callback: the source is still drained exactly once. This is unlike a length prefix around
230
+ the *whole* field, which would have to know the total before any element was pulled; that
231
+ case is still refused by serialize() above.
232
+
233
+ \param field_number The field number written in each element's tag.
234
+ \param buffer The destination buffer.
235
+ */
236
+ Error serialize_expanded_len(uint32_t field_number, WriteBufferInterface& buffer) const
237
+ {
238
+ Error return_value = Error::NO_ERRORS;
239
+ if(!source_.is_set())
240
+ {
241
+ if(strict_)
242
+ {
243
+ return_value = Error::CALLBACK_NOT_SET;
244
+ }
245
+ // Not strict: no source bound, emit nothing.
246
+ }
247
+ else
248
+ {
249
+ bool more = true;
250
+ while(more && (Error::NO_ERRORS == return_value))
251
+ {
252
+ bool produced = false;
253
+ transient_.clear();
254
+ static_cast<void>(source_.invoke(produced, transient_));
255
+ if(produced)
256
+ {
257
+ return_value = transient_.serialize_len(field_number, transient_.serialized_size(),
258
+ buffer, true);
259
+ if(Error::NO_ERRORS == return_value)
260
+ {
261
+ ++length_;
262
+ }
263
+ }
264
+ else
265
+ {
266
+ more = false;
267
+ }
268
+ }
269
+ }
270
+ return return_value;
271
+ }
272
+
273
+ //! Deserialize one group element and push it to the sink.
274
+ /*!
275
+ The opening START_GROUP tag has been consumed by the caller. The element's
276
+ body is read into the transient (which stops at its matching END_GROUP)
277
+ and then pushed to the bound sink (drain-and-discard when unbound and not
278
+ strict). Called once per element.
279
+ */
280
+ Error deserialize(ReadBufferInterface& buffer) override
281
+ {
282
+ transient_.clear();
283
+ Error return_value = transient_.deserialize(buffer);
284
+ if(Error::NO_ERRORS == return_value)
285
+ {
286
+ return_value = push_to_sink(transient_);
287
+ if(Error::NO_ERRORS == return_value)
288
+ {
289
+ ++length_;
290
+ }
291
+ }
292
+ return return_value;
293
+ }
294
+
295
+ #ifdef PARTIAL_SERIALIZATION_ENABLED
296
+ //! Guard the whole-message partial serialize path.
297
+ /*!
298
+ A callback message is emitted EXPANDED as groups only (via
299
+ serialize_partial_as_field_expanded, which frames each element and streams
300
+ its body through the transient's own serialize_partial). This entry point
301
+ would LEN/size-pass the field, which a stream cannot provide: report
302
+ CALLBACK_SEQUENCE.
303
+ */
304
+ Error serialize_partial(WriteBufferInterface& buffer, MessageState& state) const override
305
+ {
306
+ static_cast<void>(buffer);
307
+ static_cast<void>(state);
308
+ return Error::CALLBACK_SEQUENCE;
309
+ }
310
+
311
+ //! Resumable EXPANDED pull-serialize for the partial engine.
312
+ /*!
313
+ Emits one START_GROUP / body / END_GROUP per element, pulling from the
314
+ source, and survives a write buffer that fills mid-element. The group
315
+ framing is inlined at this field's state level (state.phase drives
316
+ TAG -> DATA -> SIZE(reused for END_GROUP) -> next element; state.child
317
+ streams the element body), so a callback message field consumes no more
318
+ state-stack depth than a resident one. An element is pulled only when a
319
+ new group is started (guarded by element_loaded_), so a BUFFER_FULL resume
320
+ never double-pulls the source.
321
+ */
322
+ Error serialize_partial_as_field_expanded(uint32_t field_number,
323
+ WriteBufferInterface& buffer,
324
+ MessageState& state,
325
+ bool optional) const
326
+ {
327
+ static_cast<void>(optional);
328
+ Error return_value = Error::NO_ERRORS;
329
+ bool more = true;
330
+ while(more && (Error::NO_ERRORS == return_value))
331
+ {
332
+ if(::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.phase)
333
+ {
334
+ // The whole stream has been drained.
335
+ more = false;
336
+ }
337
+ else if(::EmbeddedProto::FieldProcessingPhase::TAG == state.phase)
338
+ {
339
+ return_value = serialize_partial_begin_group(field_number, buffer, state);
340
+ }
341
+ else if(::EmbeddedProto::FieldProcessingPhase::DATA == state.phase)
342
+ {
343
+ if(nullptr != state.child)
344
+ {
345
+ return_value = transient_.serialize_partial(buffer, *state.child);
346
+ if((Error::NO_ERRORS == return_value)
347
+ && (::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.child->phase))
348
+ {
349
+ // Body complete; the END_GROUP tag still has to be written. Reuse
350
+ // the (otherwise unused) SIZE phase to mark "END_GROUP pending".
351
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::SIZE;
352
+ }
353
+ }
354
+ else
355
+ {
356
+ return_value = Error::NESTING_TOO_DEEP;
357
+ }
358
+ }
359
+ else
360
+ {
361
+ // Phase SIZE (reused): write the END_GROUP tag, then advance to the
362
+ // next element.
363
+ const uint32_t tag = WireFormatter::MakeTag(field_number, WireFormatter::WireType::END_GROUP);
364
+ if(buffer.get_available_size() >= WireFormatter::VarintSize(tag))
365
+ {
366
+ return_value = WireFormatter::SerializeVarint(tag, buffer);
367
+ if(Error::NO_ERRORS == return_value)
368
+ {
369
+ ++length_;
370
+ element_loaded_ = false;
371
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::TAG;
372
+ if(nullptr != state.child)
373
+ {
374
+ state.child->reset();
375
+ }
376
+ }
377
+ }
378
+ else
379
+ {
380
+ return_value = Error::BUFFER_FULL;
381
+ }
382
+ }
383
+ }
384
+ return return_value;
385
+ }
386
+
387
+ //! Resumable, length delimited variant of serialize_partial_as_field_expanded.
388
+ /*!
389
+ The partial counterpart of serialize_expanded_len: one tag + size + body per element,
390
+ resuming where a full buffer stopped. The element stays resident in the transient across a
391
+ resume, so the source is pulled exactly once per element here as well.
392
+
393
+ \param field_number The field number written in each element's tag.
394
+ \param buffer The destination buffer.
395
+ \param state External state tracking progress through the stream.
396
+ \param optional Unused, an entry is always emitted, also when it is empty.
397
+ */
398
+ Error serialize_partial_as_field_expanded_len(uint32_t field_number,
399
+ WriteBufferInterface& buffer,
400
+ MessageState& state,
401
+ bool optional) const
402
+ {
403
+ static_cast<void>(optional);
404
+ Error return_value = Error::NO_ERRORS;
405
+ bool more = true;
406
+ while(more && (Error::NO_ERRORS == return_value))
407
+ {
408
+ if(::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.phase)
409
+ {
410
+ // The whole stream has been drained.
411
+ more = false;
412
+ }
413
+ else if(::EmbeddedProto::FieldProcessingPhase::DATA == state.phase)
414
+ {
415
+ if(nullptr != state.child)
416
+ {
417
+ return_value = transient_.serialize_partial(buffer, *state.child);
418
+ if((Error::NO_ERRORS == return_value)
419
+ && (::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.child->phase))
420
+ {
421
+ finish_len_element(state);
422
+ }
423
+ }
424
+ else
425
+ {
426
+ return_value = Error::NESTING_TOO_DEEP;
427
+ }
428
+ }
429
+ else
430
+ {
431
+ // Phase TAG or SIZE: pull the next element if needed and write its tag and size.
432
+ return_value = serialize_partial_begin_len(field_number, buffer, state);
433
+ }
434
+ }
435
+ return return_value;
436
+ }
437
+
438
+ //! Resumable push-deserialize of one group element for the partial engine.
439
+ /*!
440
+ Invoked by the inherited deserialize_partial_as_group, which consumes the
441
+ START_GROUP tag and streams the element body here. The body is read into
442
+ the transient; when it consumes its matching END_GROUP the transient's
443
+ state reports COMPLETE, at which point the element is pushed to the sink
444
+ and the transient is reset for the next element. Returns END_OF_BUFFER
445
+ (leaving the state mid-body) when the read buffer drains, so the next call
446
+ resumes where it stopped.
447
+ */
448
+ Error deserialize_partial(ReadBufferInterface& buffer, MessageState& state) override
449
+ {
450
+ Error return_value = transient_.deserialize_partial(buffer, state);
451
+ if((Error::NO_ERRORS == return_value)
452
+ && (::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.phase))
453
+ {
454
+ return_value = push_to_sink(transient_);
455
+ if(Error::NO_ERRORS == return_value)
456
+ {
457
+ ++length_;
458
+ }
459
+ transient_.clear();
460
+ }
461
+ return return_value;
462
+ }
463
+ //! Resumable push-deserialize of one length delimited element for the partial engine.
464
+ /*!
465
+ The length delimited counterpart of the group path used by deserialize_partial. The base
466
+ class streams the element body into the transient and marks this *field* COMPLETE once the
467
+ declared number of bytes has been consumed. That completion lands on the field state and
468
+ not on the transient's own state, which is why the element is pushed to the sink from here
469
+ instead of from deserialize_partial, the way the group path does it.
470
+ */
471
+ Error deserialize_partial_as_field(ReadBufferInterface& buffer, MessageState& state) override
472
+ {
473
+ Error return_value = MessageInterface::deserialize_partial_as_field(buffer, state);
474
+ if((Error::NO_ERRORS == return_value)
475
+ && (::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.phase))
476
+ {
477
+ return_value = push_to_sink(transient_);
478
+ if(Error::NO_ERRORS == return_value)
479
+ {
480
+ ++length_;
481
+ }
482
+ transient_.clear();
483
+ }
484
+ return return_value;
485
+ }
486
+ #endif // PARTIAL_SERIALIZATION_ENABLED
487
+
488
+ //! Reset the streaming state (the element counter). Bindings are kept.
489
+ void clear() override { length_ = 0U; }
490
+
491
+ #ifdef MSG_TO_STRING
492
+ //! A callback field holds no resident value to print, so leave the string unchanged.
493
+ ::EmbeddedProto::string_view to_string(::EmbeddedProto::string_view& str, const uint32_t indent_level, char const* name, const bool first_field) const override
494
+ {
495
+ static_cast<void>(indent_level);
496
+ static_cast<void>(name);
497
+ static_cast<void>(first_field);
498
+ return str;
499
+ }
500
+ #endif // MSG_TO_STRING
501
+
502
+ private:
503
+
504
+ //! Push one parsed element to the sink, or drain-and-discard when no sink is bound (CALLBACK_NOT_SET in strict mode).
505
+ Error push_to_sink(const MSG_TYPE& element)
506
+ {
507
+ Error return_value = Error::NO_ERRORS;
508
+ if(sink_.is_set())
509
+ {
510
+ Error sink_result = Error::NO_ERRORS;
511
+ static_cast<void>(sink_.invoke(sink_result, element));
512
+ return_value = sink_result;
513
+ }
514
+ else if(strict_)
515
+ {
516
+ return_value = Error::CALLBACK_NOT_SET;
517
+ }
518
+ else
519
+ {
520
+ // No sink bound and not strict: drain and discard.
521
+ static_cast<void>(element);
522
+ }
523
+ return return_value;
524
+ }
525
+
526
+ #ifdef PARTIAL_SERIALIZATION_ENABLED
527
+ //! Pull the next element (once, guarded by element_loaded_) and write its tag and size.
528
+ /*!
529
+ The length delimited counterpart of serialize_partial_begin_group. The size is measured on
530
+ the transient after the pull, so no element is ever produced twice. When the source is
531
+ exhausted (or unbound and not strict) the field is marked COMPLETE.
532
+
533
+ An entry that serializes to zero bytes is finished here: serialize_partial_tag_and_size
534
+ marks a zero sized field COMPLETE because it has no body to write, which for a stream
535
+ would otherwise read as "the whole field is done" instead of "this element is done".
536
+ */
537
+ Error serialize_partial_begin_len(uint32_t field_number,
538
+ WriteBufferInterface& buffer,
539
+ MessageState& state) const
540
+ {
541
+ Error return_value = Error::NO_ERRORS;
542
+ if(!element_loaded_)
543
+ {
544
+ if(!source_.is_set())
545
+ {
546
+ if(strict_)
547
+ {
548
+ return_value = Error::CALLBACK_NOT_SET;
549
+ }
550
+ else
551
+ {
552
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
553
+ }
554
+ }
555
+ else
556
+ {
557
+ bool produced = false;
558
+ transient_.clear();
559
+ static_cast<void>(source_.invoke(produced, transient_));
560
+ if(produced)
561
+ {
562
+ element_loaded_ = true;
563
+ // Measured once, here, and kept in the state so a resume after a full buffer does
564
+ // not walk the transient again.
565
+ state.size_value = transient_.serialized_size();
566
+ if(nullptr != state.child)
567
+ {
568
+ state.child->reset();
569
+ }
570
+ }
571
+ else
572
+ {
573
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
574
+ }
575
+ }
576
+ }
577
+
578
+ if((Error::NO_ERRORS == return_value) && element_loaded_)
579
+ {
580
+ return_value = serialize_partial_tag_and_size(field_number, state.size_value, buffer,
581
+ state, true);
582
+ if((Error::NO_ERRORS == return_value)
583
+ && (::EmbeddedProto::FieldProcessingPhase::COMPLETE == state.phase))
584
+ {
585
+ finish_len_element(state);
586
+ }
587
+ }
588
+ return return_value;
589
+ }
590
+
591
+ //! Close off one length delimited element and arm the state for the next one.
592
+ void finish_len_element(MessageState& state) const
593
+ {
594
+ ++length_;
595
+ element_loaded_ = false;
596
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::TAG;
597
+ if(nullptr != state.child)
598
+ {
599
+ state.child->reset();
600
+ }
601
+ }
602
+
603
+ //! Pull the next element (once, guarded by element_loaded_) and write its START_GROUP tag.
604
+ /*!
605
+ When the source is exhausted (or unbound and not strict) the field is
606
+ marked COMPLETE. Otherwise the pulled element stays resident in the
607
+ transient across a BUFFER_FULL resume so it is never pulled twice.
608
+ */
609
+ Error serialize_partial_begin_group(uint32_t field_number,
610
+ WriteBufferInterface& buffer,
611
+ MessageState& state) const
612
+ {
613
+ Error return_value = Error::NO_ERRORS;
614
+ if(!element_loaded_)
615
+ {
616
+ if(!source_.is_set())
617
+ {
618
+ if(strict_)
619
+ {
620
+ return_value = Error::CALLBACK_NOT_SET;
621
+ }
622
+ else
623
+ {
624
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
625
+ }
626
+ }
627
+ else
628
+ {
629
+ bool produced = false;
630
+ transient_.clear();
631
+ static_cast<void>(source_.invoke(produced, transient_));
632
+ if(produced)
633
+ {
634
+ element_loaded_ = true;
635
+ if(nullptr != state.child)
636
+ {
637
+ state.child->reset();
638
+ }
639
+ }
640
+ else
641
+ {
642
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::COMPLETE;
643
+ }
644
+ }
645
+ }
646
+
647
+ if((Error::NO_ERRORS == return_value) && element_loaded_)
648
+ {
649
+ const uint32_t tag = WireFormatter::MakeTag(field_number, WireFormatter::WireType::START_GROUP);
650
+ if(buffer.get_available_size() >= WireFormatter::VarintSize(tag))
651
+ {
652
+ return_value = WireFormatter::SerializeVarint(tag, buffer);
653
+ if(Error::NO_ERRORS == return_value)
654
+ {
655
+ state.phase = ::EmbeddedProto::FieldProcessingPhase::DATA;
656
+ }
657
+ }
658
+ else
659
+ {
660
+ return_value = Error::BUFFER_FULL;
661
+ }
662
+ }
663
+ return return_value;
664
+ }
665
+ #endif // PARTIAL_SERIALIZATION_ENABLED
666
+
667
+ //! Running count of elements streamed through this field. Mutable because serialize is const yet advances the counter as elements are pulled.
668
+ mutable uint32_t length_ = 0U;
669
+
670
+ //! Set while a pulled element awaits its group being written, so a BUFFER_FULL resume does not pull it again.
671
+ mutable bool element_loaded_ = false;
672
+
673
+ //! When true, streaming without a bound callback is an error rather than a silent drain/no-op.
674
+ bool strict_ = false;
675
+
676
+ //! Single sub-message landing slot required to assemble/parse one element. It is not stream storage: the collection owns no per-element buffer.
677
+ mutable MSG_TYPE transient_ = {};
678
+
679
+ //! Pull callback invoked to produce elements while serializing.
680
+ SourceCallback source_{};
681
+
682
+ //! Push callback invoked to consume elements while deserializing.
683
+ SinkCallback sink_{};
684
+ };
685
+
686
+ } // End of namespace EmbeddedProto
687
+
688
+ #endif // End of _MESSAGE_CALLBACK_H_