xref: /aosp_15_r20/external/pigweed/pw_protobuf/encoder.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <algorithm>
18*61c4878aSAndroid Build Coastguard Worker #include <cstddef>
19*61c4878aSAndroid Build Coastguard Worker #include <cstring>
20*61c4878aSAndroid Build Coastguard Worker #include <optional>
21*61c4878aSAndroid Build Coastguard Worker 
22*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/internal/codegen.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/serialized_size.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/stream_decoder.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/wire_format.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
30*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
31*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/memory_stream.h"
32*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/stream.h"
33*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string.h"
34*61c4878aSAndroid Build Coastguard Worker #include "pw_varint/varint.h"
35*61c4878aSAndroid Build Coastguard Worker 
36*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf {
37*61c4878aSAndroid Build Coastguard Worker 
38*61c4878aSAndroid Build Coastguard Worker using internal::VarintType;
39*61c4878aSAndroid Build Coastguard Worker 
GetNestedEncoder(uint32_t field_number,bool write_when_empty)40*61c4878aSAndroid Build Coastguard Worker StreamEncoder StreamEncoder::GetNestedEncoder(uint32_t field_number,
41*61c4878aSAndroid Build Coastguard Worker                                               bool write_when_empty) {
42*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(!nested_encoder_open());
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker   nested_field_number_ = field_number;
45*61c4878aSAndroid Build Coastguard Worker   if (!ValidFieldNumber(field_number)) {
46*61c4878aSAndroid Build Coastguard Worker     status_.Update(Status::InvalidArgument());
47*61c4878aSAndroid Build Coastguard Worker     return StreamEncoder(*this, ByteSpan(), false);
48*61c4878aSAndroid Build Coastguard Worker   }
49*61c4878aSAndroid Build Coastguard Worker 
50*61c4878aSAndroid Build Coastguard Worker   // Pass the unused space of the scratch buffer to the nested encoder to use
51*61c4878aSAndroid Build Coastguard Worker   // as their scratch buffer.
52*61c4878aSAndroid Build Coastguard Worker   size_t key_size =
53*61c4878aSAndroid Build Coastguard Worker       varint::EncodedSize(FieldKey(field_number, WireType::kDelimited));
54*61c4878aSAndroid Build Coastguard Worker   size_t reserved_size = key_size + config::kMaxVarintSize;
55*61c4878aSAndroid Build Coastguard Worker   size_t max_size = std::min(memory_writer_.ConservativeWriteLimit(),
56*61c4878aSAndroid Build Coastguard Worker                              writer_.ConservativeWriteLimit());
57*61c4878aSAndroid Build Coastguard Worker   // Account for reserved bytes.
58*61c4878aSAndroid Build Coastguard Worker   max_size = max_size > reserved_size ? max_size - reserved_size : 0;
59*61c4878aSAndroid Build Coastguard Worker   // Cap based on max varint size.
60*61c4878aSAndroid Build Coastguard Worker   max_size = std::min(varint::MaxValueInBytes(config::kMaxVarintSize),
61*61c4878aSAndroid Build Coastguard Worker                       static_cast<uint64_t>(max_size));
62*61c4878aSAndroid Build Coastguard Worker 
63*61c4878aSAndroid Build Coastguard Worker   ByteSpan nested_buffer;
64*61c4878aSAndroid Build Coastguard Worker   if (max_size > 0) {
65*61c4878aSAndroid Build Coastguard Worker     nested_buffer = ByteSpan(
66*61c4878aSAndroid Build Coastguard Worker         memory_writer_.data() + reserved_size + memory_writer_.bytes_written(),
67*61c4878aSAndroid Build Coastguard Worker         max_size);
68*61c4878aSAndroid Build Coastguard Worker   } else {
69*61c4878aSAndroid Build Coastguard Worker     nested_buffer = ByteSpan();
70*61c4878aSAndroid Build Coastguard Worker   }
71*61c4878aSAndroid Build Coastguard Worker   return StreamEncoder(*this, nested_buffer, write_when_empty);
72*61c4878aSAndroid Build Coastguard Worker }
73*61c4878aSAndroid Build Coastguard Worker 
CloseEncoder()74*61c4878aSAndroid Build Coastguard Worker void StreamEncoder::CloseEncoder() {
75*61c4878aSAndroid Build Coastguard Worker   // If this was an invalidated StreamEncoder which cannot be used, permit the
76*61c4878aSAndroid Build Coastguard Worker   // object to be cleanly destructed by doing nothing.
77*61c4878aSAndroid Build Coastguard Worker   if (nested_field_number_ == kFirstReservedNumber) {
78*61c4878aSAndroid Build Coastguard Worker     return;
79*61c4878aSAndroid Build Coastguard Worker   }
80*61c4878aSAndroid Build Coastguard Worker 
81*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(
82*61c4878aSAndroid Build Coastguard Worker       !nested_encoder_open(),
83*61c4878aSAndroid Build Coastguard Worker       "Tried to destruct a proto encoder with an active submessage encoder");
84*61c4878aSAndroid Build Coastguard Worker 
85*61c4878aSAndroid Build Coastguard Worker   if (parent_ != nullptr) {
86*61c4878aSAndroid Build Coastguard Worker     parent_->CloseNestedMessage(*this);
87*61c4878aSAndroid Build Coastguard Worker   }
88*61c4878aSAndroid Build Coastguard Worker }
89*61c4878aSAndroid Build Coastguard Worker 
CloseNestedMessage(StreamEncoder & nested)90*61c4878aSAndroid Build Coastguard Worker void StreamEncoder::CloseNestedMessage(StreamEncoder& nested) {
91*61c4878aSAndroid Build Coastguard Worker   PW_DCHECK_PTR_EQ(nested.parent_,
92*61c4878aSAndroid Build Coastguard Worker                    this,
93*61c4878aSAndroid Build Coastguard Worker                    "CloseNestedMessage() called on the wrong Encoder parent");
94*61c4878aSAndroid Build Coastguard Worker 
95*61c4878aSAndroid Build Coastguard Worker   // Make the nested encoder look like it has an open child to block writes for
96*61c4878aSAndroid Build Coastguard Worker   // the remainder of the object's life.
97*61c4878aSAndroid Build Coastguard Worker   nested.nested_field_number_ = kFirstReservedNumber;
98*61c4878aSAndroid Build Coastguard Worker   nested.parent_ = nullptr;
99*61c4878aSAndroid Build Coastguard Worker   // Temporarily cache the field number of the child so we can re-enable
100*61c4878aSAndroid Build Coastguard Worker   // writing to this encoder.
101*61c4878aSAndroid Build Coastguard Worker   uint32_t temp_field_number = nested_field_number_;
102*61c4878aSAndroid Build Coastguard Worker   nested_field_number_ = 0;
103*61c4878aSAndroid Build Coastguard Worker 
104*61c4878aSAndroid Build Coastguard Worker   // TODO(amontanez): If a submessage fails, we could optionally discard
105*61c4878aSAndroid Build Coastguard Worker   // it and continue happily. For now, we'll always invalidate the entire
106*61c4878aSAndroid Build Coastguard Worker   // encoder if a single submessage fails.
107*61c4878aSAndroid Build Coastguard Worker   status_.Update(nested.status_);
108*61c4878aSAndroid Build Coastguard Worker   if (!status_.ok()) {
109*61c4878aSAndroid Build Coastguard Worker     return;
110*61c4878aSAndroid Build Coastguard Worker   }
111*61c4878aSAndroid Build Coastguard Worker 
112*61c4878aSAndroid Build Coastguard Worker   if (varint::EncodedSize(nested.memory_writer_.bytes_written()) >
113*61c4878aSAndroid Build Coastguard Worker       config::kMaxVarintSize) {
114*61c4878aSAndroid Build Coastguard Worker     status_ = Status::OutOfRange();
115*61c4878aSAndroid Build Coastguard Worker     return;
116*61c4878aSAndroid Build Coastguard Worker   }
117*61c4878aSAndroid Build Coastguard Worker 
118*61c4878aSAndroid Build Coastguard Worker   if (!nested.memory_writer_.bytes_written() && !nested.write_when_empty_) {
119*61c4878aSAndroid Build Coastguard Worker     return;
120*61c4878aSAndroid Build Coastguard Worker   }
121*61c4878aSAndroid Build Coastguard Worker 
122*61c4878aSAndroid Build Coastguard Worker   status_ = WriteLengthDelimitedField(temp_field_number,
123*61c4878aSAndroid Build Coastguard Worker                                       nested.memory_writer_.WrittenData());
124*61c4878aSAndroid Build Coastguard Worker }
125*61c4878aSAndroid Build Coastguard Worker 
WriteVarintField(uint32_t field_number,uint64_t value)126*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::WriteVarintField(uint32_t field_number, uint64_t value) {
127*61c4878aSAndroid Build Coastguard Worker   PW_TRY(UpdateStatusForWrite(
128*61c4878aSAndroid Build Coastguard Worker       field_number, WireType::kVarint, varint::EncodedSize(value)));
129*61c4878aSAndroid Build Coastguard Worker 
130*61c4878aSAndroid Build Coastguard Worker   WriteVarint(FieldKey(field_number, WireType::kVarint))
131*61c4878aSAndroid Build Coastguard Worker       .IgnoreError();  // TODO: b/242598609 - Handle Status properly
132*61c4878aSAndroid Build Coastguard Worker   return WriteVarint(value);
133*61c4878aSAndroid Build Coastguard Worker }
134*61c4878aSAndroid Build Coastguard Worker 
WriteLengthDelimitedField(uint32_t field_number,ConstByteSpan data)135*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::WriteLengthDelimitedField(uint32_t field_number,
136*61c4878aSAndroid Build Coastguard Worker                                                 ConstByteSpan data) {
137*61c4878aSAndroid Build Coastguard Worker   PW_TRY(UpdateStatusForWrite(field_number, WireType::kDelimited, data.size()));
138*61c4878aSAndroid Build Coastguard Worker   status_.Update(WriteLengthDelimitedKeyAndLengthPrefix(
139*61c4878aSAndroid Build Coastguard Worker       field_number, data.size(), writer_));
140*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
141*61c4878aSAndroid Build Coastguard Worker   if (Status status = writer_.Write(data); !status.ok()) {
142*61c4878aSAndroid Build Coastguard Worker     status_ = status;
143*61c4878aSAndroid Build Coastguard Worker   }
144*61c4878aSAndroid Build Coastguard Worker   return status_;
145*61c4878aSAndroid Build Coastguard Worker }
146*61c4878aSAndroid Build Coastguard Worker 
WriteLengthDelimitedFieldFromStream(uint32_t field_number,stream::Reader & bytes_reader,size_t num_bytes,ByteSpan stream_pipe_buffer)147*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::WriteLengthDelimitedFieldFromStream(
148*61c4878aSAndroid Build Coastguard Worker     uint32_t field_number,
149*61c4878aSAndroid Build Coastguard Worker     stream::Reader& bytes_reader,
150*61c4878aSAndroid Build Coastguard Worker     size_t num_bytes,
151*61c4878aSAndroid Build Coastguard Worker     ByteSpan stream_pipe_buffer) {
152*61c4878aSAndroid Build Coastguard Worker   PW_CHECK_UINT_GT(
153*61c4878aSAndroid Build Coastguard Worker       stream_pipe_buffer.size(), 0, "Transfer buffer cannot be 0 size");
154*61c4878aSAndroid Build Coastguard Worker   PW_TRY(UpdateStatusForWrite(field_number, WireType::kDelimited, num_bytes));
155*61c4878aSAndroid Build Coastguard Worker   status_.Update(
156*61c4878aSAndroid Build Coastguard Worker       WriteLengthDelimitedKeyAndLengthPrefix(field_number, num_bytes, writer_));
157*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
158*61c4878aSAndroid Build Coastguard Worker 
159*61c4878aSAndroid Build Coastguard Worker   // Stream data from `bytes_reader` to `writer_`.
160*61c4878aSAndroid Build Coastguard Worker   // TODO(pwbug/468): move the following logic to pw_stream/copy.h at a later
161*61c4878aSAndroid Build Coastguard Worker   // time.
162*61c4878aSAndroid Build Coastguard Worker   for (size_t bytes_written = 0; bytes_written < num_bytes;) {
163*61c4878aSAndroid Build Coastguard Worker     const size_t chunk_size_bytes =
164*61c4878aSAndroid Build Coastguard Worker         std::min(num_bytes - bytes_written, stream_pipe_buffer.size_bytes());
165*61c4878aSAndroid Build Coastguard Worker     const Result<ByteSpan> read_result =
166*61c4878aSAndroid Build Coastguard Worker         bytes_reader.Read(stream_pipe_buffer.data(), chunk_size_bytes);
167*61c4878aSAndroid Build Coastguard Worker     status_.Update(read_result.status());
168*61c4878aSAndroid Build Coastguard Worker     PW_TRY(status_);
169*61c4878aSAndroid Build Coastguard Worker 
170*61c4878aSAndroid Build Coastguard Worker     status_.Update(writer_.Write(read_result.value()));
171*61c4878aSAndroid Build Coastguard Worker     PW_TRY(status_);
172*61c4878aSAndroid Build Coastguard Worker 
173*61c4878aSAndroid Build Coastguard Worker     bytes_written += read_result.value().size();
174*61c4878aSAndroid Build Coastguard Worker   }
175*61c4878aSAndroid Build Coastguard Worker 
176*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
177*61c4878aSAndroid Build Coastguard Worker }
178*61c4878aSAndroid Build Coastguard Worker 
WriteFixed(uint32_t field_number,ConstByteSpan data)179*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::WriteFixed(uint32_t field_number, ConstByteSpan data) {
180*61c4878aSAndroid Build Coastguard Worker   WireType type =
181*61c4878aSAndroid Build Coastguard Worker       data.size() == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
182*61c4878aSAndroid Build Coastguard Worker 
183*61c4878aSAndroid Build Coastguard Worker   PW_TRY(UpdateStatusForWrite(field_number, type, data.size()));
184*61c4878aSAndroid Build Coastguard Worker 
185*61c4878aSAndroid Build Coastguard Worker   WriteVarint(FieldKey(field_number, type))
186*61c4878aSAndroid Build Coastguard Worker       .IgnoreError();  // TODO: b/242598609 - Handle Status properly
187*61c4878aSAndroid Build Coastguard Worker   if (Status status = writer_.Write(data); !status.ok()) {
188*61c4878aSAndroid Build Coastguard Worker     status_ = status;
189*61c4878aSAndroid Build Coastguard Worker   }
190*61c4878aSAndroid Build Coastguard Worker   return status_;
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker 
WritePackedFixed(uint32_t field_number,span<const std::byte> values,size_t elem_size)193*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::WritePackedFixed(uint32_t field_number,
194*61c4878aSAndroid Build Coastguard Worker                                        span<const std::byte> values,
195*61c4878aSAndroid Build Coastguard Worker                                        size_t elem_size) {
196*61c4878aSAndroid Build Coastguard Worker   if (values.empty()) {
197*61c4878aSAndroid Build Coastguard Worker     return status_;
198*61c4878aSAndroid Build Coastguard Worker   }
199*61c4878aSAndroid Build Coastguard Worker 
200*61c4878aSAndroid Build Coastguard Worker   PW_CHECK_NOTNULL(values.data());
201*61c4878aSAndroid Build Coastguard Worker   PW_DCHECK(elem_size == sizeof(uint32_t) || elem_size == sizeof(uint64_t));
202*61c4878aSAndroid Build Coastguard Worker 
203*61c4878aSAndroid Build Coastguard Worker   PW_TRY(UpdateStatusForWrite(
204*61c4878aSAndroid Build Coastguard Worker       field_number, WireType::kDelimited, values.size_bytes()));
205*61c4878aSAndroid Build Coastguard Worker   WriteVarint(FieldKey(field_number, WireType::kDelimited))
206*61c4878aSAndroid Build Coastguard Worker       .IgnoreError();  // TODO: b/242598609 - Handle Status properly
207*61c4878aSAndroid Build Coastguard Worker   WriteVarint(values.size_bytes())
208*61c4878aSAndroid Build Coastguard Worker       .IgnoreError();  // TODO: b/242598609 - Handle Status properly
209*61c4878aSAndroid Build Coastguard Worker 
210*61c4878aSAndroid Build Coastguard Worker   for (auto val_start = values.begin(); val_start != values.end();
211*61c4878aSAndroid Build Coastguard Worker        val_start += elem_size) {
212*61c4878aSAndroid Build Coastguard Worker     // Allocates 8 bytes so both 4-byte and 8-byte types can be encoded as
213*61c4878aSAndroid Build Coastguard Worker     // little-endian for serialization.
214*61c4878aSAndroid Build Coastguard Worker     std::array<std::byte, sizeof(uint64_t)> data;
215*61c4878aSAndroid Build Coastguard Worker     if (endian::native == endian::little) {
216*61c4878aSAndroid Build Coastguard Worker       std::copy(val_start, val_start + elem_size, std::begin(data));
217*61c4878aSAndroid Build Coastguard Worker     } else {
218*61c4878aSAndroid Build Coastguard Worker       std::reverse_copy(val_start, val_start + elem_size, std::begin(data));
219*61c4878aSAndroid Build Coastguard Worker     }
220*61c4878aSAndroid Build Coastguard Worker     status_.Update(writer_.Write(span(data).first(elem_size)));
221*61c4878aSAndroid Build Coastguard Worker     PW_TRY(status_);
222*61c4878aSAndroid Build Coastguard Worker   }
223*61c4878aSAndroid Build Coastguard Worker   return status_;
224*61c4878aSAndroid Build Coastguard Worker }
225*61c4878aSAndroid Build Coastguard Worker 
UpdateStatusForWrite(uint32_t field_number,WireType type,size_t data_size)226*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::UpdateStatusForWrite(uint32_t field_number,
227*61c4878aSAndroid Build Coastguard Worker                                            WireType type,
228*61c4878aSAndroid Build Coastguard Worker                                            size_t data_size) {
229*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(!nested_encoder_open());
230*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
231*61c4878aSAndroid Build Coastguard Worker 
232*61c4878aSAndroid Build Coastguard Worker   if (!ValidFieldNumber(field_number)) {
233*61c4878aSAndroid Build Coastguard Worker     return status_ = Status::InvalidArgument();
234*61c4878aSAndroid Build Coastguard Worker   }
235*61c4878aSAndroid Build Coastguard Worker 
236*61c4878aSAndroid Build Coastguard Worker   const Result<size_t> field_size = SizeOfField(field_number, type, data_size);
237*61c4878aSAndroid Build Coastguard Worker   status_.Update(field_size.status());
238*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
239*61c4878aSAndroid Build Coastguard Worker 
240*61c4878aSAndroid Build Coastguard Worker   if (field_size.value() > writer_.ConservativeWriteLimit()) {
241*61c4878aSAndroid Build Coastguard Worker     status_ = Status::ResourceExhausted();
242*61c4878aSAndroid Build Coastguard Worker   }
243*61c4878aSAndroid Build Coastguard Worker 
244*61c4878aSAndroid Build Coastguard Worker   return status_;
245*61c4878aSAndroid Build Coastguard Worker }
246*61c4878aSAndroid Build Coastguard Worker 
Write(span<const std::byte> message,span<const internal::MessageField> table)247*61c4878aSAndroid Build Coastguard Worker Status StreamEncoder::Write(span<const std::byte> message,
248*61c4878aSAndroid Build Coastguard Worker                             span<const internal::MessageField> table) {
249*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(!nested_encoder_open());
250*61c4878aSAndroid Build Coastguard Worker   PW_TRY(status_);
251*61c4878aSAndroid Build Coastguard Worker 
252*61c4878aSAndroid Build Coastguard Worker   for (const auto& field : table) {
253*61c4878aSAndroid Build Coastguard Worker     // Calculate the span of bytes corresponding to the structure field to
254*61c4878aSAndroid Build Coastguard Worker     // read from.
255*61c4878aSAndroid Build Coastguard Worker     ConstByteSpan values =
256*61c4878aSAndroid Build Coastguard Worker         message.subspan(field.field_offset(), field.field_size());
257*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(values.begin() >= message.begin() &&
258*61c4878aSAndroid Build Coastguard Worker              values.end() <= message.end());
259*61c4878aSAndroid Build Coastguard Worker 
260*61c4878aSAndroid Build Coastguard Worker     // If the field is using callbacks, interpret the input field accordingly
261*61c4878aSAndroid Build Coastguard Worker     // and allow the caller to provide custom handling.
262*61c4878aSAndroid Build Coastguard Worker     if (field.callback_type() == internal::CallbackType::kSingleField) {
263*61c4878aSAndroid Build Coastguard Worker       const Callback<StreamEncoder, StreamDecoder>* callback =
264*61c4878aSAndroid Build Coastguard Worker           reinterpret_cast<const Callback<StreamEncoder, StreamDecoder>*>(
265*61c4878aSAndroid Build Coastguard Worker               values.data());
266*61c4878aSAndroid Build Coastguard Worker       PW_TRY(callback->Encode(*this));
267*61c4878aSAndroid Build Coastguard Worker       continue;
268*61c4878aSAndroid Build Coastguard Worker     } else if (field.callback_type() == internal::CallbackType::kOneOfGroup) {
269*61c4878aSAndroid Build Coastguard Worker       const OneOf<StreamEncoder, StreamDecoder>* callback =
270*61c4878aSAndroid Build Coastguard Worker           reinterpret_cast<const OneOf<StreamEncoder, StreamDecoder>*>(
271*61c4878aSAndroid Build Coastguard Worker               values.data());
272*61c4878aSAndroid Build Coastguard Worker       PW_TRY(callback->Encode(*this));
273*61c4878aSAndroid Build Coastguard Worker       continue;
274*61c4878aSAndroid Build Coastguard Worker     }
275*61c4878aSAndroid Build Coastguard Worker 
276*61c4878aSAndroid Build Coastguard Worker     switch (field.wire_type()) {
277*61c4878aSAndroid Build Coastguard Worker       case WireType::kFixed64:
278*61c4878aSAndroid Build Coastguard Worker       case WireType::kFixed32: {
279*61c4878aSAndroid Build Coastguard Worker         // Fixed fields call WriteFixed() for singular case and
280*61c4878aSAndroid Build Coastguard Worker         // WritePackedFixed() for repeated fields.
281*61c4878aSAndroid Build Coastguard Worker         PW_CHECK(field.elem_size() == (field.wire_type() == WireType::kFixed32
282*61c4878aSAndroid Build Coastguard Worker                                            ? sizeof(uint32_t)
283*61c4878aSAndroid Build Coastguard Worker                                            : sizeof(uint64_t)),
284*61c4878aSAndroid Build Coastguard Worker                  "Mismatched message field type and size");
285*61c4878aSAndroid Build Coastguard Worker         if (field.is_fixed_size()) {
286*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field.is_repeated(), "Non-repeated fixed size field");
287*61c4878aSAndroid Build Coastguard Worker           if (static_cast<size_t>(
288*61c4878aSAndroid Build Coastguard Worker                   std::count(values.begin(), values.end(), std::byte{0})) <
289*61c4878aSAndroid Build Coastguard Worker               values.size()) {
290*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WritePackedFixed(
291*61c4878aSAndroid Build Coastguard Worker                 field.field_number(), values, field.elem_size()));
292*61c4878aSAndroid Build Coastguard Worker           }
293*61c4878aSAndroid Build Coastguard Worker         } else if (field.is_repeated()) {
294*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a vector of a type
295*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
296*61c4878aSAndroid Build Coastguard Worker           // vector type so we're not performing type aliasing (except for
297*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed).
298*61c4878aSAndroid Build Coastguard Worker           if (field.elem_size() == sizeof(uint64_t)) {
299*61c4878aSAndroid Build Coastguard Worker             const auto* vector =
300*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const pw::Vector<const uint64_t>*>(
301*61c4878aSAndroid Build Coastguard Worker                     values.data());
302*61c4878aSAndroid Build Coastguard Worker             if (!vector->empty()) {
303*61c4878aSAndroid Build Coastguard Worker               PW_TRY(WritePackedFixed(
304*61c4878aSAndroid Build Coastguard Worker                   field.field_number(),
305*61c4878aSAndroid Build Coastguard Worker                   as_bytes(span(vector->data(), vector->size())),
306*61c4878aSAndroid Build Coastguard Worker                   field.elem_size()));
307*61c4878aSAndroid Build Coastguard Worker             }
308*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(uint32_t)) {
309*61c4878aSAndroid Build Coastguard Worker             const auto* vector =
310*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const pw::Vector<const uint32_t>*>(
311*61c4878aSAndroid Build Coastguard Worker                     values.data());
312*61c4878aSAndroid Build Coastguard Worker             if (!vector->empty()) {
313*61c4878aSAndroid Build Coastguard Worker               PW_TRY(WritePackedFixed(
314*61c4878aSAndroid Build Coastguard Worker                   field.field_number(),
315*61c4878aSAndroid Build Coastguard Worker                   as_bytes(span(vector->data(), vector->size())),
316*61c4878aSAndroid Build Coastguard Worker                   field.elem_size()));
317*61c4878aSAndroid Build Coastguard Worker             }
318*61c4878aSAndroid Build Coastguard Worker           }
319*61c4878aSAndroid Build Coastguard Worker         } else if (field.is_optional()) {
320*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a std::optional of a type
321*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
322*61c4878aSAndroid Build Coastguard Worker           // optional type so we're not performing type aliasing (except for
323*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed), and write from
324*61c4878aSAndroid Build Coastguard Worker           // a temporary.
325*61c4878aSAndroid Build Coastguard Worker           if (field.elem_size() == sizeof(uint64_t)) {
326*61c4878aSAndroid Build Coastguard Worker             const auto* optional =
327*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const std::optional<uint64_t>*>(values.data());
328*61c4878aSAndroid Build Coastguard Worker             if (optional->has_value()) {
329*61c4878aSAndroid Build Coastguard Worker               uint64_t value = optional->value();
330*61c4878aSAndroid Build Coastguard Worker               PW_TRY(
331*61c4878aSAndroid Build Coastguard Worker                   WriteFixed(field.field_number(), as_bytes(span(&value, 1))));
332*61c4878aSAndroid Build Coastguard Worker             }
333*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(uint32_t)) {
334*61c4878aSAndroid Build Coastguard Worker             const auto* optional =
335*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const std::optional<uint32_t>*>(values.data());
336*61c4878aSAndroid Build Coastguard Worker             if (optional->has_value()) {
337*61c4878aSAndroid Build Coastguard Worker               uint32_t value = optional->value();
338*61c4878aSAndroid Build Coastguard Worker               PW_TRY(
339*61c4878aSAndroid Build Coastguard Worker                   WriteFixed(field.field_number(), as_bytes(span(&value, 1))));
340*61c4878aSAndroid Build Coastguard Worker             }
341*61c4878aSAndroid Build Coastguard Worker           }
342*61c4878aSAndroid Build Coastguard Worker         } else {
343*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(values.size() == field.elem_size(),
344*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
345*61c4878aSAndroid Build Coastguard Worker           if (static_cast<size_t>(
346*61c4878aSAndroid Build Coastguard Worker                   std::count(values.begin(), values.end(), std::byte{0})) <
347*61c4878aSAndroid Build Coastguard Worker               values.size()) {
348*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WriteFixed(field.field_number(), values));
349*61c4878aSAndroid Build Coastguard Worker           }
350*61c4878aSAndroid Build Coastguard Worker         }
351*61c4878aSAndroid Build Coastguard Worker         break;
352*61c4878aSAndroid Build Coastguard Worker       }
353*61c4878aSAndroid Build Coastguard Worker       case WireType::kVarint: {
354*61c4878aSAndroid Build Coastguard Worker         // Varint fields call WriteVarintField() for singular case and
355*61c4878aSAndroid Build Coastguard Worker         // WritePackedVarints() for repeated fields.
356*61c4878aSAndroid Build Coastguard Worker         PW_CHECK(field.elem_size() == sizeof(uint64_t) ||
357*61c4878aSAndroid Build Coastguard Worker                      field.elem_size() == sizeof(uint32_t) ||
358*61c4878aSAndroid Build Coastguard Worker                      field.elem_size() == sizeof(bool),
359*61c4878aSAndroid Build Coastguard Worker                  "Mismatched message field type and size");
360*61c4878aSAndroid Build Coastguard Worker         if (field.is_fixed_size()) {
361*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is an array of type corresponding
362*61c4878aSAndroid Build Coastguard Worker           // to the field element size. Cast to a span of the correct type over
363*61c4878aSAndroid Build Coastguard Worker           // the array so we're not performing type aliasing (except for
364*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed).
365*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field.is_repeated(), "Non-repeated fixed size field");
366*61c4878aSAndroid Build Coastguard Worker           if (static_cast<size_t>(
367*61c4878aSAndroid Build Coastguard Worker                   std::count(values.begin(), values.end(), std::byte{0})) ==
368*61c4878aSAndroid Build Coastguard Worker               values.size()) {
369*61c4878aSAndroid Build Coastguard Worker             continue;
370*61c4878aSAndroid Build Coastguard Worker           }
371*61c4878aSAndroid Build Coastguard Worker           if (field.elem_size() == sizeof(uint64_t)) {
372*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WritePackedVarints(
373*61c4878aSAndroid Build Coastguard Worker                 field.field_number(),
374*61c4878aSAndroid Build Coastguard Worker                 span(reinterpret_cast<const uint64_t*>(values.data()),
375*61c4878aSAndroid Build Coastguard Worker                      values.size() / field.elem_size()),
376*61c4878aSAndroid Build Coastguard Worker                 field.varint_type()));
377*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(uint32_t)) {
378*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WritePackedVarints(
379*61c4878aSAndroid Build Coastguard Worker                 field.field_number(),
380*61c4878aSAndroid Build Coastguard Worker                 span(reinterpret_cast<const uint32_t*>(values.data()),
381*61c4878aSAndroid Build Coastguard Worker                      values.size() / field.elem_size()),
382*61c4878aSAndroid Build Coastguard Worker                 field.varint_type()));
383*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(bool)) {
384*61c4878aSAndroid Build Coastguard Worker             static_assert(sizeof(bool) == sizeof(uint8_t),
385*61c4878aSAndroid Build Coastguard Worker                           "bool must be same size as uint8_t");
386*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WritePackedVarints(
387*61c4878aSAndroid Build Coastguard Worker                 field.field_number(),
388*61c4878aSAndroid Build Coastguard Worker                 span(reinterpret_cast<const uint8_t*>(values.data()),
389*61c4878aSAndroid Build Coastguard Worker                      values.size() / field.elem_size()),
390*61c4878aSAndroid Build Coastguard Worker                 field.varint_type()));
391*61c4878aSAndroid Build Coastguard Worker           }
392*61c4878aSAndroid Build Coastguard Worker         } else if (field.is_repeated()) {
393*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a vector of a type
394*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
395*61c4878aSAndroid Build Coastguard Worker           // vector type so we're not performing type aliasing (except for
396*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed).
397*61c4878aSAndroid Build Coastguard Worker           if (field.elem_size() == sizeof(uint64_t)) {
398*61c4878aSAndroid Build Coastguard Worker             const auto* vector =
399*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const pw::Vector<const uint64_t>*>(
400*61c4878aSAndroid Build Coastguard Worker                     values.data());
401*61c4878aSAndroid Build Coastguard Worker             if (!vector->empty()) {
402*61c4878aSAndroid Build Coastguard Worker               PW_TRY(WritePackedVarints(field.field_number(),
403*61c4878aSAndroid Build Coastguard Worker                                         span(vector->data(), vector->size()),
404*61c4878aSAndroid Build Coastguard Worker                                         field.varint_type()));
405*61c4878aSAndroid Build Coastguard Worker             }
406*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(uint32_t)) {
407*61c4878aSAndroid Build Coastguard Worker             const auto* vector =
408*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const pw::Vector<const uint32_t>*>(
409*61c4878aSAndroid Build Coastguard Worker                     values.data());
410*61c4878aSAndroid Build Coastguard Worker             if (!vector->empty()) {
411*61c4878aSAndroid Build Coastguard Worker               PW_TRY(WritePackedVarints(field.field_number(),
412*61c4878aSAndroid Build Coastguard Worker                                         span(vector->data(), vector->size()),
413*61c4878aSAndroid Build Coastguard Worker                                         field.varint_type()));
414*61c4878aSAndroid Build Coastguard Worker             }
415*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(bool)) {
416*61c4878aSAndroid Build Coastguard Worker             static_assert(sizeof(bool) == sizeof(uint8_t),
417*61c4878aSAndroid Build Coastguard Worker                           "bool must be same size as uint8_t");
418*61c4878aSAndroid Build Coastguard Worker             const auto* vector =
419*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const pw::Vector<const uint8_t>*>(
420*61c4878aSAndroid Build Coastguard Worker                     values.data());
421*61c4878aSAndroid Build Coastguard Worker             if (!vector->empty()) {
422*61c4878aSAndroid Build Coastguard Worker               PW_TRY(WritePackedVarints(field.field_number(),
423*61c4878aSAndroid Build Coastguard Worker                                         span(vector->data(), vector->size()),
424*61c4878aSAndroid Build Coastguard Worker                                         field.varint_type()));
425*61c4878aSAndroid Build Coastguard Worker             }
426*61c4878aSAndroid Build Coastguard Worker           }
427*61c4878aSAndroid Build Coastguard Worker         } else if (field.is_optional()) {
428*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a std::optional of a type
429*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
430*61c4878aSAndroid Build Coastguard Worker           // optional type so we're not performing type aliasing (except for
431*61c4878aSAndroid Build Coastguard Worker           // unsigned vs signed which is explicitly allowed), and write from
432*61c4878aSAndroid Build Coastguard Worker           // a temporary.
433*61c4878aSAndroid Build Coastguard Worker           uint64_t value = 0;
434*61c4878aSAndroid Build Coastguard Worker           if (field.elem_size() == sizeof(uint64_t)) {
435*61c4878aSAndroid Build Coastguard Worker             if (field.varint_type() == VarintType::kUnsigned) {
436*61c4878aSAndroid Build Coastguard Worker               const auto* optional =
437*61c4878aSAndroid Build Coastguard Worker                   reinterpret_cast<const std::optional<uint64_t>*>(
438*61c4878aSAndroid Build Coastguard Worker                       values.data());
439*61c4878aSAndroid Build Coastguard Worker               if (!optional->has_value()) {
440*61c4878aSAndroid Build Coastguard Worker                 continue;
441*61c4878aSAndroid Build Coastguard Worker               }
442*61c4878aSAndroid Build Coastguard Worker               value = optional->value();
443*61c4878aSAndroid Build Coastguard Worker             } else {
444*61c4878aSAndroid Build Coastguard Worker               const auto* optional =
445*61c4878aSAndroid Build Coastguard Worker                   reinterpret_cast<const std::optional<int64_t>*>(
446*61c4878aSAndroid Build Coastguard Worker                       values.data());
447*61c4878aSAndroid Build Coastguard Worker               if (!optional->has_value()) {
448*61c4878aSAndroid Build Coastguard Worker                 continue;
449*61c4878aSAndroid Build Coastguard Worker               }
450*61c4878aSAndroid Build Coastguard Worker               value = field.varint_type() == VarintType::kZigZag
451*61c4878aSAndroid Build Coastguard Worker                           ? varint::ZigZagEncode(optional->value())
452*61c4878aSAndroid Build Coastguard Worker                           : optional->value();
453*61c4878aSAndroid Build Coastguard Worker             }
454*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(uint32_t)) {
455*61c4878aSAndroid Build Coastguard Worker             if (field.varint_type() == VarintType::kUnsigned) {
456*61c4878aSAndroid Build Coastguard Worker               const auto* optional =
457*61c4878aSAndroid Build Coastguard Worker                   reinterpret_cast<const std::optional<uint32_t>*>(
458*61c4878aSAndroid Build Coastguard Worker                       values.data());
459*61c4878aSAndroid Build Coastguard Worker               if (!optional->has_value()) {
460*61c4878aSAndroid Build Coastguard Worker                 continue;
461*61c4878aSAndroid Build Coastguard Worker               }
462*61c4878aSAndroid Build Coastguard Worker               value = optional->value();
463*61c4878aSAndroid Build Coastguard Worker             } else {
464*61c4878aSAndroid Build Coastguard Worker               const auto* optional =
465*61c4878aSAndroid Build Coastguard Worker                   reinterpret_cast<const std::optional<int32_t>*>(
466*61c4878aSAndroid Build Coastguard Worker                       values.data());
467*61c4878aSAndroid Build Coastguard Worker               if (!optional->has_value()) {
468*61c4878aSAndroid Build Coastguard Worker                 continue;
469*61c4878aSAndroid Build Coastguard Worker               }
470*61c4878aSAndroid Build Coastguard Worker               value = field.varint_type() == VarintType::kZigZag
471*61c4878aSAndroid Build Coastguard Worker                           ? varint::ZigZagEncode(optional->value())
472*61c4878aSAndroid Build Coastguard Worker                           : optional->value();
473*61c4878aSAndroid Build Coastguard Worker             }
474*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(bool)) {
475*61c4878aSAndroid Build Coastguard Worker             const auto* optional =
476*61c4878aSAndroid Build Coastguard Worker                 reinterpret_cast<const std::optional<bool>*>(values.data());
477*61c4878aSAndroid Build Coastguard Worker             if (!optional->has_value()) {
478*61c4878aSAndroid Build Coastguard Worker               continue;
479*61c4878aSAndroid Build Coastguard Worker             }
480*61c4878aSAndroid Build Coastguard Worker             value = optional->value();
481*61c4878aSAndroid Build Coastguard Worker           }
482*61c4878aSAndroid Build Coastguard Worker           PW_TRY(WriteVarintField(field.field_number(), value));
483*61c4878aSAndroid Build Coastguard Worker         } else {
484*61c4878aSAndroid Build Coastguard Worker           // The struct member for this field is a scalar of a type
485*61c4878aSAndroid Build Coastguard Worker           // corresponding to the field element size. Cast to the correct
486*61c4878aSAndroid Build Coastguard Worker           // type to retrieve the value before passing to WriteVarintField()
487*61c4878aSAndroid Build Coastguard Worker           // so we're not performing type aliasing (except for unsigned vs
488*61c4878aSAndroid Build Coastguard Worker           // signed which is explicitly allowed).
489*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(values.size() == field.elem_size(),
490*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
491*61c4878aSAndroid Build Coastguard Worker           uint64_t value = 0;
492*61c4878aSAndroid Build Coastguard Worker           if (field.elem_size() == sizeof(uint64_t)) {
493*61c4878aSAndroid Build Coastguard Worker             if (field.varint_type() == VarintType::kZigZag) {
494*61c4878aSAndroid Build Coastguard Worker               value = varint::ZigZagEncode(
495*61c4878aSAndroid Build Coastguard Worker                   *reinterpret_cast<const int64_t*>(values.data()));
496*61c4878aSAndroid Build Coastguard Worker             } else if (field.varint_type() == VarintType::kNormal) {
497*61c4878aSAndroid Build Coastguard Worker               value = *reinterpret_cast<const int64_t*>(values.data());
498*61c4878aSAndroid Build Coastguard Worker             } else {
499*61c4878aSAndroid Build Coastguard Worker               value = *reinterpret_cast<const uint64_t*>(values.data());
500*61c4878aSAndroid Build Coastguard Worker             }
501*61c4878aSAndroid Build Coastguard Worker             if (!value) {
502*61c4878aSAndroid Build Coastguard Worker               continue;
503*61c4878aSAndroid Build Coastguard Worker             }
504*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(uint32_t)) {
505*61c4878aSAndroid Build Coastguard Worker             if (field.varint_type() == VarintType::kZigZag) {
506*61c4878aSAndroid Build Coastguard Worker               value = varint::ZigZagEncode(
507*61c4878aSAndroid Build Coastguard Worker                   *reinterpret_cast<const int32_t*>(values.data()));
508*61c4878aSAndroid Build Coastguard Worker             } else if (field.varint_type() == VarintType::kNormal) {
509*61c4878aSAndroid Build Coastguard Worker               value = *reinterpret_cast<const int32_t*>(values.data());
510*61c4878aSAndroid Build Coastguard Worker             } else {
511*61c4878aSAndroid Build Coastguard Worker               value = *reinterpret_cast<const uint32_t*>(values.data());
512*61c4878aSAndroid Build Coastguard Worker             }
513*61c4878aSAndroid Build Coastguard Worker             if (!value) {
514*61c4878aSAndroid Build Coastguard Worker               continue;
515*61c4878aSAndroid Build Coastguard Worker             }
516*61c4878aSAndroid Build Coastguard Worker           } else if (field.elem_size() == sizeof(bool)) {
517*61c4878aSAndroid Build Coastguard Worker             value = *reinterpret_cast<const bool*>(values.data());
518*61c4878aSAndroid Build Coastguard Worker             if (!value) {
519*61c4878aSAndroid Build Coastguard Worker               continue;
520*61c4878aSAndroid Build Coastguard Worker             }
521*61c4878aSAndroid Build Coastguard Worker           }
522*61c4878aSAndroid Build Coastguard Worker           PW_TRY(WriteVarintField(field.field_number(), value));
523*61c4878aSAndroid Build Coastguard Worker         }
524*61c4878aSAndroid Build Coastguard Worker         break;
525*61c4878aSAndroid Build Coastguard Worker       }
526*61c4878aSAndroid Build Coastguard Worker       case WireType::kDelimited: {
527*61c4878aSAndroid Build Coastguard Worker         // Delimited fields are always a singular case because of the
528*61c4878aSAndroid Build Coastguard Worker         // inability to cast to a generic vector with an element of a certain
529*61c4878aSAndroid Build Coastguard Worker         // size (we always need a type).
530*61c4878aSAndroid Build Coastguard Worker         PW_CHECK(!field.is_repeated(),
531*61c4878aSAndroid Build Coastguard Worker                  "Repeated delimited messages always require a callback");
532*61c4878aSAndroid Build Coastguard Worker         if (field.nested_message_fields()) {
533*61c4878aSAndroid Build Coastguard Worker           // Nested Message. Struct member is an embedded struct for the
534*61c4878aSAndroid Build Coastguard Worker           // nested field. Obtain a nested encoder and recursively call Write()
535*61c4878aSAndroid Build Coastguard Worker           // using the fields table pointer from this field.
536*61c4878aSAndroid Build Coastguard Worker           auto nested_encoder = GetNestedEncoder(field.field_number(),
537*61c4878aSAndroid Build Coastguard Worker                                                  /*write_when_empty=*/false);
538*61c4878aSAndroid Build Coastguard Worker           PW_TRY(nested_encoder.Write(values, *field.nested_message_fields()));
539*61c4878aSAndroid Build Coastguard Worker         } else if (field.is_fixed_size()) {
540*61c4878aSAndroid Build Coastguard Worker           // Fixed-length bytes field. Struct member is a std::array<std::byte>.
541*61c4878aSAndroid Build Coastguard Worker           // Call WriteLengthDelimitedField() to output it to the stream.
542*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field.elem_size() == sizeof(std::byte),
543*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
544*61c4878aSAndroid Build Coastguard Worker           if (static_cast<size_t>(
545*61c4878aSAndroid Build Coastguard Worker                   std::count(values.begin(), values.end(), std::byte{0})) <
546*61c4878aSAndroid Build Coastguard Worker               values.size()) {
547*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WriteLengthDelimitedField(field.field_number(), values));
548*61c4878aSAndroid Build Coastguard Worker           }
549*61c4878aSAndroid Build Coastguard Worker         } else {
550*61c4878aSAndroid Build Coastguard Worker           // bytes or string field with a maximum size. Struct member is
551*61c4878aSAndroid Build Coastguard Worker           // pw::Vector<std::byte> for bytes or pw::InlineString<> for string.
552*61c4878aSAndroid Build Coastguard Worker           // Use the contents as a span and call WriteLengthDelimitedField() to
553*61c4878aSAndroid Build Coastguard Worker           // output it to the stream.
554*61c4878aSAndroid Build Coastguard Worker           PW_CHECK(field.elem_size() == sizeof(std::byte),
555*61c4878aSAndroid Build Coastguard Worker                    "Mismatched message field type and size");
556*61c4878aSAndroid Build Coastguard Worker           if (field.is_string()) {
557*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WriteStringOrBytes<const InlineString<>>(
558*61c4878aSAndroid Build Coastguard Worker                 field.field_number(), values.data()));
559*61c4878aSAndroid Build Coastguard Worker           } else {
560*61c4878aSAndroid Build Coastguard Worker             PW_TRY(WriteStringOrBytes<const Vector<const std::byte>>(
561*61c4878aSAndroid Build Coastguard Worker                 field.field_number(), values.data()));
562*61c4878aSAndroid Build Coastguard Worker           }
563*61c4878aSAndroid Build Coastguard Worker         }
564*61c4878aSAndroid Build Coastguard Worker         break;
565*61c4878aSAndroid Build Coastguard Worker       }
566*61c4878aSAndroid Build Coastguard Worker     }
567*61c4878aSAndroid Build Coastguard Worker   }
568*61c4878aSAndroid Build Coastguard Worker 
569*61c4878aSAndroid Build Coastguard Worker   ResetOneOfCallbacks(message, table);
570*61c4878aSAndroid Build Coastguard Worker 
571*61c4878aSAndroid Build Coastguard Worker   return status_;
572*61c4878aSAndroid Build Coastguard Worker }
573*61c4878aSAndroid Build Coastguard Worker 
ResetOneOfCallbacks(ConstByteSpan message,span<const internal::MessageField> table)574*61c4878aSAndroid Build Coastguard Worker void StreamEncoder::ResetOneOfCallbacks(
575*61c4878aSAndroid Build Coastguard Worker     ConstByteSpan message, span<const internal::MessageField> table) {
576*61c4878aSAndroid Build Coastguard Worker   for (const auto& field : table) {
577*61c4878aSAndroid Build Coastguard Worker     // Calculate the span of bytes corresponding to the structure field to
578*61c4878aSAndroid Build Coastguard Worker     // read from.
579*61c4878aSAndroid Build Coastguard Worker     ConstByteSpan values =
580*61c4878aSAndroid Build Coastguard Worker         message.subspan(field.field_offset(), field.field_size());
581*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(values.begin() >= message.begin() &&
582*61c4878aSAndroid Build Coastguard Worker              values.end() <= message.end());
583*61c4878aSAndroid Build Coastguard Worker 
584*61c4878aSAndroid Build Coastguard Worker     if (field.callback_type() == internal::CallbackType::kOneOfGroup) {
585*61c4878aSAndroid Build Coastguard Worker       const OneOf<StreamEncoder, StreamDecoder>* callback =
586*61c4878aSAndroid Build Coastguard Worker           reinterpret_cast<const OneOf<StreamEncoder, StreamDecoder>*>(
587*61c4878aSAndroid Build Coastguard Worker               values.data());
588*61c4878aSAndroid Build Coastguard Worker       callback->invoked_ = false;
589*61c4878aSAndroid Build Coastguard Worker     }
590*61c4878aSAndroid Build Coastguard Worker   }
591*61c4878aSAndroid Build Coastguard Worker }
592*61c4878aSAndroid Build Coastguard Worker 
593*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::protobuf
594