mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
[api] Collapse the three protobuf decode virtuals into one
Every decodable message overrode up to three virtuals, one per wire type, so each carried a five slot vtable and up to three functions with their own prologue and return tails. The shared decode loop now parses the payload for the wire type into a ProtoFieldValue and calls a single decode_field() virtual with the tag, the field number and the wire type; the generated override is one switch. The switch key is chosen per target through PROTO_DECODE_KEY. Embedded builds compile switches to compare chains (ESP-IDF passes -fno-jump-tables), so they key on the full wire tag, one compare per field with no separate wire type check. The host compiler builds a jump table for the dense field number switch, so there the key is the field number and PROTO_DECODE_GUARD rejects a mismatched wire type. Both forms drop a field that arrives with a wire type it does not declare, exactly as the per wire type virtuals did. Per decodable message the vtable shrinks from 20 to 12 bytes on xtensa and the extra decode functions fold into one; the shared loop shrinks as well. Host instruction counts per decoded field are unchanged apart from the guard compare, which replaces the prologue of the separate function it used to call.
This commit is contained in:
+1000
-1081
File diff suppressed because it is too large
Load Diff
@@ -424,8 +424,7 @@ class HelloRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class HelloResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -469,7 +468,7 @@ class DisconnectRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class DisconnectResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -845,8 +844,7 @@ class CoverCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
@@ -920,9 +918,7 @@ class FanCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
@@ -1018,9 +1014,7 @@ class LightCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
@@ -1125,8 +1119,7 @@ class SwitchCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
@@ -1186,7 +1179,7 @@ class SubscribeLogsRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class SubscribeLogsResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -1229,7 +1222,7 @@ class NoiseEncryptionSetKeyRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class NoiseEncryptionSetKeyResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -1323,8 +1316,7 @@ class HomeassistantActionResponse final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_API_HOMEASSISTANT_STATES
|
||||
@@ -1365,7 +1357,7 @@ class HomeAssistantStateResponse final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
class GetTimeRequest final : public ProtoMessage {
|
||||
@@ -1394,7 +1386,7 @@ class DSTRule final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class ParsedTimezone final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -1407,8 +1399,7 @@ class ParsedTimezone final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class GetTimeResponse final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -1425,8 +1416,7 @@ class GetTimeResponse final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#ifdef USE_API_USER_DEFINED_ACTIONS
|
||||
class ListEntitiesServicesArgument final : public ProtoMessage {
|
||||
@@ -1494,9 +1484,7 @@ class ExecuteServiceArgument final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class ExecuteServiceRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -1519,9 +1507,7 @@ class ExecuteServiceRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
@@ -1612,7 +1598,7 @@ class CameraImageRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_CLIMATE
|
||||
@@ -1718,9 +1704,7 @@ class ClimateCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_WATER_HEATER
|
||||
@@ -1792,8 +1776,7 @@ class WaterHeaterCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_NUMBER
|
||||
@@ -1856,8 +1839,7 @@ class NumberCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
@@ -1915,9 +1897,7 @@ class SelectCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_SIREN
|
||||
@@ -1983,9 +1963,7 @@ class SirenCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_LOCK
|
||||
@@ -2047,9 +2025,7 @@ class LockCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_BUTTON
|
||||
@@ -2085,8 +2061,7 @@ class ButtonCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_MEDIA_PLAYER
|
||||
@@ -2172,9 +2147,7 @@ class MediaPlayerCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_BLUETOOTH_PROXY
|
||||
@@ -2191,7 +2164,7 @@ class SubscribeBluetoothLEAdvertisementsRequest final : public ProtoDecodableMes
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothLERawAdvertisement final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2245,7 +2218,7 @@ class BluetoothDeviceRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothDeviceConnectionResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2283,7 +2256,7 @@ class BluetoothGATTGetServicesRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothGATTDescriptor final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2394,7 +2367,7 @@ class BluetoothGATTReadRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothGATTReadResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2440,8 +2413,7 @@ class BluetoothGATTWriteRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothGATTReadDescriptorRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2457,7 +2429,7 @@ class BluetoothGATTReadDescriptorRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2475,8 +2447,7 @@ class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothGATTNotifyRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2493,7 +2464,7 @@ class BluetoothGATTNotifyRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothGATTNotifyDataResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2711,7 +2682,7 @@ class BluetoothScannerSetModeRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_VOICE_ASSISTANT
|
||||
@@ -2729,7 +2700,7 @@ class SubscribeVoiceAssistantRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantAudioSettings final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2786,7 +2757,7 @@ class VoiceAssistantResponse final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantEventData final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2797,7 +2768,7 @@ class VoiceAssistantEventData final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantEventResponse final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2813,8 +2784,7 @@ class VoiceAssistantEventResponse final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantAudio final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2839,8 +2809,7 @@ class VoiceAssistantAudio final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantTimerEventResponse final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2860,8 +2829,7 @@ class VoiceAssistantTimerEventResponse final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantAnnounceRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2879,8 +2847,7 @@ class VoiceAssistantAnnounceRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantAnnounceFinished final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2933,8 +2900,7 @@ class VoiceAssistantExternalWakeWord final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantConfigurationRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -2949,7 +2915,7 @@ class VoiceAssistantConfigurationRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class VoiceAssistantConfigurationResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -2986,7 +2952,7 @@ class VoiceAssistantSetConfiguration final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_ALARM_CONTROL_PANEL
|
||||
@@ -3046,9 +3012,7 @@ class AlarmControlPanelCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_TEXT
|
||||
@@ -3109,9 +3073,7 @@ class TextCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATE
|
||||
@@ -3172,8 +3134,7 @@ class DateCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_DATETIME_TIME
|
||||
@@ -3234,8 +3195,7 @@ class TimeCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_EVENT
|
||||
@@ -3341,8 +3301,7 @@ class ValveCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_DATETIME_DATETIME
|
||||
@@ -3399,8 +3358,7 @@ class DateTimeCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_UPDATE
|
||||
@@ -3465,8 +3423,7 @@ class UpdateCommandRequest final : public CommandProtoMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
#endif
|
||||
#ifdef USE_ZWAVE_PROXY
|
||||
@@ -3490,7 +3447,7 @@ class ZWaveProxyFrame final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class ZWaveProxyRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -3513,8 +3470,7 @@ class ZWaveProxyRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class ZWaveProxyRequestResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -3584,9 +3540,7 @@ class InfraredRFTransmitRawTimingsRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class InfraredRFReceiveEvent final : public ProtoMessage {
|
||||
public:
|
||||
@@ -3657,7 +3611,7 @@ class SerialProxyConfigureRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class SerialProxyDataReceived final : public ProtoMessage {
|
||||
public:
|
||||
@@ -3700,8 +3654,7 @@ class SerialProxyWriteRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class SerialProxySetModemPinsRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -3717,7 +3670,7 @@ class SerialProxySetModemPinsRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class SerialProxyGetModemPinsRequest final : public ProtoDecodableMessage {
|
||||
public:
|
||||
@@ -3732,7 +3685,7 @@ class SerialProxyGetModemPinsRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class SerialProxyGetModemPinsResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -3770,7 +3723,7 @@ class SerialProxyRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class SerialProxyRequestResponse final : public ProtoMessage {
|
||||
public:
|
||||
@@ -3814,7 +3767,7 @@ class BluetoothSetConnectionParamsRequest final : public ProtoDecodableMessage {
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;
|
||||
bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;
|
||||
};
|
||||
class BluetoothSetConnectionParamsResponse final : public ProtoMessage {
|
||||
public:
|
||||
|
||||
@@ -226,6 +226,7 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
|
||||
uint32_t field_type = tag & WIRE_TYPE_MASK;
|
||||
uint32_t field_id = tag >> 3;
|
||||
ptr += res.consumed;
|
||||
ProtoFieldValue value;
|
||||
|
||||
switch (field_type) {
|
||||
case WIRE_TYPE_VARINT: { // VarInt
|
||||
@@ -234,10 +235,7 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
|
||||
ESP_LOGV(TAG, "Invalid VarInt at offset %ld", (long) (ptr - buffer));
|
||||
return;
|
||||
}
|
||||
if (!this->decode_varint(field_id, res.value)) {
|
||||
ESP_LOGV(TAG, "Cannot decode VarInt field %" PRIu32 " with value %" PRIu64 "!", field_id,
|
||||
static_cast<uint64_t>(res.value));
|
||||
}
|
||||
value.varint_ = res.value;
|
||||
ptr += res.consumed;
|
||||
break;
|
||||
}
|
||||
@@ -253,9 +251,8 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
|
||||
ESP_LOGV(TAG, "Out-of-bounds Length Delimited at offset %ld", (long) (ptr - buffer));
|
||||
return;
|
||||
}
|
||||
if (!this->decode_length(field_id, ProtoLengthDelimited(ptr, field_length))) {
|
||||
ESP_LOGV(TAG, "Cannot decode Length Delimited field %" PRIu32 "!", field_id);
|
||||
}
|
||||
value.ld_.data = ptr;
|
||||
value.ld_.len = field_length;
|
||||
ptr += field_length;
|
||||
break;
|
||||
}
|
||||
@@ -264,16 +261,12 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
|
||||
ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at offset %ld", (long) (ptr - buffer));
|
||||
return;
|
||||
}
|
||||
uint32_t val;
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
// Protobuf fixed32 is little-endian — direct load on LE platforms
|
||||
memcpy(&val, ptr, 4);
|
||||
memcpy(&value.fixed32_, ptr, 4);
|
||||
#else
|
||||
val = encode_uint32(ptr[3], ptr[2], ptr[1], ptr[0]);
|
||||
value.fixed32_ = encode_uint32(ptr[3], ptr[2], ptr[1], ptr[0]);
|
||||
#endif
|
||||
if (!this->decode_32bit(field_id, Proto32Bit(val))) {
|
||||
ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32 " with value %" PRIu32 "!", field_id, val);
|
||||
}
|
||||
ptr += 4;
|
||||
break;
|
||||
}
|
||||
@@ -281,6 +274,9 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
|
||||
ESP_LOGV(TAG, "Invalid field type %" PRIu32 " at offset %ld", field_type, (long) (ptr - buffer));
|
||||
return;
|
||||
}
|
||||
if (!this->decode_field(tag, field_id, field_type, value)) {
|
||||
ESP_LOGV(TAG, "Cannot decode field %" PRIu32 " with wire type %" PRIu32 "!", field_id, field_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,40 +170,59 @@ class ProtoVarInt {
|
||||
class ProtoMessage;
|
||||
class ProtoSize;
|
||||
|
||||
class ProtoLengthDelimited {
|
||||
public:
|
||||
explicit ProtoLengthDelimited(const uint8_t *value, size_t length) : value_(value), length_(length) {}
|
||||
std::string as_string() const { return std::string(reinterpret_cast<const char *>(this->value_), this->length_); }
|
||||
// Generated decode_field() bodies switch on PROTO_DECODE_KEY and label each case with
|
||||
// PROTO_DECODE_CASE. Embedded targets compile switches to compare chains (ESP-IDF passes
|
||||
// -fno-jump-tables), so keying on the full wire tag costs one compare per field and needs no
|
||||
// separate wire type check. The host compiler turns the dense field number switch into a jump
|
||||
// table, so there the key is the field number and PROTO_DECODE_GUARD rejects the wrong wire type
|
||||
// before the field is read. Both forms drop a field that arrives with a wire type it does not
|
||||
// declare, which is what the per wire type virtuals did before.
|
||||
#ifdef USE_HOST
|
||||
#define PROTO_DECODE_KEY(tag, field_id) (field_id)
|
||||
#define PROTO_DECODE_CASE(field_id, wire_type) (field_id)
|
||||
#define PROTO_DECODE_GUARD(wire_type, expected) \
|
||||
if ((wire_type) != (expected)) \
|
||||
return false
|
||||
#else
|
||||
#define PROTO_DECODE_KEY(tag, field_id) (tag)
|
||||
#define PROTO_DECODE_CASE(field_id, wire_type) (((field_id) << 3) | (wire_type))
|
||||
#define PROTO_DECODE_GUARD(wire_type, expected) (void) 0
|
||||
#endif
|
||||
|
||||
// Direct access to raw data without string allocation
|
||||
const uint8_t *data() const { return this->value_; }
|
||||
size_t size() const { return this->length_; }
|
||||
/// Payload of one decoded field, handed to ProtoDecodableMessage::decode_field() together with
|
||||
/// the field number and wire type. The wire type says which member is live; the accessors do not check.
|
||||
/// Eight bytes with or without USE_API_VARINT64, so it travels in two registers on every target.
|
||||
struct ProtoFieldValue {
|
||||
union {
|
||||
proto_varint_value_t varint_;
|
||||
struct {
|
||||
const uint8_t *data;
|
||||
uint32_t len;
|
||||
} ld_;
|
||||
uint32_t fixed32_;
|
||||
};
|
||||
|
||||
/// Decode the length-delimited data into a message instance.
|
||||
proto_varint_value_t as_varint() const { return this->varint_; }
|
||||
|
||||
// Length-delimited accessors
|
||||
const uint8_t *data() const { return this->ld_.data; }
|
||||
size_t size() const { return this->ld_.len; }
|
||||
std::string as_string() const { return std::string(reinterpret_cast<const char *>(this->ld_.data), this->ld_.len); }
|
||||
/// Decode the length-delimited payload into a message instance.
|
||||
/// Template preserves concrete type so decode() resolves statically.
|
||||
template<typename T> void decode_to_message(T &msg) const;
|
||||
template<typename T> void decode_to_message(T &msg) const { msg.decode(this->ld_.data, this->ld_.len); }
|
||||
|
||||
protected:
|
||||
const uint8_t *const value_;
|
||||
const size_t length_;
|
||||
};
|
||||
|
||||
class Proto32Bit {
|
||||
public:
|
||||
explicit Proto32Bit(uint32_t value) : value_(value) {}
|
||||
uint32_t as_fixed32() const { return this->value_; }
|
||||
int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); }
|
||||
// Fixed32 accessors
|
||||
uint32_t as_fixed32() const { return this->fixed32_; }
|
||||
int32_t as_sfixed32() const { return static_cast<int32_t>(this->fixed32_); }
|
||||
float as_float() const {
|
||||
union {
|
||||
uint32_t raw;
|
||||
float value;
|
||||
} s{};
|
||||
s.raw = this->value_;
|
||||
s.raw = this->fixed32_;
|
||||
return s.value;
|
||||
}
|
||||
|
||||
protected:
|
||||
const uint32_t value_;
|
||||
};
|
||||
|
||||
// NOTE: Proto64Bit class removed - wire type 1 (64-bit fixed) not supported
|
||||
@@ -728,10 +747,16 @@ class ProtoDecodableMessage : public ProtoMessage {
|
||||
|
||||
protected:
|
||||
~ProtoDecodableMessage() = default;
|
||||
virtual bool decode_varint(uint32_t field_id, proto_varint_value_t value) { return false; }
|
||||
virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value) { return false; }
|
||||
virtual bool decode_32bit(uint32_t field_id, Proto32Bit value) { return false; }
|
||||
// NOTE: decode_64bit removed - wire type 1 not supported
|
||||
/// Store one decoded field. \p field_id and \p wire_type are \p tag split in two; the loop has all
|
||||
/// three at hand, so passing them costs nothing and the generated switch keys on whichever form is
|
||||
/// cheapest for the target (see PROTO_DECODE_KEY). \p wire_type selects the live ProtoFieldValue
|
||||
/// member; overrides reject a field that arrived with a wire type other than the one it declares.
|
||||
/// Return false for unknown or mismatched fields.
|
||||
/// One virtual instead of one per wire type keeps each message's vtable at a single slot.
|
||||
// NOTE: wire type 1 (64-bit fixed) is not supported
|
||||
virtual bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class ProtoSize {
|
||||
@@ -951,11 +976,6 @@ template<typename T> inline void ProtoWriteBuffer::encode_optional_sub_message(u
|
||||
this->encode_optional_sub_message(field_id, T::calc_size_msg(&value), &value, &T::encode_msg);
|
||||
}
|
||||
|
||||
// Template decode_to_message - preserves concrete type so decode() resolves statically
|
||||
template<typename T> void ProtoLengthDelimited::decode_to_message(T &msg) const {
|
||||
msg.decode(this->value_, this->length_);
|
||||
}
|
||||
|
||||
template<typename T> const char *proto_enum_to_string(T value);
|
||||
|
||||
// ProtoService removed — its methods were inlined into APIConnection.
|
||||
|
||||
@@ -229,12 +229,27 @@ class TypeInfo(ABC):
|
||||
def class_member(self) -> str:
|
||||
return f"{self.cpp_type} {self.field_name}{{{self.default_value}}};"
|
||||
|
||||
# decode_field() cases are keyed through the PROTO_DECODE_* macros in proto.h: embedded
|
||||
# targets switch on the full wire tag, the host switches on the field number and guards
|
||||
# the wire type. Either way a field that arrives with the wrong wire type falls through
|
||||
# to "return false" instead of being read from the wrong ProtoFieldValue member.
|
||||
def decode_case(self, wire_type: WireType, body: str) -> str:
|
||||
"""Emit one decode_field() case for a field and the wire type it expects."""
|
||||
return (
|
||||
f"case PROTO_DECODE_CASE({self.number}, {int(wire_type)}):\n"
|
||||
f" PROTO_DECODE_GUARD(wire_type, {int(wire_type)});\n"
|
||||
f" {body}\n"
|
||||
f" break;"
|
||||
)
|
||||
|
||||
@property
|
||||
def decode_varint_content(self) -> str:
|
||||
content = self.decode_varint
|
||||
if content is None:
|
||||
return None
|
||||
return f"case {self.number}: this->{self.field_name} = {content}; break;"
|
||||
return self.decode_case(
|
||||
WireType.VARINT, f"this->{self.field_name} = {content};"
|
||||
)
|
||||
|
||||
decode_varint = None
|
||||
|
||||
@@ -243,7 +258,9 @@ class TypeInfo(ABC):
|
||||
content = self.decode_length
|
||||
if content is None:
|
||||
return None
|
||||
return f"case {self.number}: this->{self.field_name} = {content}; break;"
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED, f"this->{self.field_name} = {content};"
|
||||
)
|
||||
|
||||
decode_length = None
|
||||
|
||||
@@ -252,19 +269,12 @@ class TypeInfo(ABC):
|
||||
content = self.decode_32bit
|
||||
if content is None:
|
||||
return None
|
||||
return f"case {self.number}: this->{self.field_name} = {content}; break;"
|
||||
return self.decode_case(
|
||||
WireType.FIXED32, f"this->{self.field_name} = {content};"
|
||||
)
|
||||
|
||||
decode_32bit = None
|
||||
|
||||
@property
|
||||
def decode_64bit_content(self) -> str:
|
||||
content = self.decode_64bit
|
||||
if content is None:
|
||||
return None
|
||||
return f"case {self.number}: this->{self.field_name} = {content}; break;"
|
||||
|
||||
decode_64bit = None
|
||||
|
||||
# Mapping from encode_func to raw encode expression template.
|
||||
# When a forced field has a single-byte tag, the code generator emits
|
||||
# write_raw_byte(tag) + raw encode instead of the full encode_* method,
|
||||
@@ -638,7 +648,6 @@ class DoubleType(FixedSizeTypeMixin, TypeInfo):
|
||||
# Unsupported but defined for completeness
|
||||
cpp_type = "double"
|
||||
default_value = "0.0"
|
||||
decode_64bit = "value.as_double()"
|
||||
encode_func = "encode_double"
|
||||
wire_type = WireType.FIXED64 # Uses wire type 1 according to protobuf spec
|
||||
|
||||
@@ -693,7 +702,7 @@ class Int64Type(VarintTypeMixin, TypeInfo):
|
||||
cpp_type = "int64_t"
|
||||
_varint_max_bits = 64
|
||||
default_value = "0"
|
||||
decode_varint = "static_cast<int64_t>(value)"
|
||||
decode_varint = "static_cast<int64_t>(value.as_varint())"
|
||||
encode_func = "encode_int64"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -714,7 +723,7 @@ class UInt64Type(VarintTypeMixin, TypeInfo):
|
||||
cpp_type = "uint64_t"
|
||||
_varint_max_bits = 64
|
||||
default_value = "0"
|
||||
decode_varint = "value"
|
||||
decode_varint = "value.as_varint()"
|
||||
encode_func = "encode_uint64"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -749,7 +758,7 @@ class Int32Type(VarintTypeMixin, TypeInfo):
|
||||
cpp_type = "int32_t"
|
||||
_varint_max_bits = 64 # int32 is sign-extended to 64 bits in protobuf
|
||||
default_value = "0"
|
||||
decode_varint = "static_cast<int32_t>(value)"
|
||||
decode_varint = "static_cast<int32_t>(value.as_varint())"
|
||||
encode_func = "encode_int32"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -769,7 +778,6 @@ class Int32Type(VarintTypeMixin, TypeInfo):
|
||||
class Fixed64Type(FixedSizeTypeMixin, TypeInfo):
|
||||
cpp_type = "uint64_t"
|
||||
default_value = "0"
|
||||
decode_64bit = "value.as_fixed64()"
|
||||
encode_func = "encode_fixed64"
|
||||
wire_type = WireType.FIXED64 # Uses wire type 1
|
||||
|
||||
@@ -824,7 +832,7 @@ class BoolType(VarintTypeMixin, TypeInfo):
|
||||
_varint_max_bits = 1
|
||||
cpp_type = "bool"
|
||||
default_value = "false"
|
||||
decode_varint = "value != 0"
|
||||
decode_varint = "value.as_varint() != 0"
|
||||
encode_func = "encode_bool"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -1014,13 +1022,15 @@ class MessageType(TypeInfo):
|
||||
# decode_to_message() cannot report failure, so setting the flag
|
||||
# afterwards only documents intent; a status-returning decode could
|
||||
# gate it for real without touching callers.
|
||||
return (
|
||||
f"case {self.number}:\n"
|
||||
f" value.decode_to_message(this->{self.field_name});\n"
|
||||
f" this->has_{self.name} = true;\n"
|
||||
f" break;"
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED,
|
||||
f"value.decode_to_message(this->{self.field_name});\n"
|
||||
f" this->has_{self.name} = true;",
|
||||
)
|
||||
return f"case {self.number}: value.decode_to_message(this->{self.field_name}); break;"
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED,
|
||||
f"value.decode_to_message(this->{self.field_name});",
|
||||
)
|
||||
|
||||
def dump(self, name: str) -> str:
|
||||
return f"{name}.dump_to(out);"
|
||||
@@ -1216,11 +1226,11 @@ class PointerToBytesBufferType(PointerToBufferTypeBase):
|
||||
|
||||
@property
|
||||
def decode_length_content(self) -> str | None:
|
||||
return f"""case {self.number}: {{
|
||||
this->{self.field_name} = value.data();
|
||||
this->{self.field_name}_len = value.size();
|
||||
break;
|
||||
}}"""
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED,
|
||||
f"this->{self.field_name} = value.data();\n"
|
||||
f" this->{self.field_name}_len = value.size();",
|
||||
)
|
||||
|
||||
def dump(self, name: str) -> str:
|
||||
return (
|
||||
@@ -1281,10 +1291,10 @@ class PointerToStringBufferType(PointerToBufferTypeBase):
|
||||
|
||||
@property
|
||||
def decode_length_content(self) -> str | None:
|
||||
return f"""case {self.number}: {{
|
||||
this->{self.field_name} = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
|
||||
break;
|
||||
}}"""
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED,
|
||||
f"this->{self.field_name} = StringRef(reinterpret_cast<const char *>(value.data()), value.size());",
|
||||
)
|
||||
|
||||
def dump(self, name: str) -> str:
|
||||
# Not used since we use dump_field, but required by abstract base class
|
||||
@@ -1355,12 +1365,12 @@ class PackedBufferTypeInfo(TypeInfo):
|
||||
@property
|
||||
def decode_length_content(self) -> str:
|
||||
"""Store pointer to buffer and calculate count of packed varints."""
|
||||
return f"""case {self.number}: {{
|
||||
this->{self.field_name}_data_ = value.data();
|
||||
this->{self.field_name}_length_ = value.size();
|
||||
this->{self.field_name}_count_ = count_packed_varints(value.data(), value.size());
|
||||
break;
|
||||
}}"""
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED,
|
||||
f"this->{self.field_name}_data_ = value.data();\n"
|
||||
f" this->{self.field_name}_length_ = value.size();\n"
|
||||
f" this->{self.field_name}_count_ = count_packed_varints(value.data(), value.size());",
|
||||
)
|
||||
|
||||
@property
|
||||
def encode_content(self) -> str:
|
||||
@@ -1446,16 +1456,13 @@ class FixedArrayBytesType(TypeInfo):
|
||||
|
||||
@property
|
||||
def decode_length_content(self) -> str:
|
||||
o = f"case {self.number}: {{\n"
|
||||
o += " const std::string &data_str = value.as_string();\n"
|
||||
o += f" this->{self.field_name}_len = data_str.size();\n"
|
||||
o += f" if (this->{self.field_name}_len > {self.array_size}) {{\n"
|
||||
o += f" this->{self.field_name}_len = {self.array_size};\n"
|
||||
o += " }\n"
|
||||
o += f" memcpy(this->{self.field_name}, data_str.data(), this->{self.field_name}_len);\n"
|
||||
o += " break;\n"
|
||||
o += "}"
|
||||
return o
|
||||
body = "const std::string &data_str = value.as_string();\n"
|
||||
body += f" this->{self.field_name}_len = data_str.size();\n"
|
||||
body += f" if (this->{self.field_name}_len > {self.array_size}) {{\n"
|
||||
body += f" this->{self.field_name}_len = {self.array_size};\n"
|
||||
body += " }\n"
|
||||
body += f" memcpy(this->{self.field_name}, data_str.data(), this->{self.field_name}_len);"
|
||||
return self.decode_case(WireType.LENGTH_DELIMITED, body)
|
||||
|
||||
@property
|
||||
def encode_content(self) -> str:
|
||||
@@ -1518,7 +1525,7 @@ class UInt32Type(VarintTypeMixin, TypeInfo):
|
||||
cpp_type = "uint32_t"
|
||||
_varint_max_bits = 32
|
||||
default_value = "0"
|
||||
decode_varint = "value"
|
||||
decode_varint = "value.as_varint()"
|
||||
encode_func = "encode_uint32"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -1547,7 +1554,7 @@ class EnumType(VarintTypeMixin, TypeInfo):
|
||||
|
||||
@property
|
||||
def decode_varint(self) -> str:
|
||||
return f"static_cast<{self.cpp_type}>(value)"
|
||||
return f"static_cast<{self.cpp_type}>(value.as_varint())"
|
||||
|
||||
default_value = ""
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
@@ -1620,7 +1627,6 @@ class SFixed32Type(FixedSizeTypeMixin, TypeInfo):
|
||||
class SFixed64Type(FixedSizeTypeMixin, TypeInfo):
|
||||
cpp_type = "int64_t"
|
||||
default_value = "0"
|
||||
decode_64bit = "value.as_sfixed64()"
|
||||
encode_func = "encode_sfixed64"
|
||||
wire_type = WireType.FIXED64 # Uses wire type 1
|
||||
|
||||
@@ -1647,7 +1653,7 @@ class SInt32Type(VarintTypeMixin, TypeInfo):
|
||||
cpp_type = "int32_t"
|
||||
_varint_max_bits = 32 # zigzag encoding keeps it 32-bit
|
||||
default_value = "0"
|
||||
decode_varint = "decode_zigzag32(static_cast<uint32_t>(value))"
|
||||
decode_varint = "decode_zigzag32(static_cast<uint32_t>(value.as_varint()))"
|
||||
encode_func = "encode_sint32"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -1668,7 +1674,7 @@ class SInt64Type(VarintTypeMixin, TypeInfo):
|
||||
cpp_type = "int64_t"
|
||||
_varint_max_bits = 64
|
||||
default_value = "0"
|
||||
decode_varint = "decode_zigzag64(value)"
|
||||
decode_varint = "decode_zigzag64(value.as_varint())"
|
||||
encode_func = "encode_sint64"
|
||||
wire_type = WireType.VARINT # Uses wire type 0
|
||||
|
||||
@@ -2138,8 +2144,8 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
content = self._ti.decode_varint
|
||||
if content is None:
|
||||
return None
|
||||
return (
|
||||
f"case {self.number}: this->{self.field_name}.push_back({content}); break;"
|
||||
return self.decode_case(
|
||||
WireType.VARINT, f"this->{self.field_name}.push_back({content});"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -2150,11 +2156,15 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
content = self._ti.decode_length
|
||||
if content is None and isinstance(self._ti, MessageType):
|
||||
# Special handling for non-template message decoding
|
||||
return f"case {self.number}: this->{self.field_name}.emplace_back(); value.decode_to_message(this->{self.field_name}.back()); break;"
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED,
|
||||
f"this->{self.field_name}.emplace_back();\n"
|
||||
f" value.decode_to_message(this->{self.field_name}.back());",
|
||||
)
|
||||
if content is None:
|
||||
return None
|
||||
return (
|
||||
f"case {self.number}: this->{self.field_name}.push_back({content}); break;"
|
||||
return self.decode_case(
|
||||
WireType.LENGTH_DELIMITED, f"this->{self.field_name}.push_back({content});"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -2165,20 +2175,8 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
content = self._ti.decode_32bit
|
||||
if content is None:
|
||||
return None
|
||||
return (
|
||||
f"case {self.number}: this->{self.field_name}.push_back({content}); break;"
|
||||
)
|
||||
|
||||
@property
|
||||
def decode_64bit_content(self) -> str:
|
||||
# Pointer fields don't support decoding
|
||||
if self._use_pointer:
|
||||
return None
|
||||
content = self._ti.decode_64bit
|
||||
if content is None:
|
||||
return None
|
||||
return (
|
||||
f"case {self.number}: this->{self.field_name}.push_back({content}); break;"
|
||||
return self.decode_case(
|
||||
WireType.FIXED32, f"this->{self.field_name}.push_back({content});"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -2595,10 +2593,7 @@ def build_message_type(
|
||||
) -> tuple[str, str, str]:
|
||||
public_content: list[str] = []
|
||||
protected_content: list[str] = []
|
||||
decode_varint: list[str] = []
|
||||
decode_length: list[str] = []
|
||||
decode_32bit: list[str] = []
|
||||
decode_64bit: list[str] = []
|
||||
decode: list[str] = []
|
||||
encode: list[str] = []
|
||||
dump: list[str] = []
|
||||
size_calc: list[str] = []
|
||||
@@ -2727,22 +2722,13 @@ def build_message_type(
|
||||
if field.options.HasExtension(pb.field_ifdef):
|
||||
field_ifdef = field.options.Extensions[pb.field_ifdef]
|
||||
|
||||
if ti.decode_varint_content:
|
||||
decode_varint.extend(
|
||||
wrap_with_ifdef(ti.decode_varint_content, field_ifdef)
|
||||
)
|
||||
if ti.decode_length_content:
|
||||
decode_length.extend(
|
||||
wrap_with_ifdef(ti.decode_length_content, field_ifdef)
|
||||
)
|
||||
if ti.decode_32bit_content:
|
||||
decode_32bit.extend(
|
||||
wrap_with_ifdef(ti.decode_32bit_content, field_ifdef)
|
||||
)
|
||||
if ti.decode_64bit_content:
|
||||
decode_64bit.extend(
|
||||
wrap_with_ifdef(ti.decode_64bit_content, field_ifdef)
|
||||
)
|
||||
for case in (
|
||||
ti.decode_varint_content,
|
||||
ti.decode_length_content,
|
||||
ti.decode_32bit_content,
|
||||
):
|
||||
if case:
|
||||
decode.extend(wrap_with_ifdef(case, field_ifdef))
|
||||
if ti.dump_content:
|
||||
# Check for field_ifdef option for dump as well
|
||||
field_ifdef = None
|
||||
@@ -2752,49 +2738,18 @@ def build_message_type(
|
||||
dump.extend(wrap_with_ifdef(ti.dump_content, field_ifdef))
|
||||
|
||||
cpp = ""
|
||||
if decode_varint:
|
||||
o = f"bool {desc.name}::decode_varint(uint32_t field_id, proto_varint_value_t value) {{\n"
|
||||
o += " switch (field_id) {\n"
|
||||
o += indent("\n".join(decode_varint), " ") + "\n"
|
||||
if decode:
|
||||
# One virtual per message: the shared decode loop parses the payload for the wire
|
||||
# type and hands it over with the tag, so a single switch covers every field.
|
||||
o = f"bool {desc.name}::decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) {{\n"
|
||||
o += " switch (PROTO_DECODE_KEY(tag, field_id)) {\n"
|
||||
o += indent("\n".join(decode), " ") + "\n"
|
||||
o += " default: return false;\n"
|
||||
o += " }\n"
|
||||
o += " return true;\n"
|
||||
o += "}\n"
|
||||
cpp += o
|
||||
prot = "bool decode_varint(uint32_t field_id, proto_varint_value_t value) override;"
|
||||
protected_content.insert(0, prot)
|
||||
if decode_length:
|
||||
o = f"bool {desc.name}::decode_length(uint32_t field_id, ProtoLengthDelimited value) {{\n"
|
||||
o += " switch (field_id) {\n"
|
||||
o += indent("\n".join(decode_length), " ") + "\n"
|
||||
o += " default: return false;\n"
|
||||
o += " }\n"
|
||||
o += " return true;\n"
|
||||
o += "}\n"
|
||||
cpp += o
|
||||
prot = "bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;"
|
||||
protected_content.insert(0, prot)
|
||||
if decode_32bit:
|
||||
o = f"bool {desc.name}::decode_32bit(uint32_t field_id, Proto32Bit value) {{\n"
|
||||
o += " switch (field_id) {\n"
|
||||
o += indent("\n".join(decode_32bit), " ") + "\n"
|
||||
o += " default: return false;\n"
|
||||
o += " }\n"
|
||||
o += " return true;\n"
|
||||
o += "}\n"
|
||||
cpp += o
|
||||
prot = "bool decode_32bit(uint32_t field_id, Proto32Bit value) override;"
|
||||
protected_content.insert(0, prot)
|
||||
if decode_64bit:
|
||||
o = f"bool {desc.name}::decode_64bit(uint32_t field_id, Proto64Bit value) {{\n"
|
||||
o += " switch (field_id) {\n"
|
||||
o += indent("\n".join(decode_64bit), " ") + "\n"
|
||||
o += " default: return false;\n"
|
||||
o += " }\n"
|
||||
o += " return true;\n"
|
||||
o += "}\n"
|
||||
cpp += o
|
||||
prot = "bool decode_64bit(uint32_t field_id, Proto64Bit value) override;"
|
||||
prot = "bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;"
|
||||
protected_content.insert(0, prot)
|
||||
|
||||
# Generate custom decode() override for messages with FixedVector fields
|
||||
|
||||
@@ -18,7 +18,9 @@ sys.path.insert(0, str(Path(__file__).parents[4] / "script" / "api_protobuf"))
|
||||
import aioesphomeapi.api_options_pb2 as pb # noqa: E402
|
||||
from api_protobuf import ( # noqa: E402
|
||||
MAX_MESSAGE_ID,
|
||||
SOURCE_CLIENT,
|
||||
_make_ifdef_line,
|
||||
build_message_type,
|
||||
create_field_type_info,
|
||||
get_varint64_ifdef,
|
||||
validate_message_id,
|
||||
@@ -182,3 +184,68 @@ def test_multi_byte_tag_fixed32_falls_back_to_the_generic_helper(
|
||||
content = _encode_field(field_type, number=16)
|
||||
assert "write_tag_and_fixed32" not in content, content
|
||||
assert content.startswith("pos = ProtoEncode::encode_"), content
|
||||
|
||||
|
||||
def _decode_cases(field_type: int, number: int) -> list[str]:
|
||||
"""Return the decode_field() case lines the generator emits for one decoded field."""
|
||||
field = descriptor_pb2.FieldDescriptorProto(
|
||||
name="value", number=number, type=field_type
|
||||
)
|
||||
ti = create_field_type_info(field, needs_decode=True, needs_encode=False)
|
||||
return [
|
||||
case
|
||||
for case in (
|
||||
ti.decode_varint_content,
|
||||
ti.decode_length_content,
|
||||
ti.decode_32bit_content,
|
||||
)
|
||||
if case
|
||||
]
|
||||
|
||||
|
||||
UINT32_T = descriptor_pb2.FieldDescriptorProto.TYPE_UINT32
|
||||
STRING_T = descriptor_pb2.FieldDescriptorProto.TYPE_STRING
|
||||
BOOL_T = descriptor_pb2.FieldDescriptorProto.TYPE_BOOL
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("field_type", "number", "wire_type", "accessor"),
|
||||
[
|
||||
(UINT32_T, 2, 0, "value.as_varint()"),
|
||||
(BOOL_T, 3, 0, "value.as_varint() != 0"),
|
||||
(STRING_T, 1, 2, "value.data()"),
|
||||
(FLOAT, 4, 5, "value.as_float()"),
|
||||
(FIXED32, 5, 5, "value.as_fixed32()"),
|
||||
],
|
||||
)
|
||||
def test_decode_cases_carry_field_number_and_wire_type(
|
||||
field_type: int, number: int, wire_type: int, accessor: str
|
||||
) -> None:
|
||||
"""Each decoded field yields one case keyed on its number and declared wire type."""
|
||||
cases = _decode_cases(field_type, number)
|
||||
assert len(cases) == 1, cases
|
||||
lines = cases[0].splitlines()
|
||||
assert lines[0] == f"case PROTO_DECODE_CASE({number}, {wire_type}):", cases[0]
|
||||
assert lines[1].strip() == f"PROTO_DECODE_GUARD(wire_type, {wire_type});", cases[0]
|
||||
assert accessor in cases[0], cases[0]
|
||||
|
||||
|
||||
def test_message_gets_a_single_decode_field_override() -> None:
|
||||
"""All wire types of a decoded message land in one decode_field() switch."""
|
||||
desc = descriptor_pb2.DescriptorProto(name="Mixed")
|
||||
desc.field.add(name="name", number=1, type=STRING_T)
|
||||
desc.field.add(name="count", number=2, type=UINT32_T)
|
||||
desc.field.add(name="level", number=3, type=FLOAT)
|
||||
header, cpp, _ = build_message_type(desc, {}, {"Mixed": SOURCE_CLIENT})
|
||||
decl = "bool decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) override;"
|
||||
assert header.count(decl) == 1
|
||||
assert "decode_varint" not in header and "decode_length" not in header
|
||||
assert (
|
||||
cpp.count(
|
||||
"bool Mixed::decode_field(uint32_t tag, uint32_t field_id, uint32_t wire_type, ProtoFieldValue value) {"
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert "switch (PROTO_DECODE_KEY(tag, field_id)) {" in cpp
|
||||
for number, wire_type in ((1, 2), (2, 0), (3, 5)):
|
||||
assert f"case PROTO_DECODE_CASE({number}, {wire_type}):" in cpp, cpp
|
||||
|
||||
Reference in New Issue
Block a user