Add a max_data_length field option to api_options.proto for string/bytes
fields. When max_data_length < 128 and force = true, the code generator
uses encode_short_string_force() — a single call that writes the tag
byte, 1-byte length varint, and raw string data with no branching. Size
calculation simplifies from calc_length(1, size) to 2 + size.
Annotate entity fields across all 25 ListEntities*Response messages:
- name and object_id: max_data_length = 120, force = true (50 fields)
- icon: max_data_length = 63 (25 fields)
The 120 and 63 values match NAME_MAX_LENGTH and ICON_MAX_LENGTH in
esphome/core/config.py, validated at config time.
Scan all enum definitions in api.proto at codegen time and automatically
populate max_value for enum-typed fields. This eliminates the need for
manual (max_value) annotations on every enum field.
When max_value < 128, the generated calculate_size uses constant-size
arithmetic instead of a function call:
- `calc_uint32(1, static_cast<uint32_t>(field))` → `field ? 2 : 0`
For repeated enum fields with constant element size, the per-element
loop is replaced with a multiply: `size += count * bytes_per_element`.
- Convert ProtoEncode::write_short_string to static method with pos param
- Fix codegen to emit ProtoEncode::write_short_string(pos, ...)
- Add PROTO_ENCODE_DEBUG_INIT to encode_fn call in encode_to_buffer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix double static_cast in enum encode precomputed tag path by
passing raw field ref instead of pre-cast value_expr.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace two separate write_raw_byte calls with a single
encode_small_varint(tag, value) call that writes both bytes
with one bounds check. Used for enum fields with max < 128.
When an enum field has max_value < 128 and a single-byte tag, emit
inline write_raw_byte calls instead of calling encode_uint32, which
avoids encode_field_raw and encode_varint_raw function call overhead.
When a repeated enum field has a constant size per element (max < 128),
emit size * constant instead of iterating. This fixes unused variable
warnings from clang-tidy and generates more efficient code.
The protobuf code generator already parses all enum definitions and
knows every enum's maximum value. Use this to automatically apply the
max_value < 128 optimization to all enum fields, eliminating the need
for manual annotation.
Since every enum in api.proto has max < 128, all 58 enum field size
calculations now use constant arithmetic instead of calling varint
size functions.
Builds on #15424 which introduced the max_value optimization.
Replace 3-call sequence (write_raw_byte + write_raw_byte + encode_raw)
with single inlined encode_raw_short_string call for forced string
fields with max_data_length < 128. The compiler can hoist the pos
pointer across all three writes in one function boundary.
Add max_data_length field option for string/bytes fields. When
max_data_length < 128, the codegen emits constant-size length varint
calculations and direct byte writes.
Annotate all entity name and object_id fields with
(max_data_length) = 120 and (force) = true across all 25
ListEntities*Response messages (50 fields).
Generated code changes:
- calculate_size: `calc_length(1, size)` -> `2 + size` (constant)
- encode: `encode_string(N, ref)` -> `write_raw_byte(tag) + write_raw_byte(len) + encode_raw(data, len)`
Eliminates 2 function calls per field per entity list response,
removes zero-check branches, and removes varint size computation.
Refactor the constant-size varint pattern into a reusable helper
method on the TypeInfo base class, used by both UInt32Type (max_value)
and FixedArrayBytesType (fixed_array_size < 128).
Add a max_value field option to api_options.proto that tells the code
generator the maximum value a field can have. When max_value < 128,
the generated calculate_size() uses constant arithmetic instead of
calling varint size functions, and encode() uses direct byte writes
instead of varint encoding.
Also optimize FixedArrayBytesType: when fixed_array_size < 128, the
length varint is always 1 byte, so calculate_size() uses constant
arithmetic and encode() uses write_raw_byte for the length.
Applied to BluetoothLERawAdvertisement.address_type (max_value=4).
Measured on ESP32 (upstairsdesk89proxy):
- BluetoothLERawAdvertisement::calculate_size: 88 → 71 bytes (-19%)
- BluetoothLERawAdvertisement::encode: 199 → 179 bytes (-10%)
- Total BLE proxy hot path: 1807 → 1770 bytes (-37 bytes)
Add encode_varint_raw_short() and ProtoSize::varint_short() that
inline both the 1-byte and 2-byte varint paths, falling back to
the noinline slow path for 3+ bytes.
Use these for sint32 fields (zigzag encoding), where values like
RSSI (-100 to 0) produce zigzag values that are 1-2 bytes. This
avoids a function call for the common case without bloating the
generic encode_varint_raw fast path.
Add CodSpeed benchmarks for BluetoothLERawAdvertisementsResponse
(12 advertisements) covering calculate_size, encode, calc+encode,
and fresh-buffer paths.
Includes a lightweight bluetooth_proxy stub header in
tests/benchmarks/stubs/ so the api component can compile with
USE_BLUETOOTH_PROXY on the host platform without pulling in
ESP32 BLE dependencies.