On BLE builds where proto_varint_value_t is uint64_t, decode_zigzag32()
takes uint32_t — make the narrowing explicit to match the static_cast
pattern used for other type conversions in generated code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cast msg_size/type_varint.value to uint32_t in HELPER_LOG to match PRIu32
format (proto_varint_value_t is uint64_t on BLE builds)
- Remove unused is_varint64 field from api_protobuf.py TypeInfo classes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-override #ifdef USE_API_VARINT64 conditionals with a
single type alias proto_varint_value_t, eliminating preprocessor
blocks from every decode_varint signature in api_pb2.cpp/h.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass uint32_t (or uint64_t when USE_API_VARINT64 is defined) directly
to decode_varint() instead of the ProtoVarIntResult struct. This
eliminates accessor method overhead in each of the 51 overrides,
replacing value.as_uint32() with direct value usage, value.as_bool()
with value != 0, etc. No vtable growth - single virtual method with
conditionally-typed parameter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace optional<ProtoVarInt> + consumed pointer with ProtoVarIntResult
struct that returns value + consumed count directly. This eliminates
memory stores through a pointer on the fast path (single-byte varints
< 128), keeping everything in registers.
The parse() method is now ESPHOME_ALWAYS_INLINE with the multi-byte
slow path outlined to parse_slow_(). The common case for protobuf
field tags, small enums, booleans, and typical message sizes/types
is a simple high-bit check + register return with no function call.
Measured on ESP32 (Xtensa): try_read_frame_ grows only +12 bytes
(320 → 332) for two inlined parse sites, while eliminating two
function calls per message on the hot path.
Ensure EnumType.encode_content passes force=true to the encode
function when the force field option is set, matching all other
TypeInfo subclasses for consistency and safety.
Fixed-width types (float, fixed32, sfixed32, fixed64, sfixed64)
now handle force=true by emitting a compile-time constant size
instead of the zero-checked calc_ call.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a `force` proto field option that generates `_force` variants of
calc_ and encode methods, skipping the zero/empty check. Applied to
BluetoothLERawAdvertisement fields that are almost always non-default
(address, rssi, data) to eliminate dead branches on the BLE proxy
hot path.
On-device benchmarks show calculate_size improved from 12,649 ns to
10,982 ns per 12-advertisement batch (-13.2%) with only +8 bytes flash.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace encode_message with encode_sub_message for protobuf submessage encoding.
For repeated submessage fields, encode_sub_message uses a backpatch approach:
writes field tag, reserves 1 byte for length varint, encodes the body, then
backpatches the actual length. For bodies >= 128 bytes, shifts the body forward
to make room for a multi-byte varint. This eliminates 2 of 3 calculate_size()
calls per repeated submessage element.
For singular submessage fields, encode_sub_message uses calculate_size() upfront
to skip empty submessages without writing to the buffer, preserving the debug
size check.
For the BLE advertisement proxy hot path (16 advertisements per batch), this
reduces calculate_size() calls from 48 to 16 per flush.
Add ESPHOME_DEBUG_ASSERT macro that only fires when ESPHOME_DEBUG is
defined. Use it to assert global_logger is not null in log functions.
Enable ESPHOME_DEBUG in C++ unit test builds so these assertions are
active during testing but have zero cost in production firmware.