1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <algorithm>
17 #include <array>
18 #include <cstddef>
19 #include <cstring>
20 #include <string_view>
21
22 #include "pw_assert/assert.h"
23 #include "pw_bytes/bit.h"
24 #include "pw_bytes/endian.h"
25 #include "pw_bytes/span.h"
26 #include "pw_containers/vector.h"
27 #include "pw_protobuf/config.h"
28 #include "pw_protobuf/internal/codegen.h"
29 #include "pw_protobuf/wire_format.h"
30 #include "pw_span/span.h"
31 #include "pw_status/status.h"
32 #include "pw_status/try.h"
33 #include "pw_stream/memory_stream.h"
34 #include "pw_stream/stream.h"
35 #include "pw_varint/varint.h"
36
37 namespace pw::protobuf {
38
39 // Provides a size estimate to help with sizing buffers passed to
40 // StreamEncoder and MemoryEncoder objects.
41 //
42 // Args:
43 // max_message_size: For MemoryEncoder objects, this is the max expected size
44 // of the final proto. For StreamEncoder objects, this should be the max
45 // size of any nested proto submessage that will be built with this encoder
46 // (recursively accumulating the size from the root submessage). If your
47 // proto will encode many large submessages, this value should just be the
48 // size of the largest one.
49 // max_nested_depth: The max number of nested submessage encoders that are
50 // expected to be open simultaneously to encode this proto message.
MaxScratchBufferSize(size_t max_message_size,size_t max_nested_depth)51 constexpr size_t MaxScratchBufferSize(size_t max_message_size,
52 size_t max_nested_depth) {
53 return max_message_size + max_nested_depth * config::kMaxVarintSize;
54 }
55
56 // Write a varint value to the writer.
57 //
58 // Args:
59 // value: The value of the varint to write
60 // writer: The writer for writing to output.
61 //
62 // Returns:
63 // OK - varint is written successfully
64 //
65 // Errors encountered by the `writer` will be returned as it is.
WriteVarint(uint64_t value,stream::Writer & writer)66 inline Status WriteVarint(uint64_t value, stream::Writer& writer) {
67 std::array<std::byte, varint::kMaxVarint64SizeBytes> varint_encode_buffer;
68 const size_t varint_size =
69 pw::varint::EncodeLittleEndianBase128(value, varint_encode_buffer);
70 return writer.Write(span(varint_encode_buffer).first(varint_size));
71 }
72
73 // Write the field key and length prefix for a length-delimited field. It is
74 // up to the caller to ensure that this will be followed by an exact number
75 // of bytes written for the field in order to form a valid proto message.
76 //
77 // Args:
78 // field_number: The field number for the field.
79 // payload_size: The size of the payload.
80 // writer: The output writer to write to
81 //
82 //
83 // Returns:
84 // OK - Field key is written successfully
85 //
86 // Errors encountered by the `writer` will be returned as it is.
87 //
88 // Precondition: The field_number must be a ValidFieldNumber.
89 // Precondition: `data_size_bytes` must be smaller than
90 // std::numeric_limits<uint32_t>::max()
WriteLengthDelimitedKeyAndLengthPrefix(uint32_t field_number,size_t payload_size,stream::Writer & writer)91 inline Status WriteLengthDelimitedKeyAndLengthPrefix(uint32_t field_number,
92 size_t payload_size,
93 stream::Writer& writer) {
94 PW_TRY(WriteVarint(FieldKey(field_number, WireType::kDelimited), writer));
95 return WriteVarint(payload_size, writer);
96 }
97
98 // Forward declaration. StreamEncoder and MemoryEncoder are very tightly
99 // coupled.
100 class MemoryEncoder;
101
102 // A protobuf encoder that encodes serialized proto data to a
103 // pw::stream::Writer.
104 class StreamEncoder {
105 public:
106 // The StreamEncoder will serialize proto data to the pw::stream::Writer
107 // provided through the constructor. The scratch buffer provided is for
108 // internal use ONLY and should not be considered valid proto data.
109 //
110 // If a StreamEncoder object will be writing nested proto messages, it must
111 // provide a scratch buffer large enough to hold the largest submessage some
112 // additional overhead incurred by the encoder's implementation. It's a good
113 // idea to be generous when sizing this buffer. MaxScratchBufferSize() can be
114 // helpful in providing an estimated size for this buffer. The scratch buffer
115 // must exist for the lifetime of the StreamEncoder object.
116 //
117 // StreamEncoder objects that do not write nested proto messages can
118 // provide a zero-length scratch buffer.
StreamEncoder(stream::Writer & writer,ByteSpan scratch_buffer)119 constexpr StreamEncoder(stream::Writer& writer, ByteSpan scratch_buffer)
120 : status_(OkStatus()),
121 write_when_empty_(true),
122 parent_(nullptr),
123 nested_field_number_(0),
124 memory_writer_(scratch_buffer),
125 writer_(writer) {}
126
127 // Precondition: Encoder has no active child encoder.
128 //
129 // Postcondition: If this encoder is a nested one, the parent encoder is
130 // unlocked and proto encoding may resume on the parent.
~StreamEncoder()131 ~StreamEncoder() { CloseEncoder(); }
132
133 // Disallow copy/assign to avoid confusion about who owns the buffer.
134 StreamEncoder& operator=(const StreamEncoder& other) = delete;
135 StreamEncoder(const StreamEncoder& other) = delete;
136
137 // It's not safe to move an encoder as it could cause another encoder's
138 // parent_ pointer to become invalid.
139 StreamEncoder& operator=(StreamEncoder&& other) = delete;
140
141 // Closes this encoder, finalizing its output.
142 //
143 // This method is called automatically by `StreamEncoder`'s destructor, but
144 // may be invoked manually in order to close an encoder before the end of its
145 // lexical scope.
146 //
147 // Precondition: Encoder has no active child encoder.
148 //
149 // Postcondition: If this encoder is a nested one, the parent encoder is
150 // unlocked and proto encoding may resume on the parent. No more writes
151 // to this encoder may be performed.
152 void CloseEncoder();
153
154 // Forwards the conservative write limit of the underlying
155 // pw::stream::Writer.
156 //
157 // Precondition: Encoder has no active child encoder.
ConservativeWriteLimit()158 size_t ConservativeWriteLimit() const {
159 PW_ASSERT(!nested_encoder_open());
160 return writer_.ConservativeWriteLimit();
161 }
162
163 enum class EmptyEncoderBehavior { kWriteFieldNumber, kWriteNothing };
164
165 // Creates a nested encoder with the provided field number. Once this is
166 // called, the parent encoder is locked and not available for use until the
167 // nested encoder is finalized (either explicitly or through destruction).
168 //
169 // Precondition: Encoder has no active child encoder.
170 //
171 // Postcondition: Until the nested child encoder has been destroyed, this
172 // encoder cannot be used.
173 StreamEncoder GetNestedEncoder(uint32_t field_number,
174 EmptyEncoderBehavior empty_encoder_behavior =
175 EmptyEncoderBehavior::kWriteFieldNumber) {
176 return GetNestedEncoder(
177 field_number, /*write_when_empty=*/
178 empty_encoder_behavior == EmptyEncoderBehavior::kWriteFieldNumber);
179 }
180
181 // Returns the current encoder's status.
182 //
183 // Precondition: Encoder has no active child encoder.
status()184 Status status() const {
185 PW_ASSERT(!nested_encoder_open());
186 return status_;
187 }
188
189 // Writes a proto uint32 key-value pair.
190 //
191 // Precondition: Encoder has no active child encoder.
WriteUint32(uint32_t field_number,uint32_t value)192 Status WriteUint32(uint32_t field_number, uint32_t value) {
193 return WriteUint64(field_number, value);
194 }
195
196 // Writes a repeated uint32 using packed encoding.
197 //
198 // Precondition: Encoder has no active child encoder.
WritePackedUint32(uint32_t field_number,span<const uint32_t> values)199 Status WritePackedUint32(uint32_t field_number, span<const uint32_t> values) {
200 return WritePackedVarints(
201 field_number, values, internal::VarintType::kNormal);
202 }
203
204 // Writes a repeated uint32 using packed encoding.
205 //
206 // Precondition: Encoder has no active child encoder.
WriteRepeatedUint32(uint32_t field_number,const pw::Vector<uint32_t> & values)207 Status WriteRepeatedUint32(uint32_t field_number,
208 const pw::Vector<uint32_t>& values) {
209 return WritePackedVarints(field_number,
210 span(values.data(), values.size()),
211 internal::VarintType::kNormal);
212 }
213
214 // Writes a proto uint64 key-value pair.
215 //
216 // Precondition: Encoder has no active child encoder.
WriteUint64(uint32_t field_number,uint64_t value)217 Status WriteUint64(uint32_t field_number, uint64_t value) {
218 return WriteVarintField(field_number, value);
219 }
220
221 // Writes a repeated uint64 using packed encoding.
222 //
223 // Precondition: Encoder has no active child encoder.
WritePackedUint64(uint64_t field_number,span<const uint64_t> values)224 Status WritePackedUint64(uint64_t field_number, span<const uint64_t> values) {
225 return WritePackedVarints(
226 field_number, values, internal::VarintType::kNormal);
227 }
228
229 // Writes a repeated uint64 using packed encoding.
230 //
231 // Precondition: Encoder has no active child encoder.
WriteRepeatedUint64(uint32_t field_number,const pw::Vector<uint64_t> & values)232 Status WriteRepeatedUint64(uint32_t field_number,
233 const pw::Vector<uint64_t>& values) {
234 return WritePackedVarints(field_number,
235 span(values.data(), values.size()),
236 internal::VarintType::kNormal);
237 }
238
239 // Writes a proto int32 key-value pair.
240 //
241 // Precondition: Encoder has no active child encoder.
WriteInt32(uint32_t field_number,int32_t value)242 Status WriteInt32(uint32_t field_number, int32_t value) {
243 return WriteUint64(field_number, value);
244 }
245
246 // Writes a repeated int32 using packed encoding.
247 //
248 // Precondition: Encoder has no active child encoder.
WritePackedInt32(uint32_t field_number,span<const int32_t> values)249 Status WritePackedInt32(uint32_t field_number, span<const int32_t> values) {
250 return WritePackedVarints(
251 field_number,
252 span(reinterpret_cast<const uint32_t*>(values.data()), values.size()),
253 internal::VarintType::kNormal);
254 }
255
256 // Writes a repeated int32 using packed encoding.
257 //
258 // Precondition: Encoder has no active child encoder.
WriteRepeatedInt32(uint32_t field_number,const pw::Vector<int32_t> & values)259 Status WriteRepeatedInt32(uint32_t field_number,
260 const pw::Vector<int32_t>& values) {
261 return WritePackedVarints(
262 field_number,
263 span(reinterpret_cast<const uint32_t*>(values.data()), values.size()),
264 internal::VarintType::kNormal);
265 }
266
267 // Writes a proto int64 key-value pair.
268 //
269 // Precondition: Encoder has no active child encoder.
WriteInt64(uint32_t field_number,int64_t value)270 Status WriteInt64(uint32_t field_number, int64_t value) {
271 return WriteUint64(field_number, value);
272 }
273
274 // Writes a repeated int64 using packed encoding.
275 //
276 // Precondition: Encoder has no active child encoder.
WritePackedInt64(uint32_t field_number,span<const int64_t> values)277 Status WritePackedInt64(uint32_t field_number, span<const int64_t> values) {
278 return WritePackedVarints(
279 field_number,
280 span(reinterpret_cast<const uint64_t*>(values.data()), values.size()),
281 internal::VarintType::kNormal);
282 }
283
284 // Writes a repeated int64 using packed encoding.
285 //
286 // Precondition: Encoder has no active child encoder.
WriteRepeatedInt64(uint32_t field_number,const pw::Vector<int64_t> & values)287 Status WriteRepeatedInt64(uint32_t field_number,
288 const pw::Vector<int64_t>& values) {
289 return WritePackedVarints(
290 field_number,
291 span(reinterpret_cast<const uint64_t*>(values.data()), values.size()),
292 internal::VarintType::kNormal);
293 }
294
295 // Writes a proto sint32 key-value pair.
296 //
297 // Precondition: Encoder has no active child encoder.
WriteSint32(uint32_t field_number,int32_t value)298 Status WriteSint32(uint32_t field_number, int32_t value) {
299 return WriteUint64(field_number, varint::ZigZagEncode(value));
300 }
301
302 // Writes a repeated sint32 using packed encoding.
303 //
304 // Precondition: Encoder has no active child encoder.
WritePackedSint32(uint32_t field_number,span<const int32_t> values)305 Status WritePackedSint32(uint32_t field_number, span<const int32_t> values) {
306 return WritePackedVarints(
307 field_number,
308 span(reinterpret_cast<const uint32_t*>(values.data()), values.size()),
309 internal::VarintType::kZigZag);
310 }
311
312 // Writes a repeated sint32 using packed encoding.
313 //
314 // Precondition: Encoder has no active child encoder.
WriteRepeatedSint32(uint32_t field_number,const pw::Vector<int32_t> & values)315 Status WriteRepeatedSint32(uint32_t field_number,
316 const pw::Vector<int32_t>& values) {
317 return WritePackedVarints(
318 field_number,
319 span(reinterpret_cast<const uint32_t*>(values.data()), values.size()),
320 internal::VarintType::kZigZag);
321 }
322
323 // Writes a proto sint64 key-value pair.
324 //
325 // Precondition: Encoder has no active child encoder.
WriteSint64(uint32_t field_number,int64_t value)326 Status WriteSint64(uint32_t field_number, int64_t value) {
327 return WriteUint64(field_number, varint::ZigZagEncode(value));
328 }
329
330 // Writes a repeated sint64 using packed encoding.
331 //
332 // Precondition: Encoder has no active child encoder.
WritePackedSint64(uint32_t field_number,span<const int64_t> values)333 Status WritePackedSint64(uint32_t field_number, span<const int64_t> values) {
334 return WritePackedVarints(
335 field_number,
336 span(reinterpret_cast<const uint64_t*>(values.data()), values.size()),
337 internal::VarintType::kZigZag);
338 }
339
340 // Writes a repeated sint64 using packed encoding.
341 //
342 // Precondition: Encoder has no active child encoder.
WriteRepeatedSint64(uint32_t field_number,const pw::Vector<int64_t> & values)343 Status WriteRepeatedSint64(uint32_t field_number,
344 const pw::Vector<int64_t>& values) {
345 return WritePackedVarints(
346 field_number,
347 span(reinterpret_cast<const uint64_t*>(values.data()), values.size()),
348 internal::VarintType::kZigZag);
349 }
350
351 // Writes a proto bool key-value pair.
352 //
353 // Precondition: Encoder has no active child encoder.
WriteBool(uint32_t field_number,bool value)354 Status WriteBool(uint32_t field_number, bool value) {
355 return WriteUint32(field_number, static_cast<uint32_t>(value));
356 }
357
358 // Writes a repeated bool using packed encoding.
359 //
360 // Precondition: Encoder has no active child encoder.
WritePackedBool(uint32_t field_number,span<const bool> values)361 Status WritePackedBool(uint32_t field_number, span<const bool> values) {
362 static_assert(sizeof(bool) == sizeof(uint8_t),
363 "bool must be same size as uint8_t");
364 return WritePackedVarints(
365 field_number,
366 span(reinterpret_cast<const uint8_t*>(values.data()), values.size()),
367 internal::VarintType::kNormal);
368 }
369
370 // Writes a repeated bool using packed encoding.
371 //
372 // Precondition: Encoder has no active child encoder.
WriteRepeatedBool(uint32_t field_number,const pw::Vector<bool> & values)373 Status WriteRepeatedBool(uint32_t field_number,
374 const pw::Vector<bool>& values) {
375 static_assert(sizeof(bool) == sizeof(uint8_t),
376 "bool must be same size as uint8_t");
377
378 return WritePackedVarints(
379 field_number,
380 span(reinterpret_cast<const uint8_t*>(values.data()), values.size()),
381 internal::VarintType::kNormal);
382 }
383
384 // Writes a proto fixed32 key-value pair.
385 //
386 // Precondition: Encoder has no active child encoder.
WriteFixed32(uint32_t field_number,uint32_t value)387 Status WriteFixed32(uint32_t field_number, uint32_t value) {
388 std::array<std::byte, sizeof(value)> data =
389 bytes::CopyInOrder(endian::little, value);
390 return WriteFixed(field_number, data);
391 }
392
393 // Writes a repeated fixed32 field using packed encoding.
394 //
395 // Precondition: Encoder has no active child encoder.
WritePackedFixed32(uint32_t field_number,span<const uint32_t> values)396 Status WritePackedFixed32(uint32_t field_number,
397 span<const uint32_t> values) {
398 return WritePackedFixed(field_number, as_bytes(values), sizeof(uint32_t));
399 }
400
401 // Writes a repeated fixed32 field using packed encoding.
402 //
403 // Precondition: Encoder has no active child encoder.
WriteRepeatedFixed32(uint32_t field_number,const pw::Vector<uint32_t> & values)404 Status WriteRepeatedFixed32(uint32_t field_number,
405 const pw::Vector<uint32_t>& values) {
406 return WritePackedFixed(field_number,
407 as_bytes(span(values.data(), values.size())),
408 sizeof(uint32_t));
409 }
410
411 // Writes a proto fixed64 key-value pair.
412 //
413 // Precondition: Encoder has no active child encoder.
WriteFixed64(uint32_t field_number,uint64_t value)414 Status WriteFixed64(uint32_t field_number, uint64_t value) {
415 std::array<std::byte, sizeof(value)> data =
416 bytes::CopyInOrder(endian::little, value);
417 return WriteFixed(field_number, data);
418 }
419
420 // Writes a repeated fixed64 field using packed encoding.
421 //
422 // Precondition: Encoder has no active child encoder.
WritePackedFixed64(uint32_t field_number,span<const uint64_t> values)423 Status WritePackedFixed64(uint32_t field_number,
424 span<const uint64_t> values) {
425 return WritePackedFixed(field_number, as_bytes(values), sizeof(uint64_t));
426 }
427
428 // Writes a repeated fixed64 field using packed encoding.
429 //
430 // Precondition: Encoder has no active child encoder.
WriteRepeatedFixed64(uint32_t field_number,const pw::Vector<uint64_t> & values)431 Status WriteRepeatedFixed64(uint32_t field_number,
432 const pw::Vector<uint64_t>& values) {
433 return WritePackedFixed(field_number,
434 as_bytes(span(values.data(), values.size())),
435 sizeof(uint64_t));
436 }
437
438 // Writes a proto sfixed32 key-value pair.
439 //
440 // Precondition: Encoder has no active child encoder.
WriteSfixed32(uint32_t field_number,int32_t value)441 Status WriteSfixed32(uint32_t field_number, int32_t value) {
442 return WriteFixed32(field_number, static_cast<uint32_t>(value));
443 }
444
445 // Writes a repeated sfixed32 field using packed encoding.
446 //
447 // Precondition: Encoder has no active child encoder.
WritePackedSfixed32(uint32_t field_number,span<const int32_t> values)448 Status WritePackedSfixed32(uint32_t field_number,
449 span<const int32_t> values) {
450 return WritePackedFixed(field_number, as_bytes(values), sizeof(int32_t));
451 }
452
453 // Writes a repeated fixed32 field using packed encoding.
454 //
455 // Precondition: Encoder has no active child encoder.
WriteRepeatedSfixed32(uint32_t field_number,const pw::Vector<int32_t> & values)456 Status WriteRepeatedSfixed32(uint32_t field_number,
457 const pw::Vector<int32_t>& values) {
458 return WritePackedFixed(field_number,
459 as_bytes(span(values.data(), values.size())),
460 sizeof(int32_t));
461 }
462
463 // Writes a proto sfixed64 key-value pair.
464 //
465 // Precondition: Encoder has no active child encoder.
WriteSfixed64(uint32_t field_number,int64_t value)466 Status WriteSfixed64(uint32_t field_number, int64_t value) {
467 return WriteFixed64(field_number, static_cast<uint64_t>(value));
468 }
469
470 // Writes a repeated sfixed64 field using packed encoding.
471 //
472 // Precondition: Encoder has no active child encoder.
WritePackedSfixed64(uint32_t field_number,span<const int64_t> values)473 Status WritePackedSfixed64(uint32_t field_number,
474 span<const int64_t> values) {
475 return WritePackedFixed(field_number, as_bytes(values), sizeof(int64_t));
476 }
477
478 // Writes a repeated fixed64 field using packed encoding.
479 //
480 // Precondition: Encoder has no active child encoder.
WriteRepeatedSfixed64(uint32_t field_number,const pw::Vector<int64_t> & values)481 Status WriteRepeatedSfixed64(uint32_t field_number,
482 const pw::Vector<int64_t>& values) {
483 return WritePackedFixed(field_number,
484 as_bytes(span(values.data(), values.size())),
485 sizeof(int64_t));
486 }
487
488 // Writes a proto float key-value pair.
489 //
490 // Precondition: Encoder has no active child encoder.
WriteFloat(uint32_t field_number,float value)491 Status WriteFloat(uint32_t field_number, float value) {
492 static_assert(sizeof(float) == sizeof(uint32_t),
493 "Float and uint32_t are not the same size");
494 uint32_t integral_value;
495 std::memcpy(&integral_value, &value, sizeof(value));
496 std::array<std::byte, sizeof(value)> data =
497 bytes::CopyInOrder(endian::little, integral_value);
498 return WriteFixed(field_number, data);
499 }
500
501 // Writes a repeated float field using packed encoding.
502 //
503 // Precondition: Encoder has no active child encoder.
WritePackedFloat(uint32_t field_number,span<const float> values)504 Status WritePackedFloat(uint32_t field_number, span<const float> values) {
505 return WritePackedFixed(field_number, as_bytes(values), sizeof(float));
506 }
507
508 // Writes a repeated float field using packed encoding.
509 //
510 // Precondition: Encoder has no active child encoder.
WriteRepeatedFloat(uint32_t field_number,const pw::Vector<float> & values)511 Status WriteRepeatedFloat(uint32_t field_number,
512 const pw::Vector<float>& values) {
513 return WritePackedFixed(field_number,
514 as_bytes(span(values.data(), values.size())),
515 sizeof(float));
516 }
517
518 // Writes a proto double key-value pair.
519 //
520 // Precondition: Encoder has no active child encoder.
WriteDouble(uint32_t field_number,double value)521 Status WriteDouble(uint32_t field_number, double value) {
522 static_assert(sizeof(double) == sizeof(uint64_t),
523 "Double and uint64_t are not the same size");
524 uint64_t integral_value;
525 std::memcpy(&integral_value, &value, sizeof(value));
526 std::array<std::byte, sizeof(value)> data =
527 bytes::CopyInOrder(endian::little, integral_value);
528 return WriteFixed(field_number, data);
529 }
530
531 // Writes a repeated double field using packed encoding.
532 //
533 // Precondition: Encoder has no active child encoder.
WritePackedDouble(uint32_t field_number,span<const double> values)534 Status WritePackedDouble(uint32_t field_number, span<const double> values) {
535 return WritePackedFixed(field_number, as_bytes(values), sizeof(double));
536 }
537
538 // Writes a repeated double field using packed encoding.
539 //
540 // Precondition: Encoder has no active child encoder.
WriteRepeatedDouble(uint32_t field_number,const pw::Vector<double> & values)541 Status WriteRepeatedDouble(uint32_t field_number,
542 const pw::Vector<double>& values) {
543 return WritePackedFixed(field_number,
544 as_bytes(span(values.data(), values.size())),
545 sizeof(double));
546 }
547
548 // Writes a proto `bytes` field as a key-value pair. This can also be used to
549 // write a pre-encoded nested submessage directly without using a nested
550 // encoder.
551 //
552 // Precondition: Encoder has no active child encoder.
WriteBytes(uint32_t field_number,ConstByteSpan value)553 Status WriteBytes(uint32_t field_number, ConstByteSpan value) {
554 return WriteLengthDelimitedField(field_number, value);
555 }
556
557 // Writes a proto 'bytes' field from the stream bytes_reader.
558 //
559 // The payload for the value is provided through the stream::Reader
560 // `bytes_reader`. The method reads a chunk of the data from the reader using
561 // the `stream_pipe_buffer` and writes it to the encoder.
562 //
563 // Precondition: The stream_pipe_buffer.byte_size() >= 1
564 // Precondition: Encoder has no active child encoder.
565 //
566 // Returns:
567 // OK - Bytes field is written successfully.
568 // RESOURCE_EXHAUSTED - Exceeds write limits.
569 // OUT_OF_RANGE - `bytes_reader` is exhausted before `num_bytes` of
570 // bytes is read.
571 //
572 // Other errors encountered by the writer will be returned as it is.
WriteBytesFromStream(uint32_t field_number,stream::Reader & bytes_reader,size_t num_bytes,ByteSpan stream_pipe_buffer)573 Status WriteBytesFromStream(uint32_t field_number,
574 stream::Reader& bytes_reader,
575 size_t num_bytes,
576 ByteSpan stream_pipe_buffer) {
577 return WriteLengthDelimitedFieldFromStream(
578 field_number, bytes_reader, num_bytes, stream_pipe_buffer);
579 }
580
581 // Writes a proto string key-value pair.
582 //
583 // Precondition: Encoder has no active child encoder.
WriteString(uint32_t field_number,std::string_view value)584 Status WriteString(uint32_t field_number, std::string_view value) {
585 return WriteBytes(field_number, as_bytes(span<const char>(value)));
586 }
587
588 // Writes a proto string key-value pair.
589 //
590 // Precondition: Encoder has no active child encoder.
WriteString(uint32_t field_number,const char * value,size_t len)591 Status WriteString(uint32_t field_number, const char* value, size_t len) {
592 return WriteBytes(field_number, as_bytes(span(value, len)));
593 }
594
595 // Writes a proto 'string' field from the stream bytes_reader.
596 //
597 // The payload for the value is provided through the stream::Reader
598 // `bytes_reader`. The method reads a chunk of the data from the reader using
599 // the `stream_pipe_buffer` and writes it to the encoder.
600 //
601 // Precondition: The stream_pipe_buffer.byte_size() >= 1
602 // Precondition: Encoder has no active child encoder.
603 //
604 // Returns:
605 // OK - String field is written successfully.
606 // RESOURCE_EXHAUSTED - Exceeds write limits.
607 // OUT_OF_RANGE - `bytes_reader` is exhausted before `num_bytes` of
608 // bytes is read.
609 //
610 // Other errors encountered by the writer will be returned as it is.
WriteStringFromStream(uint32_t field_number,stream::Reader & bytes_reader,size_t num_bytes,ByteSpan stream_pipe_buffer)611 Status WriteStringFromStream(uint32_t field_number,
612 stream::Reader& bytes_reader,
613 size_t num_bytes,
614 ByteSpan stream_pipe_buffer) {
615 return WriteBytesFromStream(
616 field_number, bytes_reader, num_bytes, stream_pipe_buffer);
617 }
618
619 protected:
620 // Specialized move constructor used only for codegen.
621 //
622 // Postcondition: The other encoder is invalidated and cannot be used as it
623 // acts like a parent encoder with an active child encoder.
StreamEncoder(StreamEncoder && other)624 constexpr StreamEncoder(StreamEncoder&& other)
625 : status_(other.status_),
626 write_when_empty_(true),
627 parent_(other.parent_),
628 nested_field_number_(other.nested_field_number_),
629 memory_writer_(std::move(other.memory_writer_)),
630 writer_(&other.writer_ == &other.memory_writer_ ? memory_writer_
631 : other.writer_) {
632 PW_ASSERT(nested_field_number_ == 0);
633 // Make the nested encoder look like it has an open child to block writes
634 // for the remainder of the object's life.
635 other.nested_field_number_ = kFirstReservedNumber;
636 other.parent_ = nullptr;
637 }
638
639 // Writes proto values to the stream from the structure contained within
640 // message, according to the description of fields in table.
641 //
642 // This is called by codegen subclass Write() functions that accept a typed
643 // struct Message reference, using the appropriate codegen MessageField table
644 // corresponding to that type.
645 Status Write(span<const std::byte> message,
646 span<const internal::MessageField> table);
647
648 // Protected method to create a nested encoder, specifying whether the field
649 // should be written when no fields were added to the nested encoder. Exposed
650 // using an enum in the public API, for better readability.
651 StreamEncoder GetNestedEncoder(uint32_t field_number, bool write_when_empty);
652
653 private:
654 friend class MemoryEncoder;
655
656 constexpr StreamEncoder(StreamEncoder& parent,
657 ByteSpan scratch_buffer,
658 bool write_when_empty = true)
659 : status_(scratch_buffer.empty() ? Status::ResourceExhausted()
660 : OkStatus()),
661 write_when_empty_(write_when_empty),
662 parent_(&parent),
663 nested_field_number_(0),
664 memory_writer_(scratch_buffer),
665 writer_(memory_writer_) {}
666
nested_encoder_open()667 bool nested_encoder_open() const { return nested_field_number_ != 0; }
668
669 // CloseNestedMessage() is called on the parent encoder as part of the nested
670 // encoder destructor.
671 void CloseNestedMessage(StreamEncoder& nested);
672
673 // Implementation for encoding all varint field types.
674 Status WriteVarintField(uint32_t field_number, uint64_t value);
675
676 // Implementation for encoding all length-delimited field types.
677 Status WriteLengthDelimitedField(uint32_t field_number, ConstByteSpan data);
678
679 // Encoding of length-delimited field where payload comes from `bytes_reader`.
680 Status WriteLengthDelimitedFieldFromStream(uint32_t field_number,
681 stream::Reader& bytes_reader,
682 size_t num_bytes,
683 ByteSpan stream_pipe_buffer);
684
685 // Implementation for encoding all fixed-length integer types.
686 Status WriteFixed(uint32_t field_number, ConstByteSpan data);
687
688 // Encodes a base-128 varint to the buffer. This function assumes the caller
689 // has already checked UpdateStatusForWrite() to ensure the writer's
690 // conservative write limit indicates the Writer has sufficient buffer space.
WriteVarint(uint64_t value)691 Status WriteVarint(uint64_t value) {
692 PW_TRY(status_);
693 status_.Update(::pw::protobuf::WriteVarint(value, writer_));
694 return status_;
695 }
696
WriteZigzagVarint(int64_t value)697 Status WriteZigzagVarint(int64_t value) {
698 return WriteVarint(varint::ZigZagEncode(value));
699 }
700
701 // Writes a list of varints to the buffer in length-delimited packed encoding.
702 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
WritePackedVarints(uint32_t field_number,span<T> values,internal::VarintType encode_type)703 Status WritePackedVarints(uint32_t field_number,
704 span<T> values,
705 internal::VarintType encode_type) {
706 static_assert(std::is_same<T, const uint8_t>::value ||
707 std::is_same<T, const uint32_t>::value ||
708 std::is_same<T, const int32_t>::value ||
709 std::is_same<T, const uint64_t>::value ||
710 std::is_same<T, const int64_t>::value,
711 "Packed varints must be of type bool, uint32_t, int32_t, "
712 "uint64_t, or int64_t");
713
714 size_t payload_size = 0;
715 for (T val : values) {
716 if (encode_type == internal::VarintType::kZigZag) {
717 int64_t integer =
718 static_cast<int64_t>(static_cast<std::make_signed_t<T>>(val));
719 payload_size += varint::EncodedSize(varint::ZigZagEncode(integer));
720 } else {
721 uint64_t integer = static_cast<uint64_t>(val);
722 payload_size += varint::EncodedSize(integer);
723 }
724 }
725
726 if (!UpdateStatusForWrite(field_number, WireType::kDelimited, payload_size)
727 .ok()) {
728 return status_;
729 }
730
731 WriteVarint(FieldKey(field_number, WireType::kDelimited))
732 .IgnoreError(); // TODO(b/242598609): Handle Status properly
733 WriteVarint(payload_size)
734 .IgnoreError(); // TODO(b/242598609): Handle Status properly
735 for (T value : values) {
736 if (encode_type == internal::VarintType::kZigZag) {
737 WriteZigzagVarint(static_cast<std::make_signed_t<T>>(value))
738 .IgnoreError(); // TODO(b/242598609): Handle Status properly
739 } else {
740 WriteVarint(value)
741 .IgnoreError(); // TODO(b/242598609): Handle Status properly
742 }
743 }
744
745 return status_;
746 }
747
748 // Writes a list of fixed-size types to the buffer in length-delimited
749 // packed encoding. Only float, double, uint32_t, int32_t, uint64_t, and
750 // int64_t are permitted
751 Status WritePackedFixed(uint32_t field_number,
752 span<const std::byte> values,
753 size_t elem_size);
754
755 template <typename Container>
WriteStringOrBytes(uint32_t field_number,const std::byte * raw_container)756 Status WriteStringOrBytes(uint32_t field_number,
757 const std::byte* raw_container) {
758 const auto& container = *reinterpret_cast<Container*>(raw_container);
759 if (container.empty()) {
760 return OkStatus();
761 }
762 return WriteLengthDelimitedField(field_number, as_bytes(span(container)));
763 }
764
765 // Checks if a write is invalid or will cause the encoder to enter an error
766 // state, and preemptively sets this encoder's status to that error to block
767 // the write. Only the first error encountered is tracked.
768 //
769 // Precondition: Encoder has no active child encoder.
770 //
771 // Returns:
772 // InvalidArgument: The field number provided was invalid.
773 // ResourceExhausted: The requested write would have exceeded the
774 // stream::Writer's conservative write limit.
775 // Other: If any Write() operations on the stream::Writer caused an error,
776 // that error will be repeated here.
777 Status UpdateStatusForWrite(uint32_t field_number,
778 WireType type,
779 size_t data_size);
780
781 // The current encoder status. This status is only updated to reflect the
782 // first error encountered. Any further write operations are blocked when the
783 // encoder enters an error state.
784 Status status_;
785
786 // Checked by the parent when the nested encoder is closed, and if no bytes
787 // were written, the field is not written.
788 bool write_when_empty_;
789
790 // If this is a nested encoder, this points to the encoder that created it.
791 // For user-created MemoryEncoders, parent_ points to this object as an
792 // optimization for the MemoryEncoder and nested encoders to use the same
793 // underlying buffer.
794 StreamEncoder* parent_;
795
796 // If an encoder has a child encoder open, this is the field number of that
797 // submessage. Otherwise, this is 0 to indicate no child encoder is open.
798 uint32_t nested_field_number_;
799
800 // This memory writer is used for staging proto submessages to the
801 // scratch_buffer.
802 stream::MemoryWriter memory_writer_;
803
804 // All proto encode operations are directly written to this writer.
805 stream::Writer& writer_;
806 };
807
808 // A protobuf encoder that writes directly to a provided buffer.
809 //
810 // Example:
811 //
812 // // Writes a proto response to the provided buffer, returning the encode
813 // // status and number of bytes written.
814 // StatusWithSize WriteProtoResponse(ByteSpan response) {
815 // // All proto writes are directly written to the `response` buffer.
816 // MemoryEncoder encoder(response);
817 // encoder.WriteUint32(kMagicNumberField, 0x1a1a2b2b);
818 // encoder.WriteString(kFavoriteFood, "cookies");
819 // return StatusWithSize(encoder.status(), encoder.size());
820 // }
821 //
822 // Note: Avoid using a MemoryEncoder reference as an argument for a function.
823 // The StreamEncoder is more generic.
824 class MemoryEncoder : public StreamEncoder {
825 public:
MemoryEncoder(ByteSpan dest)826 constexpr MemoryEncoder(ByteSpan dest) : StreamEncoder(*this, dest) {}
827
828 // Precondition: Encoder has no active child encoder.
829 //
830 // Postcondition: If this encoder is a nested one, the parent encoder is
831 // unlocked and proto encoding may resume on the parent.
832 ~MemoryEncoder() = default;
833
834 // Disallow copy/assign to avoid confusion about who owns the buffer.
835 MemoryEncoder(const MemoryEncoder& other) = delete;
836 MemoryEncoder& operator=(const MemoryEncoder& other) = delete;
837
838 // It's not safe to move an encoder as it could cause another encoder's
839 // parent_ pointer to become invalid.
840 MemoryEncoder& operator=(MemoryEncoder&& other) = delete;
841
data()842 const std::byte* data() const { return memory_writer_.data(); }
size()843 size_t size() const { return memory_writer_.bytes_written(); }
844
begin()845 const std::byte* begin() const { return data(); }
end()846 const std::byte* end() const { return data() + size(); }
847
848 protected:
849 // This is needed by codegen.
850 MemoryEncoder(MemoryEncoder&& other) = default;
851 };
852
853 // pw_protobuf guarantees that all generated StreamEncoder classes can be
854 // converted among each other. It's also safe to convert any MemoryEncoder to
855 // any other StreamEncoder.
856 //
857 // This guarantee exists to facilitate usage of protobuf overlays. Protobuf
858 // overlays are protobuf message definitions that deliberately ensure that
859 // fields defined in one message will not conflict with fields defined in other
860 // messages.
861 //
862 // Example:
863 //
864 // // The first half of the overlaid message.
865 // message BaseMessage {
866 // uint32 length = 1;
867 // reserved 2; // Reserved for Overlay
868 // }
869 //
870 // // OK: The second half of the overlaid message.
871 // message Overlay {
872 // reserved 1; // Reserved for BaseMessage
873 // uint32 height = 2;
874 // }
875 //
876 // // OK: A message that overlays and bundles both types together.
877 // message Both {
878 // uint32 length = 1; // Defined independently by BaseMessage
879 // uint32 height = 2; // Defined independently by Overlay
880 // }
881 //
882 // // BAD: Diverges from BaseMessage's definition, and can cause decode
883 // // errors/corruption.
884 // message InvalidOverlay {
885 // fixed32 length = 1;
886 // }
887 //
888 // While this use case is somewhat uncommon, it's a core supported use case of
889 // pw_protobuf.
890 //
891 // Warning: Using this to convert one stream encoder to another when the
892 // messages themselves do not safely overlay will result in corrupt protos.
893 // Be careful when doing this as there's no compile-time way to detect whether
894 // or not two messages are meant to overlay.
895 template <typename ToStreamEncoder, typename FromStreamEncoder>
StreamEncoderCast(FromStreamEncoder & encoder)896 inline ToStreamEncoder& StreamEncoderCast(FromStreamEncoder& encoder) {
897 static_assert(std::is_base_of<StreamEncoder, FromStreamEncoder>::value,
898 "Provided argument is not a derived class of "
899 "pw::protobuf::StreamEncoder");
900 static_assert(std::is_base_of<StreamEncoder, ToStreamEncoder>::value,
901 "Cannot cast to a type that is not a derived class of "
902 "pw::protobuf::StreamEncoder");
903 return static_cast<ToStreamEncoder&>(static_cast<StreamEncoder&>(encoder));
904 }
905
906 } // namespace pw::protobuf
907