Coverage Report

Created: 2025-08-28 06:26

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