Coverage Report

Created: 2026-02-14 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/pw_protobuf/encoder.cc
Line
Count
Source
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.0k
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.0k
  size_t key_size =
101
15.0k
      varint::EncodedSize(FieldKey(field_number, WireType::kDelimited));
102
15.0k
  size_t reserved_size = key_size + config::kMaxVarintSize;
103
15.0k
  size_t max_size = std::min(memory_writer_.ConservativeWriteLimit(),
104
15.0k
                             writer_.ConservativeWriteLimit());
105
  // Cap based on max varint size.
106
15.0k
  max_size = std::min(varint::MaxValueInBytes(config::kMaxVarintSize),
107
15.0k
                      static_cast<uint64_t>(max_size));
108
109
  // Account for reserved bytes.
110
15.0k
  max_size = max_size > reserved_size ? max_size - reserved_size : 0;
111
112
15.0k
  ByteSpan nested_buffer;
113
15.0k
  if (max_size > 0) {
114
8.18k
    nested_buffer = ByteSpan(
115
8.18k
        memory_writer_.data() + reserved_size + memory_writer_.bytes_written(),
116
8.18k
        max_size);
117
8.18k
  } else {
118
6.85k
    nested_buffer = ByteSpan();
119
6.85k
  }
120
15.0k
  return nested_buffer;
121
15.0k
}
122
123
StreamEncoder StreamEncoder::GetNestedEncoder(uint32_t field_number,
124
20.9k
                                              bool write_when_empty) {
125
20.9k
  PW_CHECK(!nested_encoder_open());
126
127
20.9k
  nested_field_number_ = field_number;
128
20.9k
  if (!ValidFieldNumber(field_number)) {
129
5.92k
    status_.Update(Status::InvalidArgument());
130
5.92k
    return StreamEncoder(*this, ByteSpan(), false);
131
5.92k
  }
132
133
15.0k
  ByteSpan nested_buffer = GetNestedScratchBuffer(field_number);
134
15.0k
  return StreamEncoder(*this, nested_buffer, write_when_empty);
135
20.9k
}
136
137
24.6k
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.6k
  if (nested_field_number_ == kFirstReservedNumber) {
141
0
    return;
142
0
  }
143
144
24.6k
  PW_CHECK(
145
24.6k
      !nested_encoder_open(),
146
24.6k
      "Tried to destruct a proto encoder with an active submessage encoder");
147
148
24.6k
  if (parent_ != nullptr) {
149
24.6k
    parent_->CloseNestedMessage(*this);
150
24.6k
  }
151
24.6k
}
152
153
24.6k
void StreamEncoder::CloseNestedMessage(StreamEncoder& nested) {
154
24.6k
  PW_DCHECK_PTR_EQ(nested.parent_,
155
24.6k
                   this,
156
24.6k
                   "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.6k
  nested.nested_field_number_ = kFirstReservedNumber;
161
24.6k
  nested.parent_ = nullptr;
162
  // Temporarily cache the field number of the child so we can re-enable
163
  // writing to this encoder.
164
24.6k
  uint32_t temp_field_number = nested_field_number_;
165
24.6k
  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.6k
  status_.Update(nested.status_);
171
24.6k
  if (!status_.ok()) {
172
18.8k
    return;
173
18.8k
  }
174
175
5.78k
  if (varint::EncodedSize(nested.memory_writer_.bytes_written()) >
176
5.78k
      config::kMaxVarintSize) {
177
0
    status_ = Status::OutOfRange();
178
0
    return;
179
0
  }
180
181
5.78k
  if (!nested.memory_writer_.bytes_written() && !nested.write_when_empty_) {
182
0
    return;
183
0
  }
184
185
5.78k
  status_ = WriteLengthDelimitedField(temp_field_number,
186
5.78k
                                      nested.memory_writer_.WrittenData());
187
5.78k
}
188
189
1.46M
Status StreamEncoder::WriteVarintField(uint32_t field_number, uint64_t value) {
190
1.46M
  PW_TRY(UpdateStatusForWrite(
191
6.64k
      field_number, WireType::kVarint, varint::EncodedSize(value)));
192
193
6.64k
  WriteVarint(FieldKey(field_number, WireType::kVarint))
194
6.64k
      .IgnoreError();  // TODO: b/242598609 - Handle Status properly
195
6.64k
  return WriteVarint(value);
196
1.46M
}
197
198
Status StreamEncoder::WriteLengthDelimitedField(uint32_t field_number,
199
175k
                                                ConstByteSpan data) {
200
175k
  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
8
    status_ = status;
206
8
  }
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
320k
Status StreamEncoder::WriteFixed(uint32_t field_number, ConstByteSpan data) {
265
320k
  WireType type =
266
320k
      data.size() == sizeof(uint32_t) ? WireType::kFixed32 : WireType::kFixed64;
267
268
320k
  PW_TRY(UpdateStatusForWrite(field_number, type, data.size()));
269
270
2.01k
  WriteVarint(FieldKey(field_number, type))
271
2.01k
      .IgnoreError();  // TODO: b/242598609 - Handle Status properly
272
2.01k
  if (Status status = writer_.Write(data); !status.ok()) {
273
0
    status_ = status;
274
0
  }
275
2.01k
  return status_;
276
320k
}
277
278
Status StreamEncoder::WritePackedFixed(uint32_t field_number,
279
                                       span<const std::byte> values,
280
9.40k
                                       size_t elem_size) {
281
9.40k
  if (values.empty()) {
282
5.09k
    return status_;
283
5.09k
  }
284
285
4.30k
  PW_CHECK_NOTNULL(values.data());
286
4.30k
  PW_DCHECK(elem_size == sizeof(uint32_t) || elem_size == sizeof(uint64_t));
287
288
4.30k
  PW_TRY(UpdateStatusForWrite(
289
1.01k
      field_number, WireType::kDelimited, values.size_bytes()));
290
1.01k
  WriteVarint(FieldKey(field_number, WireType::kDelimited))
291
1.01k
      .IgnoreError();  // TODO: b/242598609 - Handle Status properly
292
1.01k
  WriteVarint(values.size_bytes())
293
1.01k
      .IgnoreError();  // TODO: b/242598609 - Handle Status properly
294
295
1.01k
  auto element_size = static_cast<span<std::byte>::difference_type>(elem_size);
296
101k
  for (auto val_start = values.begin(); val_start != values.end();
297
100k
       val_start += element_size) {
298
    // Allocates 8 bytes so both 4-byte and 8-byte types can be encoded as
299
    // little-endian for serialization.
300
100k
    std::array<std::byte, sizeof(uint64_t)> data;
301
100k
    if (endian::native == endian::little) {
302
100k
      std::copy(val_start, val_start + element_size, std::begin(data));
303
100k
    } else {
304
0
      std::reverse_copy(val_start, val_start + element_size, std::begin(data));
305
0
    }
306
100k
    status_.Update(writer_.Write(span(data).first(elem_size)));
307
100k
    PW_TRY(status_);
308
100k
  }
309
1.01k
  return status_;
310
1.01k
}
311
312
Status StreamEncoder::UpdateStatusForWrite(uint32_t field_number,
313
                                           WireType type,
314
1.97M
                                           size_t data_size) {
315
1.97M
  PW_CHECK(!nested_encoder_open());
316
1.97M
  PW_TRY(status_);
317
318
37.5k
  if (!ValidFieldNumber(field_number)) {
319
3.15k
    return status_ = Status::InvalidArgument();
320
3.15k
  }
321
322
34.3k
  const Result<size_t> field_size = SizeOfField(field_number, type, data_size);
323
34.3k
  status_.Update(field_size.status());
324
34.3k
  PW_TRY(status_);
325
326
34.3k
  if (field_size.value() > writer_.ConservativeWriteLimit()) {
327
191
    status_ = Status::ResourceExhausted();
328
191
  }
329
330
34.3k
  return status_;
331
34.3k
}
332
333
Status StreamEncoder::Write(span<const std::byte> message,
334
0
                            span<const internal::MessageField> table) {
335
0
  PW_CHECK(!nested_encoder_open());
336
0
  PW_TRY(status_);
337
338
0
  for (const auto& field : table) {
339
    // Calculate the span of bytes corresponding to the structure field to
340
    // read from.
341
0
    ConstByteSpan values =
342
0
        message.subspan(field.field_offset(), field.field_size());
343
0
    PW_CHECK(values.begin() >= message.begin() &&
344
0
             values.end() <= message.end());
345
346
    // If the field is using callbacks, interpret the input field accordingly
347
    // and allow the caller to provide custom handling.
348
0
    if (field.callback_type() == internal::CallbackType::kSingleField) {
349
0
      const Callback<StreamEncoder, StreamDecoder>* callback =
350
0
          reinterpret_cast<const Callback<StreamEncoder, StreamDecoder>*>(
351
0
              values.data());
352
0
      PW_TRY(callback->Encode(*this));
353
0
      continue;
354
0
    } else if (field.callback_type() == internal::CallbackType::kOneOfGroup) {
355
0
      const OneOf<StreamEncoder, StreamDecoder>* callback =
356
0
          reinterpret_cast<const OneOf<StreamEncoder, StreamDecoder>*>(
357
0
              values.data());
358
0
      PW_TRY(callback->Encode(*this));
359
0
      continue;
360
0
    }
361
362
0
    switch (field.wire_type()) {
363
0
      case WireType::kFixed64:
364
0
      case WireType::kFixed32: {
365
        // Fixed fields call WriteFixed() for singular case and
366
        // WritePackedFixed() for repeated fields.
367
0
        PW_CHECK(field.elem_size() == (field.wire_type() == WireType::kFixed32
368
0
                                           ? sizeof(uint32_t)
369
0
                                           : sizeof(uint64_t)),
370
0
                 "Mismatched message field type and size");
371
0
        if (field.is_fixed_size()) {
372
0
          PW_CHECK(field.is_repeated(), "Non-repeated fixed size field");
373
0
          if (static_cast<size_t>(
374
0
                  std::count(values.begin(), values.end(), std::byte{0})) <
375
0
              values.size()) {
376
0
            PW_TRY(WritePackedFixed(
377
0
                field.field_number(), values, field.elem_size()));
378
0
          }
379
0
        } else if (field.is_repeated()) {
380
          // The struct member for this field is a vector of a type
381
          // corresponding to the field element size. Cast to the correct
382
          // vector type so we're not performing type aliasing (except for
383
          // unsigned vs signed which is explicitly allowed).
384
0
          if (field.elem_size() == sizeof(uint64_t)) {
385
0
            const auto* vector =
386
0
                reinterpret_cast<const pw::Vector<const uint64_t>*>(
387
0
                    values.data());
388
0
            if (!vector->empty()) {
389
0
              PW_TRY(WritePackedFixed(
390
0
                  field.field_number(),
391
0
                  as_bytes(span(vector->data(), vector->size())),
392
0
                  field.elem_size()));
393
0
            }
394
0
          } else if (field.elem_size() == sizeof(uint32_t)) {
395
0
            const auto* vector =
396
0
                reinterpret_cast<const pw::Vector<const uint32_t>*>(
397
0
                    values.data());
398
0
            if (!vector->empty()) {
399
0
              PW_TRY(WritePackedFixed(
400
0
                  field.field_number(),
401
0
                  as_bytes(span(vector->data(), vector->size())),
402
0
                  field.elem_size()));
403
0
            }
404
0
          }
405
0
        } else if (field.is_optional()) {
406
          // The struct member for this field is a std::optional of a type
407
          // corresponding to the field element size. Cast to the correct
408
          // optional type so we're not performing type aliasing (except for
409
          // unsigned vs signed which is explicitly allowed), and write from
410
          // a temporary.
411
0
          if (field.elem_size() == sizeof(uint64_t)) {
412
0
            const auto* optional =
413
0
                reinterpret_cast<const std::optional<uint64_t>*>(values.data());
414
0
            if (optional->has_value()) {
415
0
              uint64_t value = optional->value();
416
0
              PW_TRY(
417
0
                  WriteFixed(field.field_number(), as_bytes(span(&value, 1))));
418
0
            }
419
0
          } else if (field.elem_size() == sizeof(uint32_t)) {
420
0
            const auto* optional =
421
0
                reinterpret_cast<const std::optional<uint32_t>*>(values.data());
422
0
            if (optional->has_value()) {
423
0
              uint32_t value = optional->value();
424
0
              PW_TRY(
425
0
                  WriteFixed(field.field_number(), as_bytes(span(&value, 1))));
426
0
            }
427
0
          }
428
0
        } else {
429
0
          PW_CHECK(values.size() == field.elem_size(),
430
0
                   "Mismatched message field type and size");
431
0
          if (static_cast<size_t>(
432
0
                  std::count(values.begin(), values.end(), std::byte{0})) <
433
0
              values.size()) {
434
0
            PW_TRY(WriteFixed(field.field_number(), values));
435
0
          }
436
0
        }
437
0
        break;
438
0
      }
439
0
      case WireType::kVarint: {
440
        // Varint fields call WriteVarintField() for singular case and
441
        // WritePackedVarints() for repeated fields.
442
0
        PW_CHECK(field.elem_size() == sizeof(uint64_t) ||
443
0
                     field.elem_size() == sizeof(uint32_t) ||
444
0
                     field.elem_size() == sizeof(bool),
445
0
                 "Mismatched message field type and size");
446
0
        if (field.is_fixed_size()) {
447
          // The struct member for this field is an array of type corresponding
448
          // to the field element size. Cast to a span of the correct type over
449
          // the array so we're not performing type aliasing (except for
450
          // unsigned vs signed which is explicitly allowed).
451
0
          PW_CHECK(field.is_repeated(), "Non-repeated fixed size field");
452
0
          if (static_cast<size_t>(
453
0
                  std::count(values.begin(), values.end(), std::byte{0})) ==
454
0
              values.size()) {
455
0
            continue;
456
0
          }
457
0
          if (field.elem_size() == sizeof(uint64_t)) {
458
0
            PW_TRY(WritePackedVarints(
459
0
                field.field_number(),
460
0
                span(reinterpret_cast<const uint64_t*>(values.data()),
461
0
                     values.size() / field.elem_size()),
462
0
                field.varint_type()));
463
0
          } else if (field.elem_size() == sizeof(uint32_t)) {
464
0
            PW_TRY(WritePackedVarints(
465
0
                field.field_number(),
466
0
                span(reinterpret_cast<const uint32_t*>(values.data()),
467
0
                     values.size() / field.elem_size()),
468
0
                field.varint_type()));
469
0
          } else if (field.elem_size() == sizeof(bool)) {
470
0
            static_assert(sizeof(bool) == sizeof(uint8_t),
471
0
                          "bool must be same size as uint8_t");
472
0
            PW_TRY(WritePackedVarints(
473
0
                field.field_number(),
474
0
                span(reinterpret_cast<const uint8_t*>(values.data()),
475
0
                     values.size() / field.elem_size()),
476
0
                field.varint_type()));
477
0
          }
478
0
        } else if (field.is_repeated()) {
479
          // The struct member for this field is a vector of a type
480
          // corresponding to the field element size. Cast to the correct
481
          // vector type so we're not performing type aliasing (except for
482
          // unsigned vs signed which is explicitly allowed).
483
0
          if (field.elem_size() == sizeof(uint64_t)) {
484
0
            const auto* vector =
485
0
                reinterpret_cast<const pw::Vector<const uint64_t>*>(
486
0
                    values.data());
487
0
            if (!vector->empty()) {
488
0
              PW_TRY(WritePackedVarints(field.field_number(),
489
0
                                        span(vector->data(), vector->size()),
490
0
                                        field.varint_type()));
491
0
            }
492
0
          } else if (field.elem_size() == sizeof(uint32_t)) {
493
0
            const auto* vector =
494
0
                reinterpret_cast<const pw::Vector<const uint32_t>*>(
495
0
                    values.data());
496
0
            if (!vector->empty()) {
497
0
              PW_TRY(WritePackedVarints(field.field_number(),
498
0
                                        span(vector->data(), vector->size()),
499
0
                                        field.varint_type()));
500
0
            }
501
0
          } else if (field.elem_size() == sizeof(bool)) {
502
0
            static_assert(sizeof(bool) == sizeof(uint8_t),
503
0
                          "bool must be same size as uint8_t");
504
0
            const auto* vector =
505
0
                reinterpret_cast<const pw::Vector<const uint8_t>*>(
506
0
                    values.data());
507
0
            if (!vector->empty()) {
508
0
              PW_TRY(WritePackedVarints(field.field_number(),
509
0
                                        span(vector->data(), vector->size()),
510
0
                                        field.varint_type()));
511
0
            }
512
0
          }
513
0
        } else if (field.is_optional()) {
514
          // The struct member for this field is a std::optional of a type
515
          // corresponding to the field element size. Cast to the correct
516
          // optional type so we're not performing type aliasing (except for
517
          // unsigned vs signed which is explicitly allowed), and write from
518
          // a temporary.
519
0
          uint64_t value = 0;
520
0
          if (field.elem_size() == sizeof(uint64_t)) {
521
0
            if (field.varint_type() == VarintType::kUnsigned) {
522
0
              const auto* optional =
523
0
                  reinterpret_cast<const std::optional<uint64_t>*>(
524
0
                      values.data());
525
0
              if (!optional->has_value()) {
526
0
                continue;
527
0
              }
528
0
              value = optional->value();
529
0
            } else {
530
0
              const auto* optional =
531
0
                  reinterpret_cast<const std::optional<int64_t>*>(
532
0
                      values.data());
533
0
              if (!optional->has_value()) {
534
0
                continue;
535
0
              }
536
0
              value = field.varint_type() == VarintType::kZigZag
537
0
                          ? varint::ZigZagEncode(optional->value())
538
0
                          : static_cast<uint64_t>(optional->value());
539
0
            }
540
0
          } else if (field.elem_size() == sizeof(uint32_t)) {
541
0
            if (field.varint_type() == VarintType::kUnsigned) {
542
0
              const auto* optional =
543
0
                  reinterpret_cast<const std::optional<uint32_t>*>(
544
0
                      values.data());
545
0
              if (!optional->has_value()) {
546
0
                continue;
547
0
              }
548
0
              value = optional->value();
549
0
            } else {
550
0
              const auto* optional =
551
0
                  reinterpret_cast<const std::optional<int32_t>*>(
552
0
                      values.data());
553
0
              if (!optional->has_value()) {
554
0
                continue;
555
0
              }
556
0
              value = field.varint_type() == VarintType::kZigZag
557
0
                          ? varint::ZigZagEncode(optional->value())
558
0
                          : static_cast<uint64_t>(optional->value());
559
0
            }
560
0
          } else if (field.elem_size() == sizeof(bool)) {
561
0
            const auto* optional =
562
0
                reinterpret_cast<const std::optional<bool>*>(values.data());
563
0
            if (!optional->has_value()) {
564
0
              continue;
565
0
            }
566
0
            value = optional->value();
567
0
          }
568
0
          PW_TRY(WriteVarintField(field.field_number(), value));
569
0
        } else {
570
          // The struct member for this field is a scalar of a type
571
          // corresponding to the field element size. Cast to the correct
572
          // type to retrieve the value before passing to WriteVarintField()
573
          // so we're not performing type aliasing (except for unsigned vs
574
          // signed which is explicitly allowed).
575
0
          PW_CHECK(values.size() == field.elem_size(),
576
0
                   "Mismatched message field type and size");
577
0
          uint64_t value = 0;
578
0
          if (field.elem_size() == sizeof(uint64_t)) {
579
0
            if (field.varint_type() == VarintType::kZigZag) {
580
0
              value = varint::ZigZagEncode(
581
0
                  *reinterpret_cast<const int64_t*>(values.data()));
582
0
            } else if (field.varint_type() == VarintType::kNormal) {
583
0
              value = *reinterpret_cast<const uint64_t*>(values.data());
584
0
            } else {
585
0
              value = *reinterpret_cast<const uint64_t*>(values.data());
586
0
            }
587
0
            if (!value) {
588
0
              continue;
589
0
            }
590
0
          } else if (field.elem_size() == sizeof(uint32_t)) {
591
0
            if (field.varint_type() == VarintType::kZigZag) {
592
0
              value = varint::ZigZagEncode(
593
0
                  *reinterpret_cast<const int32_t*>(values.data()));
594
0
            } else if (field.varint_type() == VarintType::kNormal) {
595
0
              value = static_cast<uint64_t>(
596
0
                  *reinterpret_cast<const int32_t*>(values.data()));
597
0
            } else {
598
0
              value = *reinterpret_cast<const uint32_t*>(values.data());
599
0
            }
600
0
            if (!value) {
601
0
              continue;
602
0
            }
603
0
          } else if (field.elem_size() == sizeof(bool)) {
604
0
            value = *reinterpret_cast<const bool*>(values.data());
605
0
            if (!value) {
606
0
              continue;
607
0
            }
608
0
          }
609
0
          PW_TRY(WriteVarintField(field.field_number(), value));
610
0
        }
611
0
        break;
612
0
      }
613
0
      case WireType::kDelimited: {
614
        // Delimited fields are always a singular case because of the
615
        // inability to cast to a generic vector with an element of a certain
616
        // size (we always need a type).
617
0
        PW_CHECK(!field.is_repeated(),
618
0
                 "Repeated delimited messages always require a callback");
619
0
        if (field.nested_message_fields()) {
620
          // Nested Message. Struct member is an embedded struct for the
621
          // nested field. Obtain a nested encoder and recursively call Write()
622
          // using the fields table pointer from this field.
623
0
          auto nested_encoder = GetNestedEncoder(field.field_number(),
624
0
                                                 /*write_when_empty=*/false);
625
0
          PW_TRY(nested_encoder.Write(values, *field.nested_message_fields()));
626
0
        } else if (field.is_fixed_size()) {
627
          // Fixed-length bytes field. Struct member is a std::array<std::byte>.
628
          // Call WriteLengthDelimitedField() to output it to the stream.
629
0
          PW_CHECK(field.elem_size() == sizeof(std::byte),
630
0
                   "Mismatched message field type and size");
631
0
          if (static_cast<size_t>(
632
0
                  std::count(values.begin(), values.end(), std::byte{0})) <
633
0
              values.size()) {
634
0
            PW_TRY(WriteLengthDelimitedField(field.field_number(), values));
635
0
          }
636
0
        } else {
637
          // bytes or string field with a maximum size. Struct member is
638
          // pw::Vector<std::byte> for bytes or pw::InlineString<> for string.
639
          // Use the contents as a span and call WriteLengthDelimitedField() to
640
          // output it to the stream.
641
0
          PW_CHECK(field.elem_size() == sizeof(std::byte),
642
0
                   "Mismatched message field type and size");
643
0
          if (field.is_string()) {
644
0
            PW_TRY(WriteStringOrBytes<const InlineString<>>(
645
0
                field.field_number(), values.data()));
646
0
          } else {
647
0
            PW_TRY(WriteStringOrBytes<const Vector<const std::byte>>(
648
0
                field.field_number(), values.data()));
649
0
          }
650
0
        }
651
0
        break;
652
0
      }
653
0
    }
654
0
  }
655
656
0
  ResetOneOfCallbacks(message, table);
657
658
0
  return status_;
659
0
}
660
661
void StreamEncoder::ResetOneOfCallbacks(
662
0
    ConstByteSpan message, span<const internal::MessageField> table) {
663
0
  for (const auto& field : table) {
664
    // Calculate the span of bytes corresponding to the structure field to
665
    // read from.
666
0
    ConstByteSpan values =
667
0
        message.subspan(field.field_offset(), field.field_size());
668
0
    PW_CHECK(values.begin() >= message.begin() &&
669
0
             values.end() <= message.end());
670
671
0
    if (field.callback_type() == internal::CallbackType::kOneOfGroup) {
672
0
      const OneOf<StreamEncoder, StreamDecoder>* callback =
673
0
          reinterpret_cast<const OneOf<StreamEncoder, StreamDecoder>*>(
674
0
              values.data());
675
0
      callback->invoked_ = false;
676
0
    }
677
0
  }
678
0
}
679
680
}  // namespace pw::protobuf