Coverage Report

Created: 2025-06-13 06:31

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