mirror of
https://github.com/esphome/esphome.git
synced 2026-05-20 17:52:00 +08:00
[api] Align ProtoSize API design with ProtoWriteBuffer pattern (#9920)
This commit is contained in:
@@ -276,8 +276,9 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint8_t mess
|
||||
#endif
|
||||
|
||||
// Calculate size
|
||||
uint32_t calculated_size = 0;
|
||||
msg.calculate_size(calculated_size);
|
||||
ProtoSize size_calc;
|
||||
msg.calculate_size(size_calc);
|
||||
uint32_t calculated_size = size_calc.get_size();
|
||||
|
||||
// Cache frame sizes to avoid repeated virtual calls
|
||||
const uint8_t header_padding = conn->helper_->frame_header_padding();
|
||||
|
||||
+553
-565
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+117
-176
@@ -333,13 +333,16 @@ class ProtoWriteBuffer {
|
||||
std::vector<uint8_t> *buffer_;
|
||||
};
|
||||
|
||||
// Forward declaration
|
||||
class ProtoSize;
|
||||
|
||||
class ProtoMessage {
|
||||
public:
|
||||
virtual ~ProtoMessage() = default;
|
||||
// Default implementation for messages with no fields
|
||||
virtual void encode(ProtoWriteBuffer buffer) const {}
|
||||
// Default implementation for messages with no fields
|
||||
virtual void calculate_size(uint32_t &total_size) const {}
|
||||
virtual void calculate_size(ProtoSize &size) const {}
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
std::string dump() const;
|
||||
virtual void dump_to(std::string &out) const = 0;
|
||||
@@ -360,24 +363,32 @@ class ProtoDecodableMessage : public ProtoMessage {
|
||||
};
|
||||
|
||||
class ProtoSize {
|
||||
private:
|
||||
uint32_t total_size_ = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief ProtoSize class for Protocol Buffer serialization size calculation
|
||||
*
|
||||
* This class provides static methods to calculate the exact byte counts needed
|
||||
* for encoding various Protocol Buffer field types. All methods are designed to be
|
||||
* efficient for the common case where many fields have default values.
|
||||
* This class provides methods to calculate the exact byte counts needed
|
||||
* for encoding various Protocol Buffer field types. The class now uses an
|
||||
* object-based approach to reduce parameter passing overhead while keeping
|
||||
* varint calculation methods static for external use.
|
||||
*
|
||||
* Implements Protocol Buffer encoding size calculation according to:
|
||||
* https://protobuf.dev/programming-guides/encoding/
|
||||
*
|
||||
* Key features:
|
||||
* - Object-based approach reduces flash usage by eliminating parameter passing
|
||||
* - Early-return optimization for zero/default values
|
||||
* - Direct total_size updates to avoid unnecessary additions
|
||||
* - Static varint methods for external callers
|
||||
* - Specialized handling for different field types according to protobuf spec
|
||||
* - Templated helpers for repeated fields and messages
|
||||
*/
|
||||
|
||||
ProtoSize() = default;
|
||||
|
||||
uint32_t get_size() const { return total_size_; }
|
||||
|
||||
/**
|
||||
* @brief Calculates the size in bytes needed to encode a uint32_t value as a varint
|
||||
*
|
||||
@@ -478,9 +489,7 @@ class ProtoSize {
|
||||
* @brief Common parameters for all add_*_field methods
|
||||
*
|
||||
* All add_*_field methods follow these common patterns:
|
||||
*
|
||||
* @param total_size Reference to the total message size to update
|
||||
* @param field_id_size Pre-calculated size of the field ID in bytes
|
||||
* * @param field_id_size Pre-calculated size of the field ID in bytes
|
||||
* @param value The value to calculate size for (type varies)
|
||||
* @param force Whether to calculate size even if the value is default/zero/empty
|
||||
*
|
||||
@@ -493,85 +502,63 @@ class ProtoSize {
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int32 field to the total message size
|
||||
*/
|
||||
static inline void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
if (value < 0) {
|
||||
// Negative values are encoded as 10-byte varints in protobuf
|
||||
total_size += field_id_size + 10;
|
||||
} else {
|
||||
// For non-negative values, use the standard varint size
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(value));
|
||||
inline void add_int32(uint32_t field_id_size, int32_t value) {
|
||||
if (value != 0) {
|
||||
add_int32_force(field_id_size, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int32 field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of an int32 field to the total message size (force version)
|
||||
*/
|
||||
static inline void add_int32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
if (value < 0) {
|
||||
// Negative values are encoded as 10-byte varints in protobuf
|
||||
total_size += field_id_size + 10;
|
||||
} else {
|
||||
// For non-negative values, use the standard varint size
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(value));
|
||||
}
|
||||
inline void add_int32_force(uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size when forced
|
||||
// Negative values are encoded as 10-byte varints in protobuf
|
||||
total_size_ += field_id_size + (value < 0 ? 10 : varint(static_cast<uint32_t>(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint32 field to the total message size
|
||||
*/
|
||||
static inline void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
inline void add_uint32(uint32_t field_id_size, uint32_t value) {
|
||||
if (value != 0) {
|
||||
add_uint32_force(field_id_size, value);
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint32 field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a uint32 field to the total message size (force version)
|
||||
*/
|
||||
static inline void add_uint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
total_size += field_id_size + varint(value);
|
||||
inline void add_uint32_force(uint32_t field_id_size, uint32_t value) {
|
||||
// Always calculate size when force is true
|
||||
total_size_ += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a boolean field to the total message size
|
||||
*/
|
||||
static inline void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value) {
|
||||
// Skip calculation if value is false
|
||||
if (!value) {
|
||||
return; // No need to update total_size
|
||||
inline void add_bool(uint32_t field_id_size, bool value) {
|
||||
if (value) {
|
||||
// Boolean fields always use 1 byte when true
|
||||
total_size_ += field_id_size + 1;
|
||||
}
|
||||
|
||||
// Boolean fields always use 1 byte when true
|
||||
total_size += field_id_size + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a boolean field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a boolean field to the total message size (force version)
|
||||
*/
|
||||
static inline void add_bool_field_repeated(uint32_t &total_size, uint32_t field_id_size, bool value) {
|
||||
// Always calculate size for repeated fields
|
||||
inline void add_bool_force(uint32_t field_id_size, bool value) {
|
||||
// Always calculate size when force is true
|
||||
// Boolean fields always use 1 byte
|
||||
total_size += field_id_size + 1;
|
||||
total_size_ += field_id_size + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a float field to the total message size
|
||||
*/
|
||||
static inline void add_float_field(uint32_t &total_size, uint32_t field_id_size, float value) {
|
||||
inline void add_float(uint32_t field_id_size, float value) {
|
||||
if (value != 0.0f) {
|
||||
total_size += field_id_size + 4;
|
||||
total_size_ += field_id_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,9 +568,9 @@ class ProtoSize {
|
||||
/**
|
||||
* @brief Calculates and adds the size of a fixed32 field to the total message size
|
||||
*/
|
||||
static inline void add_fixed32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
inline void add_fixed32(uint32_t field_id_size, uint32_t value) {
|
||||
if (value != 0) {
|
||||
total_size += field_id_size + 4;
|
||||
total_size_ += field_id_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,149 +580,104 @@ class ProtoSize {
|
||||
/**
|
||||
* @brief Calculates and adds the size of a sfixed32 field to the total message size
|
||||
*/
|
||||
static inline void add_sfixed32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
inline void add_sfixed32(uint32_t field_id_size, int32_t value) {
|
||||
if (value != 0) {
|
||||
total_size += field_id_size + 4;
|
||||
total_size_ += field_id_size + 4;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: add_sfixed64_field removed - wire type 1 (64-bit: sfixed64) not supported
|
||||
// to reduce overhead on embedded systems
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an enum field to the total message size
|
||||
*
|
||||
* Enum fields are encoded as uint32 varints.
|
||||
*/
|
||||
static inline void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
// Enums are encoded as uint32
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an enum field to the total message size (repeated field version)
|
||||
*
|
||||
* Enum fields are encoded as uint32 varints.
|
||||
*/
|
||||
static inline void add_enum_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
// Enums are encoded as uint32
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a sint32 field to the total message size
|
||||
*
|
||||
* Sint32 fields use ZigZag encoding, which is more efficient for negative values.
|
||||
*/
|
||||
static inline void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
inline void add_sint32(uint32_t field_id_size, int32_t value) {
|
||||
if (value != 0) {
|
||||
add_sint32_force(field_id_size, value);
|
||||
}
|
||||
|
||||
// ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
|
||||
uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
|
||||
total_size += field_id_size + varint(zigzag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a sint32 field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a sint32 field to the total message size (force version)
|
||||
*
|
||||
* Sint32 fields use ZigZag encoding, which is more efficient for negative values.
|
||||
*/
|
||||
static inline void add_sint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
inline void add_sint32_force(uint32_t field_id_size, int32_t value) {
|
||||
// Always calculate size when force is true
|
||||
// ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
|
||||
uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
|
||||
total_size += field_id_size + varint(zigzag);
|
||||
total_size_ += field_id_size + varint(zigzag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int64 field to the total message size
|
||||
*/
|
||||
static inline void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
inline void add_int64(uint32_t field_id_size, int64_t value) {
|
||||
if (value != 0) {
|
||||
add_int64_force(field_id_size, value);
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of an int64 field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of an int64 field to the total message size (force version)
|
||||
*/
|
||||
static inline void add_int64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
total_size += field_id_size + varint(value);
|
||||
inline void add_int64_force(uint32_t field_id_size, int64_t value) {
|
||||
// Always calculate size when force is true
|
||||
total_size_ += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint64 field to the total message size
|
||||
*/
|
||||
static inline void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value) {
|
||||
// Skip calculation if value is zero
|
||||
if (value == 0) {
|
||||
return; // No need to update total_size
|
||||
inline void add_uint64(uint32_t field_id_size, uint64_t value) {
|
||||
if (value != 0) {
|
||||
add_uint64_force(field_id_size, value);
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
total_size += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a uint64 field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a uint64 field to the total message size (force version)
|
||||
*/
|
||||
static inline void add_uint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint64_t value) {
|
||||
// Always calculate size for repeated fields
|
||||
total_size += field_id_size + varint(value);
|
||||
inline void add_uint64_force(uint32_t field_id_size, uint64_t value) {
|
||||
// Always calculate size when force is true
|
||||
total_size_ += field_id_size + varint(value);
|
||||
}
|
||||
|
||||
// NOTE: sint64 support functions (add_sint64_field, add_sint64_field_repeated) removed
|
||||
// NOTE: sint64 support functions (add_sint64_field, add_sint64_field_force) removed
|
||||
// sint64 type is not supported by ESPHome API to reduce overhead on embedded systems
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a string field using length
|
||||
* @brief Calculates and adds the size of a length-delimited field (string/bytes) to the total message size
|
||||
*/
|
||||
static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, size_t len) {
|
||||
// Skip calculation if string is empty
|
||||
if (len == 0) {
|
||||
return; // No need to update total_size
|
||||
inline void add_length(uint32_t field_id_size, size_t len) {
|
||||
if (len != 0) {
|
||||
add_length_force(field_id_size, len);
|
||||
}
|
||||
|
||||
// Field ID + length varint + string bytes
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a string/bytes field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a length-delimited field (string/bytes) to the total message size (repeated
|
||||
* field version)
|
||||
*/
|
||||
static inline void add_string_field_repeated(uint32_t &total_size, uint32_t field_id_size, const std::string &str) {
|
||||
// Always calculate size for repeated fields
|
||||
const uint32_t str_size = static_cast<uint32_t>(str.size());
|
||||
total_size += field_id_size + varint(str_size) + str_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a bytes field to the total message size
|
||||
*/
|
||||
static inline void add_bytes_field(uint32_t &total_size, uint32_t field_id_size, size_t len) {
|
||||
// Skip calculation if bytes is empty
|
||||
if (len == 0) {
|
||||
return; // No need to update total_size
|
||||
}
|
||||
|
||||
inline void add_length_force(uint32_t field_id_size, size_t len) {
|
||||
// Always calculate size when force is true
|
||||
// Field ID + length varint + data bytes
|
||||
total_size += field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len);
|
||||
total_size_ += field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a pre-calculated size directly to the total
|
||||
*
|
||||
* This is used when we can calculate the total size by multiplying the number
|
||||
* of elements by the bytes per element (for repeated fixed-size types like float, fixed32, etc.)
|
||||
*
|
||||
* @param size The pre-calculated total size to add
|
||||
*/
|
||||
inline void add_precalculated_size(uint32_t size) { total_size_ += size; }
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size
|
||||
*
|
||||
@@ -744,26 +686,21 @@ class ProtoSize {
|
||||
*
|
||||
* @param nested_size The pre-calculated size of the nested message
|
||||
*/
|
||||
static inline void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) {
|
||||
// Skip calculation if nested message is empty
|
||||
if (nested_size == 0) {
|
||||
return; // No need to update total_size
|
||||
inline void add_message_field(uint32_t field_id_size, uint32_t nested_size) {
|
||||
if (nested_size != 0) {
|
||||
add_message_field_force(field_id_size, nested_size);
|
||||
}
|
||||
|
||||
// Calculate and directly add to total_size
|
||||
// Field ID + length varint + nested message content
|
||||
total_size += field_id_size + varint(nested_size) + nested_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (force version)
|
||||
*
|
||||
* @param nested_size The pre-calculated size of the nested message
|
||||
*/
|
||||
static inline void add_message_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) {
|
||||
// Always calculate size for repeated fields
|
||||
inline void add_message_field_force(uint32_t field_id_size, uint32_t nested_size) {
|
||||
// Always calculate size when force is true
|
||||
// Field ID + length varint + nested message content
|
||||
total_size += field_id_size + varint(nested_size) + nested_size;
|
||||
total_size_ += field_id_size + varint(nested_size) + nested_size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -775,26 +712,29 @@ class ProtoSize {
|
||||
*
|
||||
* @param message The nested message object
|
||||
*/
|
||||
static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message) {
|
||||
uint32_t nested_size = 0;
|
||||
message.calculate_size(nested_size);
|
||||
inline void add_message_object(uint32_t field_id_size, const ProtoMessage &message) {
|
||||
// Calculate nested message size by creating a temporary ProtoSize
|
||||
ProtoSize nested_calc;
|
||||
message.calculate_size(nested_calc);
|
||||
uint32_t nested_size = nested_calc.get_size();
|
||||
|
||||
// Use the base implementation with the calculated nested_size
|
||||
add_message_field(total_size, field_id_size, nested_size);
|
||||
add_message_field(field_id_size, nested_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (repeated field version)
|
||||
* @brief Calculates and adds the size of a nested message field to the total message size (force version)
|
||||
*
|
||||
* @param message The nested message object
|
||||
*/
|
||||
static inline void add_message_object_repeated(uint32_t &total_size, uint32_t field_id_size,
|
||||
const ProtoMessage &message) {
|
||||
uint32_t nested_size = 0;
|
||||
message.calculate_size(nested_size);
|
||||
inline void add_message_object_force(uint32_t field_id_size, const ProtoMessage &message) {
|
||||
// Calculate nested message size by creating a temporary ProtoSize
|
||||
ProtoSize nested_calc;
|
||||
message.calculate_size(nested_calc);
|
||||
uint32_t nested_size = nested_calc.get_size();
|
||||
|
||||
// Use the base implementation with the calculated nested_size
|
||||
add_message_field_repeated(total_size, field_id_size, nested_size);
|
||||
add_message_field_force(field_id_size, nested_size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -807,16 +747,15 @@ class ProtoSize {
|
||||
* @param messages Vector of message objects
|
||||
*/
|
||||
template<typename MessageType>
|
||||
static inline void add_repeated_message(uint32_t &total_size, uint32_t field_id_size,
|
||||
const std::vector<MessageType> &messages) {
|
||||
inline void add_repeated_message(uint32_t field_id_size, const std::vector<MessageType> &messages) {
|
||||
// Skip if the vector is empty
|
||||
if (messages.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the repeated field version for all messages
|
||||
// Use the force version for all messages in the repeated field
|
||||
for (const auto &message : messages) {
|
||||
add_message_object_repeated(total_size, field_id_size, message);
|
||||
add_message_object_force(field_id_size, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -826,8 +765,9 @@ inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessa
|
||||
this->encode_field_raw(field_id, 2); // type 2: Length-delimited message
|
||||
|
||||
// Calculate the message size first
|
||||
uint32_t msg_length_bytes = 0;
|
||||
value.calculate_size(msg_length_bytes);
|
||||
ProtoSize msg_size;
|
||||
value.calculate_size(msg_size);
|
||||
uint32_t msg_length_bytes = msg_size.get_size();
|
||||
|
||||
// Calculate how many bytes the length varint needs
|
||||
uint32_t varint_length_bytes = ProtoSize::varint(msg_length_bytes);
|
||||
@@ -876,8 +816,9 @@ class ProtoService {
|
||||
|
||||
// Optimized method that pre-allocates buffer based on message size
|
||||
bool send_message_(const ProtoMessage &msg, uint8_t message_type) {
|
||||
uint32_t msg_size = 0;
|
||||
msg.calculate_size(msg_size);
|
||||
ProtoSize size;
|
||||
msg.calculate_size(size);
|
||||
uint32_t msg_size = size.get_size();
|
||||
|
||||
// Create a pre-sized buffer
|
||||
auto buffer = this->create_buffer(msg_size);
|
||||
|
||||
@@ -275,13 +275,13 @@ class TypeInfo(ABC):
|
||||
Args:
|
||||
name: Field name
|
||||
force: Whether this is for a repeated field
|
||||
base_method: Base method name (e.g., "add_int32_field")
|
||||
base_method: Base method name (e.g., "add_int32")
|
||||
value_expr: Optional value expression (defaults to name)
|
||||
"""
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
method = f"{base_method}_repeated" if force else base_method
|
||||
method = f"{base_method}_force" if force else base_method
|
||||
value = value_expr if value_expr else name
|
||||
return f"ProtoSize::{method}(total_size, {field_id_size}, {value});"
|
||||
return f"size.{method}({field_id_size}, {value});"
|
||||
|
||||
@abstractmethod
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
@@ -389,7 +389,7 @@ class DoubleType(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_double_field(total_size, {field_id_size}, {name});"
|
||||
return f"size.add_double({field_id_size}, {name});"
|
||||
|
||||
def get_fixed_size_bytes(self) -> int:
|
||||
return 8
|
||||
@@ -413,7 +413,7 @@ class FloatType(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_float_field(total_size, {field_id_size}, {name});"
|
||||
return f"size.add_float({field_id_size}, {name});"
|
||||
|
||||
def get_fixed_size_bytes(self) -> int:
|
||||
return 4
|
||||
@@ -436,7 +436,7 @@ class Int64Type(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_int64_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_int64")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
|
||||
@@ -456,7 +456,7 @@ class UInt64Type(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_uint64_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_uint64")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
|
||||
@@ -476,7 +476,7 @@ class Int32Type(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_int32_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_int32")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
|
||||
@@ -497,7 +497,7 @@ class Fixed64Type(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_fixed64_field(total_size, {field_id_size}, {name});"
|
||||
return f"size.add_fixed64({field_id_size}, {name});"
|
||||
|
||||
def get_fixed_size_bytes(self) -> int:
|
||||
return 8
|
||||
@@ -521,7 +521,7 @@ class Fixed32Type(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_fixed32_field(total_size, {field_id_size}, {name});"
|
||||
return f"size.add_fixed32({field_id_size}, {name});"
|
||||
|
||||
def get_fixed_size_bytes(self) -> int:
|
||||
return 4
|
||||
@@ -543,7 +543,7 @@ class BoolType(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_bool_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_bool")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 1 # field ID + 1 byte
|
||||
@@ -657,19 +657,21 @@ class StringType(TypeInfo):
|
||||
# For no_zero_copy, we need to use .size() on the string
|
||||
if no_zero_copy and name != "it":
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_string_field(total_size, {field_id_size}, this->{self.field_name}.size());"
|
||||
return self._get_simple_size_calculation(name, force, "add_string_field")
|
||||
return (
|
||||
f"size.add_length({field_id_size}, this->{self.field_name}.size());"
|
||||
)
|
||||
return self._get_simple_size_calculation(name, force, "add_length")
|
||||
|
||||
# Check if this is being called from a repeated field context
|
||||
# In that case, 'name' will be 'it' and we need to use the repeated version
|
||||
if name == "it":
|
||||
# For repeated fields, we need to use add_string_field_repeated which includes field ID
|
||||
# For repeated fields, we need to use add_length_force which includes field ID
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_string_field_repeated(total_size, {field_id_size}, it);"
|
||||
return f"size.add_length_force({field_id_size}, it.size());"
|
||||
|
||||
# For messages that need encoding, use the StringRef size
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_string_field(total_size, {field_id_size}, this->{self.field_name}_ref_.size());"
|
||||
return f"size.add_length({field_id_size}, this->{self.field_name}_ref_.size());"
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string
|
||||
@@ -804,7 +806,7 @@ class BytesType(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return f"ProtoSize::add_bytes_field(total_size, {self.calculate_field_id_size()}, this->{self.field_name}_len_);"
|
||||
return f"size.add_length({self.calculate_field_id_size()}, this->{self.field_name}_len_);"
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical bytes
|
||||
@@ -879,15 +881,11 @@ class FixedArrayBytesType(TypeInfo):
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
|
||||
if force:
|
||||
# For repeated fields, always calculate size
|
||||
return f"total_size += {field_id_size} + ProtoSize::varint(static_cast<uint32_t>({length_field})) + {length_field};"
|
||||
# For repeated fields, always calculate size (no zero check)
|
||||
return f"size.add_length_force({field_id_size}, {length_field});"
|
||||
else:
|
||||
# For non-repeated fields, skip if length is 0 (matching encode_string behavior)
|
||||
return (
|
||||
f"if ({length_field} != 0) {{\n"
|
||||
f" total_size += {field_id_size} + ProtoSize::varint(static_cast<uint32_t>({length_field})) + {length_field};\n"
|
||||
f"}}"
|
||||
)
|
||||
# For non-repeated fields, add_length already checks for zero
|
||||
return f"size.add_length({field_id_size}, {length_field});"
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
# Estimate based on typical BLE advertisement size
|
||||
@@ -914,7 +912,7 @@ class UInt32Type(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_uint32_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_uint32")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
|
||||
@@ -951,7 +949,7 @@ class EnumType(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(
|
||||
name, force, "add_enum_field", f"static_cast<uint32_t>({name})"
|
||||
name, force, "add_uint32", f"static_cast<uint32_t>({name})"
|
||||
)
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
@@ -973,7 +971,7 @@ class SFixed32Type(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_sfixed32_field(total_size, {field_id_size}, {name});"
|
||||
return f"size.add_sfixed32({field_id_size}, {name});"
|
||||
|
||||
def get_fixed_size_bytes(self) -> int:
|
||||
return 4
|
||||
@@ -997,7 +995,7 @@ class SFixed64Type(TypeInfo):
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
field_id_size = self.calculate_field_id_size()
|
||||
return f"ProtoSize::add_sfixed64_field(total_size, {field_id_size}, {name});"
|
||||
return f"size.add_sfixed64({field_id_size}, {name});"
|
||||
|
||||
def get_fixed_size_bytes(self) -> int:
|
||||
return 8
|
||||
@@ -1020,7 +1018,7 @@ class SInt32Type(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_sint32_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_sint32")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
|
||||
@@ -1040,7 +1038,7 @@ class SInt64Type(TypeInfo):
|
||||
return o
|
||||
|
||||
def get_size_calculation(self, name: str, force: bool = False) -> str:
|
||||
return self._get_simple_size_calculation(name, force, "add_sint64_field")
|
||||
return self._get_simple_size_calculation(name, force, "add_sint64")
|
||||
|
||||
def get_estimated_size(self) -> int:
|
||||
return self.calculate_field_id_size() + 3 # field ID + 3 bytes typical varint
|
||||
@@ -1274,7 +1272,7 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
if isinstance(self._ti, MessageType):
|
||||
# For repeated messages, use the dedicated helper that handles iteration internally
|
||||
field_id_size = self._ti.calculate_field_id_size()
|
||||
o = f"ProtoSize::add_repeated_message(total_size, {field_id_size}, {name});"
|
||||
o = f"size.add_repeated_message({field_id_size}, {name});"
|
||||
return o
|
||||
|
||||
# For other repeated types, use the underlying type's size calculation with force=True
|
||||
@@ -1287,7 +1285,9 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
field_id_size = self._ti.calculate_field_id_size()
|
||||
# Pre-calculate the total bytes per element
|
||||
bytes_per_element = field_id_size + num_bytes
|
||||
o += f" total_size += {name}.size() * {bytes_per_element};\n"
|
||||
o += (
|
||||
f" size.add_precalculated_size({name}.size() * {bytes_per_element});\n"
|
||||
)
|
||||
else:
|
||||
# Other types need the actual value
|
||||
o += f" for (const auto {'' if self._ti_is_bool else '&'}it : {name}) {{\n"
|
||||
@@ -1719,11 +1719,11 @@ def build_message_type(
|
||||
if needs_encode and encode:
|
||||
o = f"void {desc.name}::encode(ProtoWriteBuffer buffer) const {{"
|
||||
if len(encode) == 1 and len(encode[0]) + len(o) + 3 < 120:
|
||||
o += f" {encode[0]} "
|
||||
o += f" {encode[0]} }}\n"
|
||||
else:
|
||||
o += "\n"
|
||||
o += indent("\n".join(encode)) + "\n"
|
||||
o += "}\n"
|
||||
o += "}\n"
|
||||
cpp += o
|
||||
prot = "void encode(ProtoWriteBuffer buffer) const override;"
|
||||
public_content.append(prot)
|
||||
@@ -1731,17 +1731,17 @@ def build_message_type(
|
||||
|
||||
# Add calculate_size method only if this message needs encoding and has fields
|
||||
if needs_encode and size_calc:
|
||||
o = f"void {desc.name}::calculate_size(uint32_t &total_size) const {{"
|
||||
o = f"void {desc.name}::calculate_size(ProtoSize &size) const {{"
|
||||
# For a single field, just inline it for simplicity
|
||||
if len(size_calc) == 1 and len(size_calc[0]) + len(o) + 3 < 120:
|
||||
o += f" {size_calc[0]} "
|
||||
o += f" {size_calc[0]} }}\n"
|
||||
else:
|
||||
# For multiple fields
|
||||
o += "\n"
|
||||
o += indent("\n".join(size_calc)) + "\n"
|
||||
o += "}\n"
|
||||
o += "}\n"
|
||||
cpp += o
|
||||
prot = "void calculate_size(uint32_t &total_size) const override;"
|
||||
prot = "void calculate_size(ProtoSize &size) const override;"
|
||||
public_content.append(prot)
|
||||
# If no fields to calculate size for or message doesn't need encoding, the default implementation in ProtoMessage will be used
|
||||
|
||||
|
||||
Reference in New Issue
Block a user