diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index ae2cd2bae8d..9515b9c3b6f 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -2252,7 +2252,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer &buffer) const { buffer.write_raw_byte(8); buffer.encode_varint_raw_64(this->address); buffer.write_raw_byte(16); - buffer.encode_varint_raw(encode_zigzag32(this->rssi)); + buffer.encode_varint_raw_short(encode_zigzag32(this->rssi)); buffer.encode_uint32(3, this->address_type); buffer.write_raw_byte(34); buffer.encode_varint_raw(this->data_len); diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index b629018a919..efec7af7071 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -207,6 +207,22 @@ class ProtoWriteBuffer { } this->encode_varint_raw_slow_(value); } + /// Encode a varint that is expected to be 1-2 bytes (e.g. zigzag RSSI, small lengths). + /// Inlines both the 1-byte and 2-byte paths; falls back to slow path for 3+ bytes. + inline void ESPHOME_ALWAYS_INLINE encode_varint_raw_short(uint32_t value) { + if (value < 128) [[likely]] { + this->debug_check_bounds_(1); + *this->pos_++ = static_cast(value); + return; + } + if (value < 16384) [[likely]] { + this->debug_check_bounds_(2); + *this->pos_++ = static_cast(value | 0x80); + *this->pos_++ = static_cast(value >> 7); + return; + } + this->encode_varint_raw_slow_(value); + } void encode_varint_raw_64(uint64_t value) { while (value > 0x7F) { this->debug_check_bounds_(1); @@ -531,6 +547,17 @@ class ProtoSize { return varint_wide(value); return varint_slow(value); } + /// Size of a varint expected to be 1-2 bytes (e.g. zigzag RSSI, small lengths). + /// Inlines both checks; falls back to slow path for 3+ bytes. + static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint_short(uint32_t value) { + if (value < VARINT_THRESHOLD_1_BYTE) [[likely]] + return 1; + if (value < VARINT_THRESHOLD_2_BYTE) [[likely]] + return 2; + if (__builtin_is_constant_evaluated()) + return varint_wide(value); + return varint_slow(value); + } private: // Slow path for varint >= 128, outlined to keep fast path small @@ -645,10 +672,10 @@ class ProtoSize { return value ? field_id_size + 4 : 0; } static constexpr uint32_t calc_sint32(uint32_t field_id_size, int32_t value) { - return value ? field_id_size + varint(encode_zigzag32(value)) : 0; + return value ? field_id_size + varint_short(encode_zigzag32(value)) : 0; } static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE calc_sint32_force(uint32_t field_id_size, int32_t value) { - return field_id_size + varint(encode_zigzag32(value)); + return field_id_size + varint_short(encode_zigzag32(value)); } static constexpr uint32_t calc_int64(uint32_t field_id_size, int64_t value) { return value ? field_id_size + varint(value) : 0; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index f2a11141af0..811e7d12d75 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -229,7 +229,7 @@ class TypeInfo(ABC): RAW_ENCODE_MAP: dict[str, str] = { "encode_uint32": "buffer.encode_varint_raw({value});", "encode_uint64": "buffer.encode_varint_raw_64({value});", - "encode_sint32": "buffer.encode_varint_raw(encode_zigzag32({value}));", + "encode_sint32": "buffer.encode_varint_raw_short(encode_zigzag32({value}));", "encode_sint64": "buffer.encode_varint_raw_64(encode_zigzag64({value}));", "encode_int64": "buffer.encode_varint_raw_64(static_cast({value}));", "encode_bool": "buffer.write_raw_byte({value} ? 0x01 : 0x00);",