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