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