pw_protobuf: Add encoder+decoder size reports
Adds size reports for pw_protobuf's base encoder and decoder types,
excluding any codegen.
Change-Id: I64ca6468a62d5aa111249c9614a4c2bc003d8edf
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/109011
Commit-Queue: Armando Montanez <amontanez@google.com>
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
diff --git a/pw_protobuf/BUILD.gn b/pw_protobuf/BUILD.gn
index a68ae74..b307c1d 100644
--- a/pw_protobuf/BUILD.gn
+++ b/pw_protobuf/BUILD.gn
@@ -96,8 +96,9 @@
pw_doc_group("docs") {
sources = [ "docs.rst" ]
report_deps = [
- "size_report:decoder_full",
"size_report:decoder_incremental",
+ "size_report:decoder_partial",
+ "size_report:protobuf_overview",
]
}
diff --git a/pw_protobuf/docs.rst b/pw_protobuf/docs.rst
index b25c02e..0c192ae 100644
--- a/pw_protobuf/docs.rst
+++ b/pw_protobuf/docs.rst
@@ -27,9 +27,10 @@
2. Per-Field Writers and Readers,
3. Direct Writers and Readers.
-This has a few benefits. The primary one is that it allows the library to be
-incredibly small, with the encoder and decoder each having a code size of
-around 1.5K and negligible RAM usage.
+This has a few benefits. The primary one is that it allows the core proto
+serialization and deserialization libraries to be relatively small.
+
+.. include:: size_report/protobuf_overview
To demonstrate these layers, we use the following protobuf message definition
in the examples:
@@ -2016,7 +2017,7 @@
decode methods and a decode callback for a proto message containing each of the
protobuf field types.
-.. include:: size_report/decoder_full
+.. include:: size_report/decoder_partial
Incremental size report
diff --git a/pw_protobuf/size_report/BUILD.bazel b/pw_protobuf/size_report/BUILD.bazel
new file mode 100644
index 0000000..aea516d
--- /dev/null
+++ b/pw_protobuf/size_report/BUILD.bazel
@@ -0,0 +1,95 @@
+# Copyright 2022 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load(
+ "//pw_build:pigweed.bzl",
+ "pw_cc_binary",
+ "pw_cc_library",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+pw_cc_binary(
+ name = "decoder_partial",
+ srcs = [
+ "decoder_partial.cc",
+ ],
+ deps = [
+ "//pw_bloat:bloat_this_binary",
+ "//pw_preprocessor",
+ "//pw_protobuf",
+ ],
+)
+
+pw_cc_binary(
+ name = "decoder_incremental",
+ srcs = [
+ "decoder_incremental.cc",
+ ],
+ deps = [
+ "//pw_bloat:bloat_this_binary",
+ "//pw_preprocessor",
+ "//pw_protobuf",
+ ],
+)
+
+pw_cc_library(
+ name = "proto_bloat",
+ srcs = [
+ "proto_bloat.cc",
+ ],
+ hdrs = ["proto_bloat.h"],
+ deps = [
+ "//pw_containers",
+ "//pw_preprocessor",
+ "//pw_protobuf",
+ "//pw_status",
+ "//pw_stream",
+ ],
+)
+
+pw_cc_binary(
+ name = "encode_decode_core",
+ srcs = [
+ "encode_decode_core.cc",
+ ],
+ deps = [
+ ":proto_bloat",
+ "//pw_bloat:bloat_this_binary",
+ ],
+)
+
+pw_cc_binary(
+ name = "message_core",
+ srcs = [
+ "message_core.cc",
+ ],
+ deps = [
+ ":proto_bloat",
+ "//pw_bloat:bloat_this_binary",
+ ],
+)
+
+pw_cc_binary(
+ name = "proto_base",
+ srcs = [
+ "proto_base.cc",
+ ],
+ deps = [
+ ":proto_bloat",
+ "//pw_bloat:bloat_this_binary",
+ ],
+)
diff --git a/pw_protobuf/size_report/BUILD.gn b/pw_protobuf/size_report/BUILD.gn
index 1c71180..dd3d310 100644
--- a/pw_protobuf/size_report/BUILD.gn
+++ b/pw_protobuf/size_report/BUILD.gn
@@ -15,24 +15,61 @@
import("//build_overrides/pigweed.gni")
import("$dir_pw_bloat/bloat.gni")
+import("$dir_pw_build/target_types.gni")
-_decoder_full = {
+_decoder_partial = {
deps = [
"$dir_pw_bloat:bloat_this_binary",
"$dir_pw_preprocessor",
- "$dir_pw_protobuf:pw_protobuf",
+ "$dir_pw_protobuf",
]
- sources = [ "decoder_full.cc" ]
+ sources = [ "decoder_partial.cc" ]
}
-pw_toolchain_size_diff("decoder_full") {
+pw_source_set("proto_bloat") {
+ public = [ "proto_bloat.h" ]
+ deps = [
+ "$dir_pw_containers",
+ "$dir_pw_preprocessor",
+ "$dir_pw_protobuf",
+ "$dir_pw_status",
+ "$dir_pw_stream",
+ ]
+ sources = [ "proto_bloat.cc" ]
+}
+
+pw_executable("proto_base") {
+ deps = [
+ ":proto_bloat",
+ "$dir_pw_bloat:bloat_this_binary",
+ ]
+ sources = [ "proto_base.cc" ]
+}
+
+pw_executable("encode_decode_core") {
+ deps = [
+ ":proto_bloat",
+ "$dir_pw_bloat:bloat_this_binary",
+ ]
+ sources = [ "encode_decode_core.cc" ]
+}
+
+pw_executable("message_core") {
+ deps = [
+ ":proto_bloat",
+ "$dir_pw_bloat:bloat_this_binary",
+ ]
+ sources = [ "message_core.cc" ]
+}
+
+pw_toolchain_size_diff("decoder_partial") {
base_executable = pw_bloat_empty_base
- diff_executable = _decoder_full
+ diff_executable = _decoder_partial
title = "Size of all decoder methods"
}
pw_toolchain_size_diff("decoder_incremental") {
- base_executable = _decoder_full
+ base_executable = _decoder_partial
diff_executable = {
deps = [
"$dir_pw_bloat:bloat_this_binary",
@@ -43,3 +80,20 @@
}
title = "Adding more fields to decode callback"
}
+
+pw_size_diff("protobuf_overview") {
+ title = "Pigweed protobuf encoder size report"
+ source_filter = "pw::protobuf::*|section .code"
+ binaries = [
+ {
+ target = ":encode_decode_core"
+ base = ":proto_base"
+ label = "Full wire-format proto encode/decode library"
+ },
+ {
+ target = ":message_core"
+ base = ":proto_base"
+ label = "Including table-based `Message` encoder and decoder"
+ },
+ ]
+}
diff --git a/pw_protobuf/size_report/decoder_full.cc b/pw_protobuf/size_report/decoder_partial.cc
similarity index 100%
rename from pw_protobuf/size_report/decoder_full.cc
rename to pw_protobuf/size_report/decoder_partial.cc
diff --git a/pw_protobuf/size_report/encode_decode_core.cc b/pw_protobuf/size_report/encode_decode_core.cc
new file mode 100644
index 0000000..4a85404
--- /dev/null
+++ b/pw_protobuf/size_report/encode_decode_core.cc
@@ -0,0 +1,25 @@
+// Copyright 2022 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "proto_bloat.h"
+#include "pw_bloat/bloat_this_binary.h"
+
+int main() {
+ pw::bloat::BloatThisBinary();
+ pw::protobuf_size_report::BloatWithBase();
+ pw::protobuf_size_report::BloatWithEncoder();
+ pw::protobuf_size_report::BloatWithDecoder();
+ pw::protobuf_size_report::BloatWithStreamDecoder();
+ return 0;
+}
diff --git a/pw_protobuf/size_report/message_core.cc b/pw_protobuf/size_report/message_core.cc
new file mode 100644
index 0000000..a5e2759
--- /dev/null
+++ b/pw_protobuf/size_report/message_core.cc
@@ -0,0 +1,27 @@
+// Copyright 2022 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "proto_bloat.h"
+#include "pw_bloat/bloat_this_binary.h"
+
+int main() {
+ pw::bloat::BloatThisBinary();
+ pw::protobuf_size_report::BloatWithBase();
+ pw::protobuf_size_report::BloatWithEncoder();
+ pw::protobuf_size_report::BloatWithDecoder();
+ pw::protobuf_size_report::BloatWithStreamDecoder();
+ pw::protobuf_size_report::BloatWithTableEncoder();
+ pw::protobuf_size_report::BloatWithTableDecoder();
+ return 0;
+}
diff --git a/pw_protobuf/size_report/proto_base.cc b/pw_protobuf/size_report/proto_base.cc
new file mode 100644
index 0000000..49be2a6
--- /dev/null
+++ b/pw_protobuf/size_report/proto_base.cc
@@ -0,0 +1,22 @@
+// Copyright 2022 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "proto_bloat.h"
+#include "pw_bloat/bloat_this_binary.h"
+
+int main() {
+ pw::bloat::BloatThisBinary();
+ pw::protobuf_size_report::BloatWithBase();
+ return 0;
+}
diff --git a/pw_protobuf/size_report/proto_bloat.cc b/pw_protobuf/size_report/proto_bloat.cc
new file mode 100644
index 0000000..542653d
--- /dev/null
+++ b/pw_protobuf/size_report/proto_bloat.cc
@@ -0,0 +1,350 @@
+// Copyright 2022 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "proto_bloat.h"
+
+#include <array>
+#include <cstdint>
+#include <string_view>
+
+#include "pw_containers/vector.h"
+#include "pw_preprocessor/concat.h"
+#include "pw_protobuf/decoder.h"
+#include "pw_protobuf/encoder.h"
+#include "pw_protobuf/stream_decoder.h"
+#include "pw_status/status.h"
+#include "pw_stream/null_stream.h"
+#include "pw_stream/stream.h"
+
+namespace pw::protobuf_size_report {
+namespace {
+
+template <typename T>
+constexpr std::array<T, 4> GetIntegerArray() {
+ return std::array<T, 4>{958736, 2085792374, 0, 42};
+}
+
+template <typename T>
+constexpr Vector<T, 4> GetIntegerVector() {
+ return Vector<T, 4>{958736, 2085792374, 0, 42};
+}
+
+constexpr std::array<bool, 5> GetBoolArray() {
+ return std::array<bool, 5>{true, false, false, true, true};
+}
+
+Vector<bool, 5> GetBoolVector() {
+ return Vector<bool, 5>{true, false, false, true, true};
+}
+
+constexpr std::array<float, 5> GetFloatArray() {
+ return std::array<float, 5>{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f};
+}
+
+Vector<float, 5> GetFloatVector() {
+ return Vector<float, 5>{1.2f, 3.4f, 5.6e20f, 0.0789f, 0.0f};
+}
+
+constexpr std::array<double, 5> GetDoubleArray() {
+ return std::array<double, 5>{1.2, 3.4, 5.6e20, 0.0789, 0.0};
+}
+
+Vector<double, 5> GetDoubleVector() {
+ return Vector<double, 5>{1.2, 3.4, 5.6e20, 0.0789, 0.0};
+}
+
+constexpr std::string_view kTestString("I eat chips too often");
+
+constexpr protobuf::internal::MessageField kFakeTable[] = {
+ {4567,
+ protobuf::WireType::kDelimited,
+ 234567,
+ protobuf::internal::VarintType::kNormal,
+ false,
+ true,
+ true,
+ true,
+ true,
+ 260,
+ 840245,
+ nullptr},
+ {4567,
+ protobuf::WireType::kDelimited,
+ 234567,
+ protobuf::internal::VarintType::kNormal,
+ false,
+ true,
+ true,
+ true,
+ true,
+ 260,
+ 840245,
+ nullptr}};
+
+class FakeMessageEncoder : public protobuf::StreamEncoder {
+ public:
+ FakeMessageEncoder(stream::Writer& writer)
+ : protobuf::StreamEncoder(writer, ByteSpan()) {}
+ void DoBloat() { Write(ByteSpan(), kFakeTable); }
+};
+
+class FakeMessageDecoder : public protobuf::StreamDecoder {
+ public:
+ FakeMessageDecoder(stream::Reader& reader)
+ : protobuf::StreamDecoder(reader) {}
+ void DoBloat() { Read(ByteSpan(), kFakeTable); }
+};
+
+void CodeToSetUpSizeReportEnvironment() {
+ [[maybe_unused]] volatile auto arr1 = GetIntegerArray<uint32_t>();
+ [[maybe_unused]] volatile auto arr2 = GetIntegerArray<int32_t>();
+ [[maybe_unused]] volatile auto arr3 = GetIntegerArray<uint64_t>();
+ [[maybe_unused]] volatile auto arr4 = GetIntegerArray<int64_t>();
+
+ [[maybe_unused]] volatile auto vec1 = GetIntegerVector<uint32_t>();
+ [[maybe_unused]] volatile auto vec2 = GetIntegerVector<int32_t>();
+ [[maybe_unused]] volatile auto vec3 = GetIntegerVector<uint64_t>();
+ [[maybe_unused]] volatile auto vec4 = GetIntegerVector<int64_t>();
+
+ [[maybe_unused]] volatile auto bool1 = GetBoolArray();
+ [[maybe_unused]] volatile auto bool2 = GetBoolVector();
+
+ [[maybe_unused]] volatile auto float1 = GetFloatArray();
+ [[maybe_unused]] volatile auto float2 = GetFloatVector();
+
+ [[maybe_unused]] volatile auto double1 = GetDoubleArray();
+ [[maybe_unused]] volatile auto double2 = GetDoubleVector();
+
+ [[maybe_unused]] volatile std::string_view test_string = kTestString;
+
+ [[maybe_unused]] volatile stream::NullStream null_stream;
+}
+
+void Dependencies() {
+ std::array<std::byte, 2> buffer;
+ stream::NullStream null_stream;
+ stream::MemoryWriter memory_writer(buffer);
+ memory_writer.Write(buffer);
+ null_stream.Write(buffer);
+ stream::MemoryReader memory_reader(buffer);
+ memory_reader.Read(buffer).IgnoreError();
+}
+
+void CodeToPullInProtoEncoder() {
+ std::array<std::byte, 1024> buffer;
+ protobuf::MemoryEncoder encoder(buffer);
+
+ encoder.WriteUint32(1, 1);
+ encoder.WritePackedUint32(1, GetIntegerArray<uint32_t>());
+ encoder.WriteRepeatedUint32(1, GetIntegerVector<uint32_t>());
+
+ encoder.WriteInt32(1, 1);
+ encoder.WritePackedInt32(1, GetIntegerArray<int32_t>());
+ encoder.WriteRepeatedInt32(1, GetIntegerVector<int32_t>());
+
+ encoder.WriteUint64(1, 1);
+ encoder.WritePackedUint64(1, GetIntegerArray<uint64_t>());
+ encoder.WriteRepeatedUint64(1, GetIntegerVector<uint64_t>());
+
+ encoder.WriteInt64(1, 1);
+ encoder.WritePackedInt64(1, GetIntegerArray<int64_t>());
+ encoder.WriteRepeatedInt64(1, GetIntegerVector<int64_t>());
+
+ encoder.WriteSint32(1, 1);
+ encoder.WritePackedSint32(1, GetIntegerArray<int32_t>());
+ encoder.WriteRepeatedSint32(1, GetIntegerVector<int32_t>());
+
+ encoder.WriteSint64(1, 1);
+ encoder.WritePackedSint64(1, GetIntegerArray<int64_t>());
+ encoder.WriteRepeatedSint64(1, GetIntegerVector<int64_t>());
+
+ encoder.WriteFixed32(1, 1);
+ encoder.WritePackedFixed32(1, GetIntegerArray<uint32_t>());
+ encoder.WriteRepeatedFixed32(1, GetIntegerVector<uint32_t>());
+
+ encoder.WriteFixed64(1, 1);
+ encoder.WritePackedFixed64(1, GetIntegerArray<uint64_t>());
+ encoder.WriteRepeatedFixed64(1, GetIntegerVector<uint64_t>());
+
+ encoder.WriteSfixed32(1, 1);
+ encoder.WritePackedSfixed32(1, GetIntegerArray<int32_t>());
+ encoder.WriteRepeatedSfixed32(1, GetIntegerVector<int32_t>());
+
+ encoder.WriteSfixed64(1, 1);
+ encoder.WritePackedSfixed64(1, GetIntegerArray<int64_t>());
+ encoder.WriteRepeatedSfixed64(1, GetIntegerVector<int64_t>());
+
+ {
+ protobuf::StreamEncoder child = encoder.GetNestedEncoder(0xc01dfee7);
+
+ child.WriteFloat(234, 3.14f);
+ child.WritePackedFloat(234, GetFloatArray());
+ child.WriteRepeatedFloat(234, GetFloatVector());
+
+ child.WriteFloat(234, 3.14);
+ child.WritePackedDouble(234, GetDoubleArray());
+ child.WriteRepeatedDouble(234, GetDoubleVector());
+
+ child.WriteBool(7, true);
+ child.WritePackedBool(8, GetBoolArray());
+ child.WriteRepeatedBool(8, GetBoolVector());
+
+ encoder.WriteBytes(93, as_bytes(span(GetDoubleArray())));
+ encoder.WriteString(21343, kTestString);
+ }
+
+ stream::NullStream null_stream;
+ protobuf::StreamEncoder stream_encoder(null_stream, buffer);
+ stream_encoder.WriteBytesFromStream(3636, null_stream, 10824, buffer);
+}
+
+void CodeToPullInTableEncoder() {
+ stream::NullStream stream;
+ FakeMessageEncoder fake_encoder(stream);
+ fake_encoder.DoBloat();
+}
+
+void CodeToPullInTableDecoder() {
+ stream::NullStream stream;
+ FakeMessageDecoder fake_decoder(stream);
+ fake_decoder.DoBloat();
+}
+
+#define _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(type_camel_case, underlying_type) \
+ do { \
+ Status status; \
+ Vector<underlying_type, 3> vec; \
+ span<underlying_type> packed_span; \
+ status.Update(decoder.PW_CONCAT(Read, type_camel_case)().status()); \
+ status.Update( \
+ decoder.PW_CONCAT(ReadPacked, type_camel_case)(packed_span).status()); \
+ status.Update(decoder.PW_CONCAT(ReadRepeated, type_camel_case)(vec)); \
+ [[maybe_unused]] volatile bool ok = status.ok(); \
+ } while (0)
+
+void CodeToPullInProtoStreamDecoder() {
+ stream::NullStream null_stream;
+ protobuf::StreamDecoder decoder(null_stream);
+ decoder.Next().IgnoreError();
+
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int32, int32_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint32, uint32_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Int64, int64_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Uint64, uint64_t);
+
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint32, int32_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sint64, int64_t);
+
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Bool, bool);
+
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed32, uint32_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Fixed64, uint64_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed32, int32_t);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Sfixed64, int64_t);
+
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Float, float);
+ _PW_USE_FUNCTIONS_FOR_STREAM_DECODER(Double, double);
+
+ {
+ Status status;
+ span<char> str_out;
+ span<std::byte> bytes_out;
+ status.Update(decoder.ReadString(str_out).status());
+ status.Update(decoder.ReadBytes(bytes_out).status());
+ status.Update(decoder.GetLengthDelimitedPayloadBounds().status());
+ [[maybe_unused]] volatile Result<uint32_t> field_number =
+ decoder.FieldNumber();
+ [[maybe_unused]] volatile protobuf::StreamDecoder::BytesReader
+ bytes_reader = decoder.GetBytesReader();
+ [[maybe_unused]] volatile bool ok = status.ok();
+ }
+}
+
+#define _PW_USE_FUNCTIONS_FOR_DECODER(type_camel_case, underlying_type) \
+ do { \
+ Status status; \
+ underlying_type val; \
+ status.Update(decoder.PW_CONCAT(Read, type_camel_case)(&val)); \
+ [[maybe_unused]] volatile bool ok = status.ok(); \
+ } while (0)
+
+void CodeToPullInProtoDecoder() {
+ std::array<std::byte, 3> buffer = {
+ std::byte(0x01), std::byte(0xff), std::byte(0x08)};
+ protobuf::Decoder decoder(buffer);
+ decoder.Next().IgnoreError();
+
+ _PW_USE_FUNCTIONS_FOR_DECODER(Int32, int32_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Uint32, uint32_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Int64, int64_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Uint64, uint64_t);
+
+ _PW_USE_FUNCTIONS_FOR_DECODER(Sint32, int32_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Sint64, int64_t);
+
+ _PW_USE_FUNCTIONS_FOR_DECODER(Bool, bool);
+
+ _PW_USE_FUNCTIONS_FOR_DECODER(Fixed32, uint32_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Fixed64, uint64_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Sfixed32, int32_t);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Sfixed64, int64_t);
+
+ _PW_USE_FUNCTIONS_FOR_DECODER(Float, float);
+ _PW_USE_FUNCTIONS_FOR_DECODER(Double, double);
+
+ {
+ Status status;
+ std::string_view str_out;
+ span<const std::byte> bytes_out;
+ status.Update(decoder.ReadString(&str_out));
+ status.Update(decoder.ReadBytes(&bytes_out));
+ decoder.Reset(buffer);
+ [[maybe_unused]] volatile uint32_t field_number = decoder.FieldNumber();
+ [[maybe_unused]] volatile bool ok = status.ok();
+ }
+}
+
+} // namespace
+
+void BloatWithBase() {
+ CodeToSetUpSizeReportEnvironment();
+ Dependencies();
+}
+
+void BloatWithEncoder() {
+ BloatWithBase();
+ CodeToPullInProtoEncoder();
+}
+
+void BloatWithTableEncoder() {
+ BloatWithBase();
+ CodeToPullInTableEncoder();
+}
+
+void BloatWithTableDecoder() {
+ BloatWithBase();
+ CodeToPullInTableDecoder();
+}
+
+void BloatWithStreamDecoder() {
+ BloatWithBase();
+ CodeToPullInProtoStreamDecoder();
+}
+
+void BloatWithDecoder() {
+ BloatWithBase();
+ CodeToPullInProtoDecoder();
+}
+
+} // namespace pw::protobuf_size_report
diff --git a/pw_protobuf/size_report/proto_bloat.h b/pw_protobuf/size_report/proto_bloat.h
new file mode 100644
index 0000000..51654d2
--- /dev/null
+++ b/pw_protobuf/size_report/proto_bloat.h
@@ -0,0 +1,45 @@
+// Copyright 2022 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+// This namespace is NOT in pw::protobuf to allow filtering of symbols not
+// intended to be reflected in the size report.
+namespace pw::protobuf_size_report {
+
+// Includes ambient glue-related code that is required to set up size reports.
+// Include this in base size reports to prevent irrelevant symbols from showing
+// up in the final diffs.
+void BloatWithBase();
+
+// Adds pw_protobuf's StreamEncoder and MemoryEncoders to the size report.
+void BloatWithEncoder();
+
+// Adds pw_protobuf's StreamDecoder to the size report. This does not include
+// the memory-buffer-only Decoder class, as the implementation is very
+// different.
+void BloatWithStreamDecoder();
+
+// Adds pw_protobuf's Decoder to the size report. This does not include the
+// StreamDecoder class, as the implementation is very different.
+void BloatWithDecoder();
+
+// Adds pw_protobuf's table-based Message encoder to the size report in addition
+// to the StreamEncoder/MemoryEncoder.
+void BloatWithTableEncoder();
+
+// Adds pw_protobuf's table-based Message decoder to the size report in addition
+// to the StreamDecoder.
+void BloatWithTableDecoder();
+
+} // namespace pw::protobuf_size_report