[api] Add max_data_length proto option and optimize entity name/object_id

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.
This commit is contained in:
J. Nick Koston
2026-04-03 13:33:51 -10:00
parent 9ece286a26
commit e174e579ed
4 changed files with 271 additions and 152 deletions
+15 -2
View File
@@ -161,6 +161,11 @@ class TypeInfo(ABC):
"""Get the max_value option for this field, or None if not set."""
return get_field_opt(self._field, pb.max_value, None)
@property
def max_data_length(self) -> int | None:
"""Get the max_data_length option for this field, or None if not set."""
return get_field_opt(self._field, pb.max_data_length, None)
@property
def wire_type(self) -> WireType:
"""Get the wire type for the field."""
@@ -1064,7 +1069,9 @@ class PointerToStringBufferType(PointerToBufferTypeBase):
@property
def encode_content(self) -> str:
if result := self._encode_bytes_with_precomputed_tag(
f"this->{self.field_name}.c_str()", f"this->{self.field_name}.size()"
f"this->{self.field_name}.c_str()",
f"this->{self.field_name}.size()",
max_len=self.max_data_length,
):
return result
if self.force:
@@ -1089,7 +1096,13 @@ class PointerToStringBufferType(PointerToBufferTypeBase):
return f'dump_field(out, ESPHOME_PSTR("{self.name}"), this->{self.field_name});'
def get_size_calculation(self, name: str, force: bool = False) -> str:
return f"size += ProtoSize::calc_length({self.calculate_field_id_size()}, this->{self.field_name}.size());"
size_field = f"this->{self.field_name}.size()"
max_len = self.max_data_length
if max_len is not None and max_len < 128:
return self._get_single_byte_varint_size(
size_field, force, extra_expr=size_field
)
return self._get_simple_size_calculation(size_field, force, "length")
def get_estimated_size(self) -> int:
return self.calculate_field_id_size() + 8 # field ID + 8 bytes typical string