diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index d3831440c5..94bf71e00d 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -344,17 +344,19 @@ void APIConnection::on_disconnect_response() { } uint16_t APIConnection::fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, - uint32_t calculated_size, MessageEncodeFn encode_fn, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { msg.key = entity->get_object_id_hash(); #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - return encode_to_buffer_(calculated_size, encode_fn, &msg, conn, remaining_size); + ProtoSize proto_size; + size_fn(&msg, proto_size); + return encode_to_buffer_(proto_size.get_size(), encode_fn, &msg, conn, remaining_size); } uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, - uint32_t calculated_size, MessageEncodeFn encode_fn, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { msg.key = entity->get_object_id_hash(); @@ -380,15 +382,17 @@ uint16_t APIConnection::fill_and_encode_entity_info_(EntityBase *entity, InfoRes #ifdef USE_DEVICES msg.device_id = entity->get_device_id(); #endif - return encode_to_buffer_(calculated_size, encode_fn, &msg, conn, remaining_size); + ProtoSize proto_size; + size_fn(&msg, proto_size); + return encode_to_buffer_(proto_size.get_size(), encode_fn, &msg, conn, remaining_size); } uint16_t APIConnection::fill_and_encode_entity_info_with_device_class_( - EntityBase *entity, InfoResponseProtoMessage &msg, StringRef &device_class_field, uint32_t calculated_size, + EntityBase *entity, InfoResponseProtoMessage &msg, StringRef &device_class_field, CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size) { char dc_buf[MAX_DEVICE_CLASS_LENGTH]; device_class_field = StringRef(entity->get_device_class_to(dc_buf)); - return fill_and_encode_entity_info_(entity, msg, calculated_size, encode_fn, conn, remaining_size); + return fill_and_encode_entity_info_(entity, msg, size_fn, encode_fn, conn, remaining_size); } #ifdef USE_BINARY_SENSOR diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index cc5388f999..c7421f3458 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -260,6 +260,8 @@ class APIConnection final : public APIServerConnectionBase { // Function pointer type for type-erased message encoding using MessageEncodeFn = void (*)(const void *, ProtoWriteBuffer &); + // Function pointer type for type-erased size calculation + using CalculateSizeFn = void (*)(const void *, ProtoSize &); template bool send_message(const T &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP @@ -331,6 +333,11 @@ class APIConnection final : public APIServerConnectionBase { static_cast(msg)->encode(buffer); } + // Size thunk — converts void* back to concrete type for direct calculate_size() call + template static void calc_size_(const void *msg, ProtoSize &size) { + static_cast(msg)->calculate_size(size); + } + // Shared no-op encode thunk for empty messages (ESTIMATED_SIZE == 0) static void encode_msg_noop_(const void *, ProtoWriteBuffer &) {} @@ -359,40 +366,40 @@ class APIConnection final : public APIServerConnectionBase { // Non-template core — fills state fields and encodes static uint16_t fill_and_encode_entity_state_(EntityBase *entity, StateResponseProtoMessage &msg, - uint32_t calculated_size, MessageEncodeFn encode_fn, - APIConnection *conn, uint32_t remaining_size); + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, + uint32_t remaining_size); // Thin template wrapper template static uint16_t fill_and_encode_entity_state(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - return fill_and_encode_entity_state_(entity, msg, calculated_size_of(msg), &encode_msg_, conn, remaining_size); + return fill_and_encode_entity_state_(entity, msg, &calc_size_, &encode_msg_, conn, remaining_size); } // Non-template core — fills info fields, allocates buffers, and encodes static uint16_t fill_and_encode_entity_info_(EntityBase *entity, InfoResponseProtoMessage &msg, - uint32_t calculated_size, MessageEncodeFn encode_fn, APIConnection *conn, + CalculateSizeFn size_fn, MessageEncodeFn encode_fn, APIConnection *conn, uint32_t remaining_size); // Thin template wrapper template static uint16_t fill_and_encode_entity_info(EntityBase *entity, T &msg, APIConnection *conn, uint32_t remaining_size) { - return fill_and_encode_entity_info_(entity, msg, calculated_size_of(msg), &encode_msg_, conn, remaining_size); + return fill_and_encode_entity_info_(entity, msg, &calc_size_, &encode_msg_, conn, remaining_size); } // Non-template core — fills device_class, then delegates to fill_and_encode_entity_info_ static uint16_t fill_and_encode_entity_info_with_device_class_(EntityBase *entity, InfoResponseProtoMessage &msg, - StringRef &device_class_field, - uint32_t calculated_size, MessageEncodeFn encode_fn, - APIConnection *conn, uint32_t remaining_size); + StringRef &device_class_field, CalculateSizeFn size_fn, + MessageEncodeFn encode_fn, APIConnection *conn, + uint32_t remaining_size); // Thin template wrapper template static uint16_t fill_and_encode_entity_info_with_device_class(EntityBase *entity, T &msg, StringRef &device_class_field, APIConnection *conn, uint32_t remaining_size) { - return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, calculated_size_of(msg), + return fill_and_encode_entity_info_with_device_class_(entity, msg, device_class_field, &calc_size_, &encode_msg_, conn, remaining_size); }