blob: 8c06b45fac9fd358f546d54b7cb365c2d7aff977 [file] [log] [blame]
// 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"
#include "pw_protobuf/decoder.h"
#include "pw_protobuf/encoder.h"
#include "pw_protobuf/stream_decoder.h"
#include "pw_protobuf_test_protos/size_report.pwpb.h"
#include "pw_result/result.h"
#include "pw_status/status.h"
#ifndef _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
#define _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN 0
#endif // _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
#ifndef _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
#define _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT 0
#endif // _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
#ifndef _PW_PROTOBUF_SIZE_REPORT_MESSAGE
#define _PW_PROTOBUF_SIZE_REPORT_MESSAGE 0
#endif // _PW_PROTOBUF_SIZE_REPORT_MESSAGE
namespace pw::protobuf_size_report {
namespace {
template <typename T>
PW_NO_INLINE void ConsumeValue(T val) {
[[maybe_unused]] volatile T no_optimize = val;
}
#if _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
std::array<std::byte, ItemInfo::kMaxEncodedSizeBytes> encode_buffer;
pw::protobuf::MemoryEncoder encoder(encode_buffer);
PW_NO_INLINE void BasicEncode() {
pw::Status status;
volatile enum KeyType : uint32_t {
NONE = 0,
KEY_STRING = 1,
KEY_TOKEN = 2,
} which_key = KeyType::KEY_STRING;
volatile bool has_timestamp = true;
volatile bool has_has_value = false;
if (which_key == KeyType::KEY_STRING) {
encoder.WriteString(1, "test");
} else if (which_key == KeyType::KEY_TOKEN) {
encoder.WriteFixed32(2, 99999);
}
if (has_timestamp) {
encoder.WriteInt64(3, 1663003467);
}
if (has_has_value) {
encoder.WriteBool(4, true);
}
{
pw::protobuf::StreamEncoder submessage_encoder =
encoder.GetNestedEncoder(5);
status.Update(submessage_encoder.WriteInt64(1, 0x5001DBADFEEDBEE5));
status.Update(submessage_encoder.WriteInt32(2, 128));
status.Update(submessage_encoder.WriteInt32(3, 2));
}
ConsumeValue(status);
}
std::array<std::byte, ItemInfo::kMaxEncodedSizeBytes> decode_buffer;
pw::protobuf::Decoder decoder(decode_buffer);
PW_NO_INLINE void DecodeItemInfo(pw::ConstByteSpan data) {
pw::protobuf::Decoder submessage_decoder(data);
while (submessage_decoder.Next().ok()) {
switch (submessage_decoder.FieldNumber()) {
case static_cast<uint32_t>(ItemInfo::Fields::OFFSET): {
uint64_t value;
if (submessage_decoder.ReadUint64(&value).ok()) {
ConsumeValue(value);
}
break;
}
case static_cast<uint32_t>(ItemInfo::Fields::SIZE): {
uint32_t value;
if (submessage_decoder.ReadUint32(&value).ok()) {
ConsumeValue(value);
}
break;
}
case static_cast<uint32_t>(ItemInfo::Fields::ACCESS_LEVEL): {
uint32_t value;
if (submessage_decoder.ReadUint32(&value).ok()) {
ConsumeValue(value);
}
break;
}
}
}
}
PW_NO_INLINE void BasicDecode() {
volatile enum KeyType : uint32_t {
NONE = 0,
KEY_STRING = 1,
KEY_TOKEN = 2,
} which_key = KeyType::NONE;
volatile bool has_timestamp = false;
volatile bool has_has_value = false;
while (decoder.Next().ok()) {
switch (decoder.FieldNumber()) {
case static_cast<uint32_t>(ResponseInfo::Fields::KEY_STRING): {
which_key = KeyType::KEY_STRING;
std::string_view value;
if (decoder.ReadString(&value).ok()) {
ConsumeValue(value);
}
break;
}
case static_cast<uint32_t>(ResponseInfo::Fields::KEY_TOKEN): {
which_key = KeyType::KEY_TOKEN;
uint32_t value;
if (decoder.ReadUint32(&value).ok()) {
ConsumeValue(value);
}
break;
}
case static_cast<uint32_t>(ResponseInfo::Fields::TIMESTAMP): {
uint64_t value;
has_timestamp = true;
if (decoder.ReadUint64(&value).ok()) {
ConsumeValue(value);
}
break;
}
case static_cast<uint32_t>(ResponseInfo::Fields::HAS_VALUE): {
bool value;
has_has_value = true;
if (decoder.ReadBool(&value).ok()) {
ConsumeValue(value);
}
break;
}
case static_cast<uint32_t>(ResponseInfo::Fields::ITEM_INFO): {
pw::ConstByteSpan value;
if (decoder.ReadBytes(&value).ok()) {
DecodeItemInfo(value);
}
break;
}
}
}
ConsumeValue(which_key);
ConsumeValue(has_timestamp);
ConsumeValue(has_has_value);
}
#endif // _PW_PROTOBUF_SIZE_REPORT_NO_CODEGEN
#if _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> encode_buffer;
ResponseInfo::MemoryEncoder encoder(encode_buffer);
PW_NO_INLINE void BasicEncode() {
pw::Status status;
volatile enum KeyType : uint32_t {
NONE = 0,
KEY_STRING = 1,
KEY_TOKEN = 2,
} which_key = KeyType::KEY_STRING;
volatile bool has_timestamp = true;
volatile bool has_has_value = false;
if (which_key == KeyType::KEY_STRING) {
encoder.WriteKeyString("test");
} else if (which_key == KeyType::KEY_TOKEN) {
encoder.WriteKeyToken(99999);
}
if (has_timestamp) {
encoder.WriteTimestamp(1663003467);
}
if (has_has_value) {
encoder.WriteHasValue(true);
}
{
ItemInfo::StreamEncoder submessage_encoder = encoder.GetItemInfoEncoder();
status.Update(submessage_encoder.WriteOffset(0x5001DBADFEEDBEE5));
status.Update(submessage_encoder.WriteSize(128));
status.Update(submessage_encoder.WriteAccessLevel(ItemInfo::Access::WRITE));
}
ConsumeValue(status);
}
std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> decode_buffer;
pw::stream::MemoryReader reader(decode_buffer);
ResponseInfo::StreamDecoder decoder(reader);
PW_NO_INLINE void DecodeItemInfo(ItemInfo::StreamDecoder& submessage_decoder) {
while (submessage_decoder.Next().ok()) {
pw::Result<ItemInfo::Fields> field = submessage_decoder.Field();
if (!field.ok()) {
ConsumeValue(field.status());
return;
}
switch (field.value()) {
case ItemInfo::Fields::OFFSET: {
pw::Result<uint64_t> value = submessage_decoder.ReadOffset();
if (value.ok()) {
ConsumeValue(value);
}
break;
}
case ItemInfo::Fields::SIZE: {
pw::Result<uint32_t> value = submessage_decoder.ReadSize();
if (value.ok()) {
ConsumeValue(value);
}
break;
}
case ItemInfo::Fields::ACCESS_LEVEL: {
pw::Result<ItemInfo::Access> value =
submessage_decoder.ReadAccessLevel();
if (value.ok()) {
ConsumeValue(value);
}
break;
}
}
}
}
PW_NO_INLINE void BasicDecode() {
volatile enum KeyType : uint32_t {
NONE = 0,
KEY_STRING = 1,
KEY_TOKEN = 2,
} which_key = KeyType::NONE;
volatile bool has_timestamp = false;
volatile bool has_has_value = false;
while (decoder.Next().ok()) {
while (decoder.Next().ok()) {
pw::Result<ResponseInfo::Fields> field = decoder.Field();
if (!field.ok()) {
ConsumeValue(field.status());
return;
}
switch (field.value()) {
case ResponseInfo::Fields::KEY_STRING: {
which_key = KeyType::KEY_STRING;
std::array<char, 8> value;
pw::StatusWithSize status = decoder.ReadKeyString(value);
if (status.ok()) {
ConsumeValue(pw::span(value));
}
break;
}
case ResponseInfo::Fields::KEY_TOKEN: {
which_key = KeyType::KEY_TOKEN;
pw::Result<uint32_t> value = decoder.ReadKeyToken();
if (value.ok()) {
ConsumeValue(value);
}
break;
}
case ResponseInfo::Fields::TIMESTAMP: {
has_timestamp = true;
pw::Result<int64_t> value = decoder.ReadTimestamp();
if (value.ok()) {
ConsumeValue(value);
}
break;
}
case ResponseInfo::Fields::HAS_VALUE: {
has_has_value = true;
pw::Result<bool> value = decoder.ReadHasValue();
if (value.ok()) {
ConsumeValue(value);
}
break;
}
case ResponseInfo::Fields::ITEM_INFO: {
ItemInfo::StreamDecoder submessage_decoder =
decoder.GetItemInfoDecoder();
DecodeItemInfo(submessage_decoder);
break;
}
}
}
}
ConsumeValue(which_key);
ConsumeValue(has_timestamp);
ConsumeValue(has_has_value);
}
#endif // _PW_PROTOBUF_SIZE_REPORT_WIRE_FORMAT
#if _PW_PROTOBUF_SIZE_REPORT_MESSAGE
ResponseInfo::Message message;
std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> encode_buffer;
ResponseInfo::MemoryEncoder encoder(encode_buffer);
PW_NO_INLINE void BasicEncode() {
volatile enum KeyType : uint32_t {
NONE = 0,
KEY_STRING = 1,
KEY_TOKEN = 2,
} which_key = KeyType::KEY_STRING;
volatile bool has_timestamp = true;
volatile bool has_has_value = false;
if (which_key == KeyType::KEY_STRING) {
message.key_string.SetEncoder(
[](ResponseInfo::StreamEncoder& key_string_encoder) -> pw::Status {
key_string_encoder.WriteKeyString("test");
return pw::OkStatus();
});
} else if (which_key == KeyType::KEY_TOKEN) {
message.key_token = 99999;
}
message.timestamp =
has_timestamp ? std::optional<uint32_t>(1663003467) : std::nullopt;
message.has_value = has_has_value ? std::optional<bool>(false) : std::nullopt;
message.item_info.offset = 0x5001DBADFEEDBEE5;
message.item_info.size = 128;
message.item_info.access_level = ItemInfo::Access::WRITE;
ConsumeValue(encoder.Write(message));
}
std::array<std::byte, ResponseInfo::kMaxEncodedSizeBytes> decode_buffer;
pw::stream::MemoryReader reader(decode_buffer);
ResponseInfo::StreamDecoder decoder(reader);
PW_NO_INLINE void BasicDecode() {
volatile enum KeyType : uint32_t {
NONE = 0,
KEY_STRING = 1,
KEY_TOKEN = 2,
} which_key = KeyType::NONE;
volatile bool has_timestamp = false;
volatile bool has_has_value = false;
if (pw::Status status = decoder.Read(message); status.ok()) {
ConsumeValue(status);
has_timestamp = message.timestamp.has_value();
has_has_value = message.has_value.has_value();
}
ConsumeValue(which_key);
ConsumeValue(has_timestamp);
ConsumeValue(has_has_value);
}
#endif // _PW_PROTOBUF_SIZE_REPORT_MESSAGE
} // namespace
} // namespace pw::protobuf_size_report
int main() {
pw::bloat::BloatThisBinary();
pw::protobuf_size_report::BloatWithBase();
pw::protobuf_size_report::BloatWithEncoder();
pw::protobuf_size_report::BloatWithStreamDecoder();
pw::protobuf_size_report::BloatWithDecoder();
pw::protobuf_size_report::BloatWithTableEncoder();
pw::protobuf_size_report::BloatWithTableDecoder();
pw::protobuf_size_report::BasicEncode();
pw::protobuf_size_report::BasicDecode();
return 0;
}