Coverage Report

Created: 2023-12-29 07:19

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