• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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