Coverage Report

Created: 2024-07-09 06:09

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