diff --git a/.gitignore b/.gitignore index da1951e..8d97d07 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ code_coverage_report/** # Ignore the generated options file. generator/EmbeddedProto/embedded_proto_options_pb2.py +generator/EmbeddedProto.egg-info diff --git a/generator/EmbeddedProto/Field.py b/generator/EmbeddedProto/Field.py index 6aa96f3..9b2d11f 100644 --- a/generator/EmbeddedProto/Field.py +++ b/generator/EmbeddedProto/Field.py @@ -157,7 +157,7 @@ def render(self, filename, jinja_environment): class FieldBasic(Field): # A dictionary to convert the wire type into a default value. type_to_default_value = {FieldDescriptorProto.TYPE_DOUBLE: "0.0", - FieldDescriptorProto.TYPE_FLOAT: "0.0", + FieldDescriptorProto.TYPE_FLOAT: "0.0f", FieldDescriptorProto.TYPE_INT64: "0", FieldDescriptorProto.TYPE_UINT64: "0U", FieldDescriptorProto.TYPE_INT32: "0", @@ -379,11 +379,18 @@ def get_type_as_defined(self): return type_name + def get_max_enum_value(self): + # Return the maximum value used by any of the enum items as a string. This is used to calculate the maximum serialized size. + max_number = self.definition.descriptor.value[0].number + for value in self.definition.descriptor.value[1:]: + if max_number < value.number: + max_number = value.number + return str(max_number) def get_type(self): - return "EmbeddedProto::enumeration<" + self.get_type_as_defined() + ">" + return "EmbeddedProto::enumeration<" + self.get_type_as_defined() + ", EmbeddedProto::WireFormatter::VarintSize(" + self.get_max_enum_value() + ")>" def get_short_type(self): - return "EmbeddedProto::enumeration<" + self.get_type_as_defined().split("::")[-1] + ">" + return "EmbeddedProto::enumeration<" + self.get_type_as_defined().split("::")[-1] + ", EmbeddedProto::WireFormatter::VarintSize(" + self.get_max_enum_value() + ")>" def get_default_value(self): return "static_cast<" + self.get_type_as_defined() + ">(0)" diff --git a/generator/EmbeddedProto/templates/TypeDefMsg.h b/generator/EmbeddedProto/templates/TypeDefMsg.h index 52a6d6c..b37dc7b 100644 --- a/generator/EmbeddedProto/templates/TypeDefMsg.h +++ b/generator/EmbeddedProto/templates/TypeDefMsg.h @@ -274,6 +274,39 @@ class {{ typedef.get_name() }} final: public ::EmbeddedProto::MessageInterface #endif + //! Calculate the maximum number of bytes required to serialize this type of message. + /*! + This function does not take into account a possible id of this message object is self. + \return The number of bytes required at most to serialize this message type. + */ + static constexpr uint32_t max_serialized_size() + { + using namespace ::EmbeddedProto; + return + {% for field in typedef.fields %} + {{"+ " if not loop.first }}{{field.get_type()}}::max_serialized_size(static_cast(FieldNumber::{{field.variable_id_name}})) + {% endfor %} + {% for oneof in typedef.oneofs %} + {{"+ " if not loop.first or typedef.fields|length != 0}}max_serialized_size_{{oneof.get_name()}}() + {% endfor %} + {% if typedef.fields|length == 0 and typedef.oneofs|length == 0 %} + 0 + {% endif %} + ; + } + + //! Calculate the maximum number of bytes required to serialize this message including the field id number and tag. + /*! + \return The number of bytes required at most to serialize this message type. + */ + static constexpr uint32_t max_serialized_size(const uint32_t field_number) + { + using namespace ::EmbeddedProto; + return WireFormatter::VarintSize(WireFormatter::MakeTag(field_number, WireFormatter::WireType::LENGTH_DELIMITED)) // Size of the tag + + WireFormatter::VarintSize(max_serialized_size()) // Length delimted value + + max_serialized_size(); // Length of the serialized content + } + #ifdef MSG_TO_STRING ::EmbeddedProto::string_view to_string(::EmbeddedProto::string_view& str) const @@ -421,6 +454,7 @@ class {{ typedef.get_name() }} final: public ::EmbeddedProto::MessageInterface {{ TypeOneof.init(oneof)|indent(6) }} {{ TypeOneof.clear(oneof)|indent(6) }} {{ TypeOneof.deserialize(oneof, environment)|indent(6) }} + {{ TypeOneof.max_serialized_size(oneof)|indent(6) }} #ifdef MSG_TO_STRING {{ TypeOneof.to_string(oneof)|indent(6) }} #endif // End of MSG_TO_STRING diff --git a/generator/EmbeddedProto/templates/TypeOneof.h b/generator/EmbeddedProto/templates/TypeOneof.h index 34ef094..899c7bf 100644 --- a/generator/EmbeddedProto/templates/TypeOneof.h +++ b/generator/EmbeddedProto/templates/TypeOneof.h @@ -157,4 +157,27 @@ ::EmbeddedProto::string_view to_string_{{_oneof.get_name()}}(::EmbeddedProto::st return left_chars; } +{% endmacro %} +{# #} +{# ------------------------------------------------------------------------------------------------------------------ #} +{# #} +{% macro max_serialized_size(_oneof) %} +static constexpr uint32_t max_serialized_size_{{_oneof.get_name()}}() +{ + using namespace EmbeddedProto; + return + {% for field in _oneof.get_fields() %} + {% if not loop.last %} + {{ ' ' * (loop.index0 * 2) }}max({{field.get_type()}}::max_serialized_size(static_cast(FieldNumber::{{field.variable_id_name}})), + {% else %} + {{ ' ' * (2 + (loop.index0 * 2))}}{{field.get_type()}}::max_serialized_size(static_cast(FieldNumber::{{field.variable_id_name}})) + {% endif %} + {% endfor %} + {% if _oneof.get_fields() | length > 1 %} + {% for i in range(_oneof.get_fields() | length - 1) %} + {{ ' ' * (5 + (loop.revindex * 2)) }}) + {% endfor %} + {% endif %} + ; +} {% endmacro %} \ No newline at end of file diff --git a/src/Defines.h b/src/Defines.h index 6c86ed0..ec03d3a 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2024 Embedded AMS B.V. - All Rights Reserved + * Copyright (C) 2020-2025 Embedded AMS B.V. - All Rights Reserved * * This file is part of Embedded Proto. * @@ -16,7 +16,7 @@ * along with Embedded Proto. If not, see . * * For commercial and closed source application please visit: - * . + * . * * Embedded AMS B.V. * Info: @@ -83,6 +83,11 @@ namespace EmbeddedProto using string_view = array_view; using bytes_view = array_view; + //! Simple max function as constexpr + constexpr uint32_t max(const uint32_t a, const uint32_t b) + { + return (a > b) ? a : b; + } } #endif //_EMBEDDED_PROTO_DEFINES_H_ \ No newline at end of file diff --git a/src/FieldStringBytes.h b/src/FieldStringBytes.h index 605da20..f97ca9c 100644 --- a/src/FieldStringBytes.h +++ b/src/FieldStringBytes.h @@ -263,7 +263,32 @@ namespace EmbeddedProto void clear() override { data_.fill(0); - current_length_ = 0; + current_length_ = 0; + } + + //! When serialized with the all elements set, how much bytes are then required. + /*! + This function takes into account the field number and tag combination. + \param[in] field_number We need to include the field number. This because large field numbers require more bytes. + \return The number of bytes required at most. + */ + static constexpr uint32_t max_serialized_size(const uint32_t field_number) + { + return MAX_LENGTH // The number of bytes of the data. + + WireFormatter::VarintSize(MAX_LENGTH) // The varint indicating the actual number of bytes. + + WireFormatter::VarintSize(WireFormatter::MakeTag(field_number, + WireFormatter::WireType::LENGTH_DELIMITED)); // The field and tag comby + } + + //! When serialized with the all elements set, how much bytes are then required. + /*! + This function is used when the field bytes or string is serialized packed. Think in a repeated field. + \return The number of bytes required at most. + */ + static constexpr uint32_t max_serialized_size() + { + return MAX_LENGTH // The number of bytes of the data. + + WireFormatter::VarintSize(MAX_LENGTH); // The varint indicating the actual number of bytes. } protected: diff --git a/src/Fields.h b/src/Fields.h index 4e391f9..653489b 100644 --- a/src/Fields.h +++ b/src/Fields.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2024 Embedded AMS B.V. - All Rights Reserved + * Copyright (C) 2020-2025 Embedded AMS B.V. - All Rights Reserved * * This file is part of Embedded Proto. * @@ -16,7 +16,7 @@ * along with Embedded Proto. If not, see . * * For commercial and closed source application please visit: - * . + * . * * Embedded AMS B.V. * Info: @@ -119,12 +119,12 @@ namespace EmbeddedProto #endif // End of MSG_TO_STRING }; - template + template class FieldTemplate { public: using TYPE = VARIABLE_TYPE; - using CLASS_TYPE = FieldTemplate; + using CLASS_TYPE = FieldTemplate; FieldTemplate() = default; FieldTemplate(const VARIABLE_TYPE& v) : value_(v) { }; @@ -209,18 +209,18 @@ namespace EmbeddedProto bool operator>=(const VARIABLE_TYPE& rhs) { return value_ >= rhs; } bool operator<=(const VARIABLE_TYPE& rhs) { return value_ <= rhs; } - template - bool operator==(const FieldTemplate& rhs) { return value_ == rhs.get(); } - template - bool operator!=(const FieldTemplate& rhs) { return value_ != rhs.get(); } - template - bool operator>(const FieldTemplate& rhs) { return value_ > rhs.get(); } - template - bool operator<(const FieldTemplate& rhs) { return value_ < rhs.get(); } - template - bool operator>=(const FieldTemplate& rhs) { return value_ >= rhs.get(); } - template - bool operator<=(const FieldTemplate& rhs) { return value_ <= rhs.get(); } + template + bool operator==(const FieldTemplate& rhs) { return value_ == rhs.get(); } + template + bool operator!=(const FieldTemplate& rhs) { return value_ != rhs.get(); } + template + bool operator>(const FieldTemplate& rhs) { return value_ > rhs.get(); } + template + bool operator<(const FieldTemplate& rhs) { return value_ < rhs.get(); } + template + bool operator>=(const FieldTemplate& rhs) { return value_ >= rhs.get(); } + template + bool operator<=(const FieldTemplate& rhs) { return value_ <= rhs.get(); } void clear() { value_ = static_cast(0); } @@ -231,6 +231,22 @@ namespace EmbeddedProto return calcBuffer.get_size(); } + //! When serialized with the most unfavrouble value how much bytes does this field need. + /*! + This function takes into account the field number and tag combination. + \param[in] field_number We need to include the field number. This because large field numbers require more bytes. + \return The number of bytes required at most. + */ + static constexpr uint32_t max_serialized_size(const uint32_t field_number) + { + return MAX_SER_SIZE + WireFormatter::VarintSize(WireFormatter::MakeTag(field_number, WIRETYPE)); + } + + static constexpr uint32_t max_serialized_size() + { + return MAX_SER_SIZE; + } + #ifdef MSG_TO_STRING //! Write all the data in this field to a human readable string. @@ -438,22 +454,22 @@ namespace EmbeddedProto }; - using int32 = FieldTemplate; - using int64 = FieldTemplate; - using uint32 = FieldTemplate; - using uint64 = FieldTemplate; - using sint32 = FieldTemplate; - using sint64 = FieldTemplate; - using boolean = FieldTemplate; - using fixed32 = FieldTemplate; - using fixed64 = FieldTemplate; - using sfixed32 = FieldTemplate; - using sfixed64 = FieldTemplate; - using floatfixed = FieldTemplate; - using doublefixed = FieldTemplate; - - template - using enumeration = FieldTemplate; + using int32 = FieldTemplate; + using int64 = FieldTemplate; + using uint32 = FieldTemplate; + using uint64 = FieldTemplate; + using sint32 = FieldTemplate; + using sint64 = FieldTemplate; + using boolean = FieldTemplate; + using fixed32 = FieldTemplate; + using fixed64 = FieldTemplate; + using sfixed32 = FieldTemplate; + using sfixed64 = FieldTemplate; + using floatfixed = FieldTemplate; + using doublefixed = FieldTemplate; + + template + using enumeration = FieldTemplate; } // End of namespace EmbeddedProto. #endif diff --git a/src/ReadBufferFixedSize.h b/src/ReadBufferFixedSize.h index ed38e9e..12867f6 100644 --- a/src/ReadBufferFixedSize.h +++ b/src/ReadBufferFixedSize.h @@ -54,7 +54,7 @@ namespace EmbeddedProto //! \see ::EmbeddedProto::ReadBufferInterface::get_size() uint32_t get_size() const override { - return write_index_; + return write_index_ - read_index_; } //! \see ::EmbeddedProto::ReadBufferInterface::get_max_size() diff --git a/src/RepeatedField.h b/src/RepeatedField.h index d6ea279..bdd26e9 100644 --- a/src/RepeatedField.h +++ b/src/RepeatedField.h @@ -55,20 +55,20 @@ namespace EmbeddedProto struct is_specialization_of_FieldTemplate : std::false_type {}; //! Definition of a trait to check if DATA_TYPE is a specialization of the FieldTemplate. - template - struct is_specialization_of_FieldTemplate<::EmbeddedProto::FieldTemplate> : std::true_type {}; + template + struct is_specialization_of_FieldTemplate<::EmbeddedProto::FieldTemplate> : std::true_type {}; //! This class only supports Field and FieldTemplate classes as template parameter. static_assert(std::is_base_of<::EmbeddedProto::Field, DATA_TYPE>::value || is_specialization_of_FieldTemplate::value, "A Field can only be used as template paramter."); + public: + //! Check how this field shoeld be serialized, packed or not. static constexpr bool REPEATED_FIELD_IS_PACKED = !(std::is_base_of::value || std::is_base_of::value); - public: - RepeatedField() = default; ~RepeatedField() override = default; diff --git a/src/RepeatedFieldFixedSize.h b/src/RepeatedFieldFixedSize.h index 5a00e1c..67b33d7 100644 --- a/src/RepeatedFieldFixedSize.h +++ b/src/RepeatedFieldFixedSize.h @@ -193,6 +193,32 @@ namespace EmbeddedProto //! Return a reference to the internal data storage array. const std::array& get_data_const() const { return data_; } + //! When serialized with the most unfavrouble value how much bytes does this field need. + /*! + This function takes into account the field number and tag combination. + \param[in] field_number We need to include the field number. This because large field numbers require more bytes. + \return The number of bytes required at most. + */ + static constexpr uint32_t max_serialized_size(const uint32_t field_number) + { + return RepeatedField::REPEATED_FIELD_IS_PACKED + ? max_packed_serialized_size(field_number) + : max_unpacked_serialized_size(field_number); + } + + static constexpr uint32_t max_packed_serialized_size(const uint32_t field_number) + { + return WireFormatter::VarintSize(WireFormatter::MakeTag(field_number, + WireFormatter::WireType::LENGTH_DELIMITED)) + + WireFormatter::VarintSize(MAX_LENGTH) + + (MAX_LENGTH * DATA_TYPE::max_serialized_size()); + } + + static constexpr uint32_t max_unpacked_serialized_size(const uint32_t field_number) + { + return MAX_LENGTH * DATA_TYPE::max_serialized_size(field_number); + } + private: //! Number of item in the data array. diff --git a/src/WireFormatter.h b/src/WireFormatter.h index 6db0422..f1c33a2 100644 --- a/src/WireFormatter.h +++ b/src/WireFormatter.h @@ -81,6 +81,24 @@ namespace EmbeddedProto FIXED32 = 5, //!< fixed32, sfixed32, float }; + //! Calculate the number of bytes a varint value will take. + /*! + \param[in] value The value of which to calculate the size. + \return The number of bytes required for serializing the varint. + */ + static constexpr uint32_t VarintSize(const uint64_t value) + { + return (value < (1ULL << 7)) ? 1 : + (value < (1ULL << 14)) ? 2 : + (value < (1ULL << 21)) ? 3 : + (value < (1ULL << 28)) ? 4 : + (value < (1ULL << 35)) ? 5 : + (value < (1ULL << 42)) ? 6 : + (value < (1ULL << 49)) ? 7 : + (value < (1ULL << 56)) ? 8 : + (value < (1ULL << 63)) ? 9 : 10; + } + //! Encode a signed integer using the zig zag method /*! As specified the right-shift must be arithmetic, hence the cast is after the shift. The diff --git a/test/proto/oneof_fields.proto b/test/proto/oneof_fields.proto index 91a36e4..51664d2 100644 --- a/test/proto/oneof_fields.proto +++ b/test/proto/oneof_fields.proto @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2024 Embedded AMS B.V. - All Rights Reserved + * Copyright (C) 2020-2025 Embedded AMS B.V. - All Rights Reserved * * This file is part of Embedded Proto. * @@ -16,7 +16,7 @@ * along with Embedded Proto. If not, see . * * For commercial and closed source application please visit: - * . + * . * * Embedded AMS B.V. * Info: @@ -92,4 +92,19 @@ message string_bytes_oneof string name = 1; bytes data = 2; } -} \ No newline at end of file +} + +message combined_oneof +{ + oneof combi + { + message_oneof msg_oneof = 1; + string_bytes_oneof msg_sb_oneof = 2; + } +} + +message oneof_sigle { + oneof single_data { + int32 single_num = 1; + } +} diff --git a/test/test_max_field_size.cpp b/test/test_max_field_size.cpp new file mode 100644 index 0000000..4aa028a --- /dev/null +++ b/test/test_max_field_size.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2020-2025 Embedded AMS B.V. - All Rights Reserved + * + * This file is part of Embedded Proto. + * + * Embedded Proto is open source software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, version 3 of the license. + * + * Embedded Proto is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Embedded Proto. If not, see . + * + * For commercial and closed source application please visit: + * . + * + * Embedded AMS B.V. + * Info: + * info at EmbeddedProto dot com + * + * Postal address: + * Atoomweg 2 + * 1627 LE, Hoorn + * the Netherlands + */ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace test_max_field_size +{ + +TEST(MaxFieldSize, Wireformatter_VarintSize) +{ + EXPECT_EQ(1, EmbeddedProto::WireFormatter::VarintSize(0)); + EXPECT_EQ(1, EmbeddedProto::WireFormatter::VarintSize(1)); + EXPECT_EQ(1, EmbeddedProto::WireFormatter::VarintSize(127)); + EXPECT_EQ(2, EmbeddedProto::WireFormatter::VarintSize(128)); + EXPECT_EQ(2, EmbeddedProto::WireFormatter::VarintSize(16383)); + EXPECT_EQ(3, EmbeddedProto::WireFormatter::VarintSize(16384)); + EXPECT_EQ(3, EmbeddedProto::WireFormatter::VarintSize(2097151)); + EXPECT_EQ(4, EmbeddedProto::WireFormatter::VarintSize(2097152)); + EXPECT_EQ(4, EmbeddedProto::WireFormatter::VarintSize(268435455)); + EXPECT_EQ(5, EmbeddedProto::WireFormatter::VarintSize(268435456)); + EXPECT_EQ(5, EmbeddedProto::WireFormatter::VarintSize(34359738367)); + EXPECT_EQ(6, EmbeddedProto::WireFormatter::VarintSize(34359738368)); + EXPECT_EQ(6, EmbeddedProto::WireFormatter::VarintSize(4398046511103)); + EXPECT_EQ(7, EmbeddedProto::WireFormatter::VarintSize(4398046511104)); + EXPECT_EQ(7, EmbeddedProto::WireFormatter::VarintSize(562949953421311)); + EXPECT_EQ(8, EmbeddedProto::WireFormatter::VarintSize(562949953421312)); + EXPECT_EQ(8, EmbeddedProto::WireFormatter::VarintSize(72057594037927935)); + EXPECT_EQ(9, EmbeddedProto::WireFormatter::VarintSize(72057594037927936)); + EXPECT_EQ(9, EmbeddedProto::WireFormatter::VarintSize(9223372036854775807)); + + // Max values + EXPECT_EQ(10, EmbeddedProto::WireFormatter::VarintSize(9223372036854775808ULL)); + EXPECT_EQ(10, EmbeddedProto::WireFormatter::VarintSize(18446744073709551615ULL)); +} + +TEST(MaxFieldSize, Field_max_serialized_size) +{ + EXPECT_EQ(6, EmbeddedProto::int32::max_serialized_size(1)); + EXPECT_EQ(11, EmbeddedProto::int64::max_serialized_size(1)); + EXPECT_EQ(6, EmbeddedProto::uint32::max_serialized_size(1)); + EXPECT_EQ(11, EmbeddedProto::uint64::max_serialized_size(1)); + EXPECT_EQ(6, EmbeddedProto::sint32::max_serialized_size(1)); + EXPECT_EQ(11, EmbeddedProto::sint64::max_serialized_size(1)); + EXPECT_EQ(5, EmbeddedProto::fixed32::max_serialized_size(1)); + EXPECT_EQ(9, EmbeddedProto::fixed64::max_serialized_size(1)); + EXPECT_EQ(5, EmbeddedProto::sfixed32::max_serialized_size(1)); + EXPECT_EQ(9, EmbeddedProto::sfixed64::max_serialized_size(1)); + EXPECT_EQ(5, EmbeddedProto::floatfixed::max_serialized_size(1)); + EXPECT_EQ(9, EmbeddedProto::doublefixed::max_serialized_size(1)); + EXPECT_EQ(2, EmbeddedProto::boolean::max_serialized_size(1)); + + // Next with a large ID such that the tag becomes multiple bytes + EXPECT_EQ(7, EmbeddedProto::int32::max_serialized_size(16)); + EXPECT_EQ(12, EmbeddedProto::int64::max_serialized_size(16)); + EXPECT_EQ(7, EmbeddedProto::uint32::max_serialized_size(16)); + EXPECT_EQ(12, EmbeddedProto::uint64::max_serialized_size(16)); + EXPECT_EQ(7, EmbeddedProto::sint32::max_serialized_size(16)); + EXPECT_EQ(12, EmbeddedProto::sint64::max_serialized_size(16)); + EXPECT_EQ(6, EmbeddedProto::fixed32::max_serialized_size(16)); + EXPECT_EQ(10, EmbeddedProto::fixed64::max_serialized_size(16)); + EXPECT_EQ(6, EmbeddedProto::sfixed32::max_serialized_size(16)); + EXPECT_EQ(10, EmbeddedProto::sfixed64::max_serialized_size(16)); + EXPECT_EQ(6, EmbeddedProto::floatfixed::max_serialized_size(16)); + EXPECT_EQ(10, EmbeddedProto::doublefixed::max_serialized_size(16)); + EXPECT_EQ(3, EmbeddedProto::boolean::max_serialized_size(16)); + +} + +template +void helper_test(const BASE_TYPE max) +{ + EmbeddedProto::WriteBufferFixedSize<10> buffer; + //constexpr BASE_TYPE max = std::numeric_limits::digits == 64 ? static_cast(18446744073709551615) : static_cast(4294967295); + FIELD_TYPE field = max; // std::numeric_limits::max(); + field.serialize(buffer); + EXPECT_EQ(buffer.get_size(), FIELD_TYPE::max_serialized_size()); +} + +void helper_set_most_consuming_value(Test_Simple_Types& msg) +{ + msg.set_a_int32(std::numeric_limits::max()); + msg.set_a_int64(-9223372036854775807); + msg.set_a_uint32(std::numeric_limits::max()); + msg.set_a_uint64(std::numeric_limits::max()); + msg.set_a_sint32(std::numeric_limits::max()); + msg.set_a_sint64(std::numeric_limits::max()); + msg.set_a_bool(true); + msg.set_a_enum(Test_Enum::TWOBILLION); + msg.set_a_fixed64(std::numeric_limits::max()); + msg.set_a_sfixed64(std::numeric_limits::max()); + msg.set_a_double(std::numeric_limits::max()); + msg.set_a_fixed32(std::numeric_limits::max()); + msg.set_a_sfixed32(std::numeric_limits::max()); + msg.set_a_float(std::numeric_limits::max()); + + msg.set_a_nested_enum(Test_Simple_Types::Nested_Enum::NE_C); +} + +TEST(MaxFieldSize, SimpleTypesMsg_max_serialized_size) +{ + helper_test(2147483647); + helper_test(-9223372036854775807); + helper_test(4294967295); + helper_test(18446744073709551615ull); + helper_test(2147483647); + helper_test(9223372036854775807); + helper_test(4294967295); + helper_test(18446744073709551615ull); + helper_test(2147483647); + helper_test(9223372036854775807); + helper_test(std::numeric_limits::max()); + helper_test(std::numeric_limits::max()); + helper_test(true); + + EmbeddedProto::WriteBufferFixedSize<150> buffer; + Test_Simple_Types msg; + helper_set_most_consuming_value(msg); + + msg.serialize(buffer); + EXPECT_EQ((Test_Simple_Types::max_serialized_size()), buffer.get_size()); + +} + +TEST(MaxFieldSize, FieldStringBytes_max_serialized_size) +{ + // N byte + varint for the number of bytes + tag size. + EXPECT_EQ(1+1+1, EmbeddedProto::FieldBytes<1>::max_serialized_size(1)); + EXPECT_EQ(15+1+1, EmbeddedProto::FieldBytes<15>::max_serialized_size(1)); + EXPECT_EQ(127+1+1, EmbeddedProto::FieldBytes<127>::max_serialized_size(1)); + EXPECT_EQ(128+2+1, EmbeddedProto::FieldBytes<128>::max_serialized_size(1)); +} + +TEST(MaxFieldSize, RepeatedFieldFixedSize_Packed) +{ + constexpr uint32_t max_ser_size_A = EmbeddedProto::RepeatedFieldFixedSize::max_serialized_size(1); + constexpr uint32_t max_ser_size_B = EmbeddedProto::RepeatedFieldFixedSize::max_serialized_size(16); + constexpr uint32_t max_ser_size_C = EmbeddedProto::RepeatedFieldFixedSize::max_serialized_size(1); + // id + size + data + EXPECT_EQ(1 + 1 + (3*5), max_ser_size_A); + EXPECT_EQ(2 + 1 + (3*5), max_ser_size_B); + EXPECT_EQ(1 + 2 + (128*5), max_ser_size_C); +} + +TEST(MaxFieldSize, RepeatedFieldFixedSize_Unpacked) +{ + EmbeddedProto::RepeatedFieldFixedSize rffs; + helper_set_most_consuming_value(rffs[0]); + helper_set_most_consuming_value(rffs[1]); + helper_set_most_consuming_value(rffs[2]); + + EmbeddedProto::WriteBufferFixedSize<500> buffer; + + constexpr uint32_t max_ser_size_A = EmbeddedProto::RepeatedFieldFixedSize::max_serialized_size(1); + rffs.serialize_with_id(1, buffer, false); + EXPECT_EQ(buffer.get_size(), max_ser_size_A); + + buffer.clear(); + constexpr uint32_t max_ser_size_B = EmbeddedProto::RepeatedFieldFixedSize::max_serialized_size(16); + rffs.serialize_with_id(16, buffer, false); + EXPECT_EQ(buffer.get_size(), max_ser_size_B); +} + +TEST(MaxFieldSize, OneofMaxFieldSize) +{ + message_oneof msg; + msg.set_a(std::numeric_limits::max()); + msg.set_x(std::numeric_limits::max()); + msg.set_b(std::numeric_limits::max()); + msg.set_w(std::numeric_limits::max()); + msg.mutable_msg_ABC().set_varA(std::numeric_limits::max()); + msg.mutable_msg_ABC().set_varB(std::numeric_limits::max()); + msg.mutable_msg_ABC().set_varC(std::numeric_limits::max()); + + EmbeddedProto::WriteBufferFixedSize<200> buffer; + + msg.serialize(buffer); + EXPECT_EQ(buffer.get_size(), message_oneof::max_serialized_size()); + + buffer.clear(); + constexpr uint32_t N_CHARS = 25+1; + string_bytes_oneof msg_chars; + msg_chars.mutable_name().set("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + msg_chars.serialize(buffer); + EXPECT_EQ(buffer.get_size(), (string_bytes_oneof::max_serialized_size())); + + buffer.clear(); + constexpr uint32_t N_BYTES = 75; + string_bytes_oneof<1, N_BYTES> msg_bytes; + for(uint32_t i = 0; i < N_BYTES; ++i) { msg_bytes.mutable_data()[i] = 0xFF; } + msg_bytes.serialize(buffer); + EXPECT_EQ(buffer.get_size(), (string_bytes_oneof<1,N_BYTES>::max_serialized_size())); + + buffer.clear(); + combined_oneof<1,1> msg_combiA; + msg_combiA.mutable_msg_oneof() = msg; + msg_combiA.serialize(buffer); + EXPECT_EQ(buffer.get_size(), (combined_oneof<1,1>::max_serialized_size())); + + buffer.clear(); + combined_oneof<1, N_BYTES> msg_combiB; + msg_combiB.mutable_msg_sb_oneof() = msg_bytes; + msg_combiB.serialize(buffer); + EXPECT_EQ(buffer.get_size(), (combined_oneof<1,N_BYTES>::max_serialized_size())); +} + +} // End of namespace test_max_field_size