remove v1

This commit is contained in:
J. Nick Koston 2025-07-10 08:15:48 -10:00
parent 0c8693b8c6
commit 0b2a889d0e
No known key found for this signature in database
5 changed files with 315 additions and 7354 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,22 +10,15 @@ namespace api {
static const char *const TAG = "api.proto";
void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
// Use V2 type-based implementation if available
if (get_field_metadata_v2() != nullptr || get_repeated_field_metadata_v2() != nullptr) {
decode_v2(buffer, length);
return;
}
// Fall back to old implementation
uint32_t i = 0;
bool error = false;
uint8_t *base = reinterpret_cast<uint8_t *>(this);
// Get metadata once at the start
const FieldMeta *fields = get_field_metadata();
size_t field_count = get_field_count();
const RepeatedFieldMeta *repeated_fields = get_repeated_field_metadata();
size_t repeated_count = get_repeated_field_count();
// Get V2 metadata once at the start
const FieldMetaV2 *fields = get_field_metadata_v2();
size_t field_count = get_field_count_v2();
const RepeatedFieldMetaV2 *repeated_fields = get_repeated_field_metadata_v2();
size_t repeated_count = get_repeated_field_count_v2();
while (i < length) {
uint32_t consumed;
@ -52,9 +45,47 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && fields[j].wire_type == 0) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 0) {
void *field_addr = base + fields[j].offset;
decoded = fields[j].decoder.decode_varint(field_addr, value);
switch (fields[j].type) {
case ProtoFieldType::TYPE_BOOL:
*static_cast<bool *>(field_addr) = value.as_bool();
decoded = true;
break;
case ProtoFieldType::TYPE_INT32:
*static_cast<int32_t *>(field_addr) = value.as_int32();
decoded = true;
break;
case ProtoFieldType::TYPE_UINT32:
*static_cast<uint32_t *>(field_addr) = value.as_uint32();
decoded = true;
break;
case ProtoFieldType::TYPE_INT64:
*static_cast<int64_t *>(field_addr) = value.as_int64();
decoded = true;
break;
case ProtoFieldType::TYPE_UINT64:
*static_cast<uint64_t *>(field_addr) = value.as_uint64();
decoded = true;
break;
case ProtoFieldType::TYPE_SINT32:
*static_cast<int32_t *>(field_addr) = value.as_sint32();
decoded = true;
break;
case ProtoFieldType::TYPE_SINT64:
*static_cast<int64_t *>(field_addr) = value.as_sint64();
decoded = true;
break;
case ProtoFieldType::TYPE_ENUM:
// For enums, we need to use the old metadata for now
// This will be fixed in Phase 5
*static_cast<uint32_t *>(field_addr) = value.as_uint32();
decoded = true;
break;
default:
break;
}
break;
}
}
@ -62,9 +93,62 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && repeated_fields[j].wire_type == 0) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 0) {
void *field_addr = base + repeated_fields[j].offset;
decoded = repeated_fields[j].decoder.decode_varint(field_addr, value);
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_BOOL: {
auto *vec = static_cast<std::vector<bool> *>(field_addr);
vec->push_back(value.as_bool());
decoded = true;
break;
}
case ProtoFieldType::TYPE_INT32: {
auto *vec = static_cast<std::vector<int32_t> *>(field_addr);
vec->push_back(value.as_int32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_UINT32: {
auto *vec = static_cast<std::vector<uint32_t> *>(field_addr);
vec->push_back(value.as_uint32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_INT64: {
auto *vec = static_cast<std::vector<int64_t> *>(field_addr);
vec->push_back(value.as_int64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_UINT64: {
auto *vec = static_cast<std::vector<uint64_t> *>(field_addr);
vec->push_back(value.as_uint64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SINT32: {
auto *vec = static_cast<std::vector<int32_t> *>(field_addr);
vec->push_back(value.as_sint32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SINT64: {
auto *vec = static_cast<std::vector<int64_t> *>(field_addr);
vec->push_back(value.as_sint64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_ENUM: {
// For repeated enums, use old metadata for now
auto *vec = static_cast<std::vector<uint32_t> *>(field_addr);
vec->push_back(value.as_uint32());
decoded = true;
break;
}
default:
break;
}
break;
}
}
@ -95,9 +179,31 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && fields[j].wire_type == 2) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 2) {
void *field_addr = base + fields[j].offset;
decoded = fields[j].decoder.decode_length(field_addr, value);
switch (fields[j].type) {
case ProtoFieldType::TYPE_STRING:
*static_cast<std::string *>(field_addr) = value.as_string();
decoded = true;
break;
case ProtoFieldType::TYPE_BYTES: {
// ProtoLengthDelimited has protected members, use buffer directly
static_cast<std::string *>(field_addr)
->assign(reinterpret_cast<const char *>(&buffer[i]), field_length);
decoded = true;
break;
}
case ProtoFieldType::TYPE_MESSAGE: {
// Use function pointer from metadata
if (fields[j].handler.message.decode) {
decoded = fields[j].handler.message.decode(field_addr, value);
}
break;
}
default:
break;
}
break;
}
}
@ -105,35 +211,76 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && repeated_fields[j].wire_type == 2) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 2) {
void *field_addr = base + repeated_fields[j].offset;
decoded = repeated_fields[j].decoder.decode_length(field_addr, value);
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_STRING: {
auto *vec = static_cast<std::vector<std::string> *>(field_addr);
vec->push_back(value.as_string());
decoded = true;
break;
}
case ProtoFieldType::TYPE_BYTES: {
auto *vec = static_cast<std::vector<std::string> *>(field_addr);
vec->emplace_back(reinterpret_cast<const char *>(&buffer[i]), field_length);
decoded = true;
break;
}
case ProtoFieldType::TYPE_MESSAGE: {
// Use function pointer from metadata
if (repeated_fields[j].handler.message.decode) {
decoded = repeated_fields[j].handler.message.decode(field_addr, value);
}
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode Length Delimited field %" PRIu32 "!", field_id);
ESP_LOGV(TAG, "Cannot decode Length field %" PRIu32, field_id);
}
i += field_length;
break;
}
case 5: { // 32-bit
if (length - i < 4) {
ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %" PRIu32, i);
ESP_LOGV(TAG, "Invalid 32-bit at %" PRIu32, i);
error = true;
break;
}
uint32_t val = encode_uint32(buffer[i + 3], buffer[i + 2], buffer[i + 1], buffer[i]);
Proto32Bit value(val);
uint32_t raw = (buffer[i]) | (buffer[i + 1] << 8) | (buffer[i + 2] << 16) | (buffer[i + 3] << 24);
Proto32Bit value(raw);
bool decoded = false;
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && fields[j].wire_type == 5) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 5) {
void *field_addr = base + fields[j].offset;
decoded = fields[j].decoder.decode_32bit(field_addr, value);
switch (fields[j].type) {
case ProtoFieldType::TYPE_FLOAT: {
float *val = static_cast<float *>(field_addr);
*val = value.as_float();
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED32:
*static_cast<uint32_t *>(field_addr) = value.as_fixed32();
decoded = true;
break;
case ProtoFieldType::TYPE_SFIXED32:
*static_cast<int32_t *>(field_addr) = value.as_sfixed32();
decoded = true;
break;
default:
break;
}
break;
}
}
@ -141,24 +288,125 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && repeated_fields[j].wire_type == 5) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 5) {
void *field_addr = base + repeated_fields[j].offset;
decoded = repeated_fields[j].decoder.decode_32bit(field_addr, value);
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_FLOAT: {
auto *vec = static_cast<std::vector<float> *>(field_addr);
vec->push_back(value.as_float());
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED32: {
auto *vec = static_cast<std::vector<uint32_t> *>(field_addr);
vec->push_back(value.as_fixed32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SFIXED32: {
auto *vec = static_cast<std::vector<int32_t> *>(field_addr);
vec->push_back(value.as_sfixed32());
decoded = true;
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32 " with value %" PRIu32 "!", field_id, val);
ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32, field_id);
}
i += 4;
break;
}
default:
ESP_LOGV(TAG, "Invalid field type at %" PRIu32, i);
error = true;
case 1: { // 64-bit
if (length - i < 8) {
ESP_LOGV(TAG, "Invalid 64-bit at %" PRIu32, i);
error = true;
break;
}
uint64_t raw = uint64_t(buffer[i]) | (uint64_t(buffer[i + 1]) << 8) | (uint64_t(buffer[i + 2]) << 16) |
(uint64_t(buffer[i + 3]) << 24) | (uint64_t(buffer[i + 4]) << 32) |
(uint64_t(buffer[i + 5]) << 40) | (uint64_t(buffer[i + 6]) << 48) |
(uint64_t(buffer[i + 7]) << 56);
Proto64Bit value(raw);
bool decoded = false;
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 1) {
void *field_addr = base + fields[j].offset;
switch (fields[j].type) {
case ProtoFieldType::TYPE_DOUBLE: {
double *val = static_cast<double *>(field_addr);
*val = value.as_double();
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED64:
*static_cast<uint64_t *>(field_addr) = value.as_fixed64();
decoded = true;
break;
case ProtoFieldType::TYPE_SFIXED64:
*static_cast<int64_t *>(field_addr) = value.as_sfixed64();
decoded = true;
break;
default:
break;
}
break;
}
}
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 1) {
void *field_addr = base + repeated_fields[j].offset;
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_DOUBLE: {
auto *vec = static_cast<std::vector<double> *>(field_addr);
vec->push_back(value.as_double());
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED64: {
auto *vec = static_cast<std::vector<uint64_t> *>(field_addr);
vec->push_back(value.as_fixed64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SFIXED64: {
auto *vec = static_cast<std::vector<int64_t> *>(field_addr);
vec->push_back(value.as_sfixed64());
decoded = true;
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode 64-bit field %" PRIu32, field_id);
}
i += 8;
break;
}
default: {
ESP_LOGV(TAG, "Invalid field type %" PRIu32 " at %" PRIu32, field_type, i);
return;
}
}
if (error) {
break;
@ -648,468 +896,8 @@ bool decode_repeated_double_field(void *field_ptr, Proto64Bit value) {
return true;
}
// Core shared functions
void encode_from_metadata(ProtoWriteBuffer buffer, const void *obj, const FieldMeta *fields, size_t field_count,
const RepeatedFieldMeta *repeated_fields, size_t repeated_count) {
const uint8_t *base = static_cast<const uint8_t *>(obj);
// Encode regular fields
for (size_t i = 0; i < field_count; i++) {
const void *field_addr = base + fields[i].offset;
fields[i].encoder(buffer, field_addr, fields[i].field_num);
}
// Encode repeated fields
for (size_t i = 0; i < repeated_count; i++) {
const void *field_addr = base + repeated_fields[i].offset;
repeated_fields[i].encoder(buffer, field_addr, repeated_fields[i].field_num);
}
}
void calculate_size_from_metadata(uint32_t &total_size, const void *obj, const FieldMeta *fields, size_t field_count,
const RepeatedFieldMeta *repeated_fields, size_t repeated_count) {
const uint8_t *base = static_cast<const uint8_t *>(obj);
// Calculate size for regular fields
for (size_t i = 0; i < field_count; i++) {
const void *field_addr = base + fields[i].offset;
fields[i].sizer(total_size, field_addr, fields[i].precalced_field_id_size, fields[i].force_encode);
}
// Calculate size for repeated fields
for (size_t i = 0; i < repeated_count; i++) {
const void *field_addr = base + repeated_fields[i].offset;
repeated_fields[i].sizer(total_size, field_addr, repeated_fields[i].precalced_field_id_size);
}
}
// ProtoMessage implementations using metadata
void ProtoMessage::encode(ProtoWriteBuffer buffer) const {
if (get_field_metadata_v2() != nullptr || get_repeated_field_metadata_v2() != nullptr) {
encode_v2(buffer);
} else {
encode_from_metadata(buffer, this, get_field_metadata(), get_field_count(), get_repeated_field_metadata(),
get_repeated_field_count());
}
}
void ProtoMessage::calculate_size(uint32_t &total_size) const {
if (get_field_metadata_v2() != nullptr || get_repeated_field_metadata_v2() != nullptr) {
calculate_size_v2(total_size);
} else {
calculate_size_from_metadata(total_size, this, get_field_metadata(), get_field_count(),
get_repeated_field_metadata(), get_repeated_field_count());
}
}
// Type-based decode implementation
void ProtoMessage::decode_v2(const uint8_t *buffer, size_t length) {
uint32_t i = 0;
bool error = false;
uint8_t *base = reinterpret_cast<uint8_t *>(this);
// Get V2 metadata once at the start
const FieldMetaV2 *fields = get_field_metadata_v2();
size_t field_count = get_field_count_v2();
const RepeatedFieldMetaV2 *repeated_fields = get_repeated_field_metadata_v2();
size_t repeated_count = get_repeated_field_count_v2();
while (i < length) {
uint32_t consumed;
auto res = ProtoVarInt::parse(&buffer[i], length - i, &consumed);
if (!res.has_value()) {
ESP_LOGV(TAG, "Invalid field start at %" PRIu32, i);
break;
}
uint32_t field_type = (res->as_uint32()) & 0b111;
uint32_t field_id = (res->as_uint32()) >> 3;
i += consumed;
switch (field_type) {
case 0: { // VarInt
res = ProtoVarInt::parse(&buffer[i], length - i, &consumed);
if (!res.has_value()) {
ESP_LOGV(TAG, "Invalid VarInt at %" PRIu32, i);
error = true;
break;
}
ProtoVarInt value = *res;
bool decoded = false;
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 0) {
void *field_addr = base + fields[j].offset;
switch (fields[j].type) {
case ProtoFieldType::TYPE_BOOL:
*static_cast<bool *>(field_addr) = value.as_bool();
decoded = true;
break;
case ProtoFieldType::TYPE_INT32:
*static_cast<int32_t *>(field_addr) = value.as_int32();
decoded = true;
break;
case ProtoFieldType::TYPE_UINT32:
*static_cast<uint32_t *>(field_addr) = value.as_uint32();
decoded = true;
break;
case ProtoFieldType::TYPE_INT64:
*static_cast<int64_t *>(field_addr) = value.as_int64();
decoded = true;
break;
case ProtoFieldType::TYPE_UINT64:
*static_cast<uint64_t *>(field_addr) = value.as_uint64();
decoded = true;
break;
case ProtoFieldType::TYPE_SINT32:
*static_cast<int32_t *>(field_addr) = value.as_sint32();
decoded = true;
break;
case ProtoFieldType::TYPE_SINT64:
*static_cast<int64_t *>(field_addr) = value.as_sint64();
decoded = true;
break;
case ProtoFieldType::TYPE_ENUM:
// For enums, we need to use the old metadata for now
// This will be fixed in Phase 5
*static_cast<uint32_t *>(field_addr) = value.as_uint32();
decoded = true;
break;
default:
break;
}
break;
}
}
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 0) {
void *field_addr = base + repeated_fields[j].offset;
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_BOOL: {
auto *vec = static_cast<std::vector<bool> *>(field_addr);
vec->push_back(value.as_bool());
decoded = true;
break;
}
case ProtoFieldType::TYPE_INT32: {
auto *vec = static_cast<std::vector<int32_t> *>(field_addr);
vec->push_back(value.as_int32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_UINT32: {
auto *vec = static_cast<std::vector<uint32_t> *>(field_addr);
vec->push_back(value.as_uint32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_INT64: {
auto *vec = static_cast<std::vector<int64_t> *>(field_addr);
vec->push_back(value.as_int64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_UINT64: {
auto *vec = static_cast<std::vector<uint64_t> *>(field_addr);
vec->push_back(value.as_uint64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SINT32: {
auto *vec = static_cast<std::vector<int32_t> *>(field_addr);
vec->push_back(value.as_sint32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SINT64: {
auto *vec = static_cast<std::vector<int64_t> *>(field_addr);
vec->push_back(value.as_sint64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_ENUM: {
// For repeated enums, use old metadata for now
auto *vec = static_cast<std::vector<uint32_t> *>(field_addr);
vec->push_back(value.as_uint32());
decoded = true;
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode VarInt field %" PRIu32 " with value %" PRIu32 "!", field_id, res->as_uint32());
}
i += consumed;
break;
}
case 2: { // Length-delimited
res = ProtoVarInt::parse(&buffer[i], length - i, &consumed);
if (!res.has_value()) {
ESP_LOGV(TAG, "Invalid Length Delimited at %" PRIu32, i);
error = true;
break;
}
uint32_t field_length = res->as_uint32();
i += consumed;
if (field_length > length - i) {
ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %" PRIu32, i);
error = true;
break;
}
ProtoLengthDelimited value(&buffer[i], field_length);
bool decoded = false;
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 2) {
void *field_addr = base + fields[j].offset;
switch (fields[j].type) {
case ProtoFieldType::TYPE_STRING:
*static_cast<std::string *>(field_addr) = value.as_string();
decoded = true;
break;
case ProtoFieldType::TYPE_BYTES: {
// ProtoLengthDelimited has protected members, use buffer directly
static_cast<std::string *>(field_addr)
->assign(reinterpret_cast<const char *>(&buffer[i]), field_length);
decoded = true;
break;
}
case ProtoFieldType::TYPE_MESSAGE: {
// Use function pointer from metadata
if (fields[j].handler.message.decode) {
decoded = fields[j].handler.message.decode(field_addr, value);
}
break;
}
default:
break;
}
break;
}
}
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 2) {
void *field_addr = base + repeated_fields[j].offset;
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_STRING: {
auto *vec = static_cast<std::vector<std::string> *>(field_addr);
vec->push_back(value.as_string());
decoded = true;
break;
}
case ProtoFieldType::TYPE_BYTES: {
auto *vec = static_cast<std::vector<std::string> *>(field_addr);
vec->emplace_back(reinterpret_cast<const char *>(&buffer[i]), field_length);
decoded = true;
break;
}
case ProtoFieldType::TYPE_MESSAGE: {
// Use function pointer from metadata
if (repeated_fields[j].handler.message.decode) {
decoded = repeated_fields[j].handler.message.decode(field_addr, value);
}
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode Length field %" PRIu32, field_id);
}
i += field_length;
break;
}
case 5: { // 32-bit
if (length - i < 4) {
ESP_LOGV(TAG, "Invalid 32-bit at %" PRIu32, i);
error = true;
break;
}
uint32_t raw = (buffer[i]) | (buffer[i + 1] << 8) | (buffer[i + 2] << 16) | (buffer[i + 3] << 24);
Proto32Bit value(raw);
bool decoded = false;
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 5) {
void *field_addr = base + fields[j].offset;
switch (fields[j].type) {
case ProtoFieldType::TYPE_FLOAT: {
float *val = static_cast<float *>(field_addr);
*val = value.as_float();
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED32:
*static_cast<uint32_t *>(field_addr) = value.as_fixed32();
decoded = true;
break;
case ProtoFieldType::TYPE_SFIXED32:
*static_cast<int32_t *>(field_addr) = value.as_sfixed32();
decoded = true;
break;
default:
break;
}
break;
}
}
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 5) {
void *field_addr = base + repeated_fields[j].offset;
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_FLOAT: {
auto *vec = static_cast<std::vector<float> *>(field_addr);
vec->push_back(value.as_float());
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED32: {
auto *vec = static_cast<std::vector<uint32_t> *>(field_addr);
vec->push_back(value.as_fixed32());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SFIXED32: {
auto *vec = static_cast<std::vector<int32_t> *>(field_addr);
vec->push_back(value.as_sfixed32());
decoded = true;
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32, field_id);
}
i += 4;
break;
}
case 1: { // 64-bit
if (length - i < 8) {
ESP_LOGV(TAG, "Invalid 64-bit at %" PRIu32, i);
error = true;
break;
}
uint64_t raw = uint64_t(buffer[i]) | (uint64_t(buffer[i + 1]) << 8) | (uint64_t(buffer[i + 2]) << 16) |
(uint64_t(buffer[i + 3]) << 24) | (uint64_t(buffer[i + 4]) << 32) |
(uint64_t(buffer[i + 5]) << 40) | (uint64_t(buffer[i + 6]) << 48) |
(uint64_t(buffer[i + 7]) << 56);
Proto64Bit value(raw);
bool decoded = false;
// Check regular fields
for (size_t j = 0; j < field_count; j++) {
if (fields[j].field_num == field_id && get_wire_type(fields[j].type) == 1) {
void *field_addr = base + fields[j].offset;
switch (fields[j].type) {
case ProtoFieldType::TYPE_DOUBLE: {
double *val = static_cast<double *>(field_addr);
*val = value.as_double();
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED64:
*static_cast<uint64_t *>(field_addr) = value.as_fixed64();
decoded = true;
break;
case ProtoFieldType::TYPE_SFIXED64:
*static_cast<int64_t *>(field_addr) = value.as_sfixed64();
decoded = true;
break;
default:
break;
}
break;
}
}
// Check repeated fields if not found
if (!decoded && repeated_fields) {
for (size_t j = 0; j < repeated_count; j++) {
if (repeated_fields[j].field_num == field_id && get_wire_type(repeated_fields[j].type) == 1) {
void *field_addr = base + repeated_fields[j].offset;
switch (repeated_fields[j].type) {
case ProtoFieldType::TYPE_DOUBLE: {
auto *vec = static_cast<std::vector<double> *>(field_addr);
vec->push_back(value.as_double());
decoded = true;
break;
}
case ProtoFieldType::TYPE_FIXED64: {
auto *vec = static_cast<std::vector<uint64_t> *>(field_addr);
vec->push_back(value.as_fixed64());
decoded = true;
break;
}
case ProtoFieldType::TYPE_SFIXED64: {
auto *vec = static_cast<std::vector<int64_t> *>(field_addr);
vec->push_back(value.as_sfixed64());
decoded = true;
break;
}
default:
break;
}
break;
}
}
}
if (!decoded) {
ESP_LOGV(TAG, "Cannot decode 64-bit field %" PRIu32, field_id);
}
i += 8;
break;
}
default: {
ESP_LOGV(TAG, "Invalid field type %" PRIu32 " at %" PRIu32, field_type, i);
return;
}
}
if (error) {
break;
}
}
}
// Type-based encode implementation
void ProtoMessage::encode_v2(ProtoWriteBuffer buffer) const {
const uint8_t *base = reinterpret_cast<const uint8_t *>(this);
// Get V2 metadata once at the start
@ -1351,8 +1139,7 @@ void ProtoMessage::encode_v2(ProtoWriteBuffer buffer) const {
}
}
// Type-based size calculation implementation
void ProtoMessage::calculate_size_v2(uint32_t &total_size) const {
void ProtoMessage::calculate_size(uint32_t &total_size) const {
const uint8_t *base = reinterpret_cast<const uint8_t *>(this);
// Get V2 metadata once at the start

View File

@ -75,22 +75,11 @@ constexpr uint8_t get_wire_type(ProtoFieldType type) {
return 0;
}
// Function pointer types for encoding and size calculation
using EncodeFunc = void (*)(ProtoWriteBuffer &, const void *field_ptr, uint8_t field_num);
using SizeFunc = void (*)(uint32_t &total_size, const void *field_ptr, uint8_t precalced_field_id_size, bool force);
// Macro to calculate field offset without triggering -Winvalid-offsetof
// This uses the same approach as offsetof but with explicit reinterpret_cast
#define PROTO_FIELD_OFFSET(Type, Member) \
static_cast<uint16_t>(reinterpret_cast<size_t>(&reinterpret_cast<Type *>(16)->Member) - 16)
// Function pointer types for repeated fields
using RepeatedEncodeFunc = void (*)(ProtoWriteBuffer &, const void *field_ptr, uint8_t field_num);
using RepeatedSizeFunc = void (*)(uint32_t &total_size, const void *field_ptr, uint8_t precalced_field_id_size);
// Forward declaration for RepeatedFieldMeta - will be defined after Proto* classes
struct RepeatedFieldMeta;
/// Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit
class ProtoVarInt {
public:
@ -262,28 +251,15 @@ class Proto64Bit {
const uint64_t value_;
};
// Function pointer types for decoding (now that Proto classes are defined)
using DecodeVarintFunc = bool (*)(void *field_ptr, ProtoVarInt value);
// Function pointer types used by V2 structures
using EncodeFunc = void (*)(ProtoWriteBuffer &, const void *field_ptr, uint8_t field_num);
using SizeFunc = void (*)(uint32_t &total_size, const void *field_ptr, uint8_t precalced_field_id_size, bool force);
using DecodeLengthFunc = bool (*)(void *field_ptr, ProtoLengthDelimited value);
using Decode32BitFunc = bool (*)(void *field_ptr, Proto32Bit value);
using Decode64BitFunc = bool (*)(void *field_ptr, Proto64Bit value);
// Metadata structure describing each field
struct FieldMeta {
uint8_t field_num; // Protobuf field number (1-255)
uint16_t offset; // offset of field in class
EncodeFunc encoder; // Function to encode this field type
SizeFunc sizer; // Function to calculate size for this field type
bool force_encode; // If true, encode even if value is default/empty
uint8_t wire_type; // Wire type (0=varint, 2=length, 5=32bit, 1=64bit)
uint8_t precalced_field_id_size; // Pre-calculated size of field tag in bytes
union {
DecodeVarintFunc decode_varint;
DecodeLengthFunc decode_length;
Decode32BitFunc decode_32bit;
Decode64BitFunc decode_64bit;
} decoder;
};
// Function pointer types for repeated fields used by V2 structures
using RepeatedEncodeFunc = void (*)(ProtoWriteBuffer &, const void *field_ptr, uint8_t field_num);
using RepeatedSizeFunc = void (*)(uint32_t &total_size, const void *field_ptr, uint8_t precalced_field_id_size);
using RepeatedDecodeLengthFunc = bool (*)(void *field_ptr, ProtoLengthDelimited value);
// New type-based metadata structure (smaller and more efficient)
struct FieldMetaV2 {
@ -464,28 +440,6 @@ class ProtoWriteBuffer {
std::vector<uint8_t> *buffer_;
};
// Forward declarations for repeated field decode - now that Proto* classes are defined
using RepeatedDecodeVarintFunc = bool (*)(void *field_ptr, ProtoVarInt value);
using RepeatedDecodeLengthFunc = bool (*)(void *field_ptr, ProtoLengthDelimited value);
using RepeatedDecode32BitFunc = bool (*)(void *field_ptr, Proto32Bit value);
using RepeatedDecode64BitFunc = bool (*)(void *field_ptr, Proto64Bit value);
// Special metadata for repeated fields
struct RepeatedFieldMeta {
uint8_t field_num;
uint16_t offset;
RepeatedEncodeFunc encoder; // Encoder for the entire vector
RepeatedSizeFunc sizer; // Sizer for the entire vector
uint8_t precalced_field_id_size; // Pre-calculated size of field tag in bytes
uint8_t wire_type; // Wire type for decoding
union {
RepeatedDecodeVarintFunc decode_varint;
RepeatedDecodeLengthFunc decode_length;
RepeatedDecode32BitFunc decode_32bit;
RepeatedDecode64BitFunc decode_64bit;
} decoder;
};
// New type-based repeated field metadata
struct RepeatedFieldMetaV2 {
uint8_t field_num;
@ -508,28 +462,17 @@ class ProtoMessage {
public:
virtual ~ProtoMessage() = default;
// Virtual methods to get metadata - must be implemented by derived classes
virtual const FieldMeta *get_field_metadata() const { return nullptr; }
virtual size_t get_field_count() const { return 0; }
virtual const RepeatedFieldMeta *get_repeated_field_metadata() const { return nullptr; }
virtual size_t get_repeated_field_count() const { return 0; }
// V2 metadata getters - default implementations return nullptr/0
// V2 metadata getters - must be implemented by derived classes
virtual const FieldMetaV2 *get_field_metadata_v2() const { return nullptr; }
virtual size_t get_field_count_v2() const { return 0; }
virtual const RepeatedFieldMetaV2 *get_repeated_field_metadata_v2() const { return nullptr; }
virtual size_t get_repeated_field_count_v2() const { return 0; }
// Encode/decode/calculate_size using metadata
// Encode/decode/calculate_size using V2 metadata
void encode(ProtoWriteBuffer buffer) const;
void decode(const uint8_t *buffer, size_t length);
void calculate_size(uint32_t &total_size) const;
// Type-based implementations using V2 metadata
void decode_v2(const uint8_t *buffer, size_t length);
void encode_v2(ProtoWriteBuffer buffer) const;
void calculate_size_v2(uint32_t &total_size) const;
#ifdef HAS_PROTO_MESSAGE_DUMP
std::string dump() const;
virtual void dump_to(std::string &out) const = 0;
@ -721,12 +664,7 @@ void encode_repeated_message_field(ProtoWriteBuffer &buffer, const void *field_p
template<typename MessageType>
void size_repeated_message_field(uint32_t &total_size, const void *field_ptr, uint8_t precalced_field_id_size);
// Core shared functions
void encode_from_metadata(ProtoWriteBuffer buffer, const void *obj, const FieldMeta *fields, size_t field_count,
const RepeatedFieldMeta *repeated_fields = nullptr, size_t repeated_count = 0);
void calculate_size_from_metadata(uint32_t &total_size, const void *obj, const FieldMeta *fields, size_t field_count,
const RepeatedFieldMeta *repeated_fields = nullptr, size_t repeated_count = 0);
// Core shared functions removed - V2 metadata is used directly
} // namespace api
} // namespace esphome

View File

@ -1290,94 +1290,10 @@ def build_message_type(
# Generate metadata arrays for all classes using metadata approach
regular_fields = []
repeated_fields = []
regular_fields_v2 = []
repeated_fields_v2 = []
metadata_info = None
if use_metadata:
for field in desc.field:
if field.label == 3: # Repeated field
ti = RepeatedTypeInfo(field)
encoder = get_repeated_encoder_function(ti)
sizer = get_repeated_sizer_function(ti)
decoder = get_repeated_decoder_function(ti)
field_tag_size = ti.calculate_field_id_size()
wire_type = get_wire_type(ti._ti)
if encoder and sizer and decoder:
# Format: {field_num, offset, encoder, sizer, precalced_field_id_size, wire_type, {decoder}}
decoder_field = (
f".decode_varint = {decoder}"
if wire_type == 0
else f".decode_length = {decoder}"
if wire_type == 2
else f".decode_32bit = {decoder}"
if wire_type == 5
else f".decode_64bit = {decoder}"
)
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), {encoder}, {sizer}, {field_tag_size}, {wire_type}, {{{decoder_field}}}}}"
)
elif isinstance(ti._ti, EnumType):
# Handle enum repeated fields with template
enum_type = ti._ti.cpp_type
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"&encode_repeated_enum_field<{enum_type}>, &size_repeated_enum_field<{enum_type}>, {field_tag_size}, 0, "
f"{{.decode_varint = &decode_repeated_enum_field<{enum_type}>}}}}"
)
elif isinstance(ti._ti, MessageType):
# Handle message repeated fields with template
msg_type = ti._ti.cpp_type
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"&encode_repeated_message_field<{msg_type}>, &size_repeated_message_field<{msg_type}>, {field_tag_size}, 2, "
f"{{.decode_length = &decode_repeated_message_field<{msg_type}>}}}}"
)
else:
ti = TYPE_INFO[field.type](field)
encoder = get_encoder_function(ti)
sizer = get_sizer_function(ti)
wire_type = get_wire_type(ti)
decoder = get_decoder_function(ti, wire_type)
force = "true" if field.label == 2 else "false" # Required fields
if encoder and sizer and decoder:
# Calculate pre-calculated field tag size
field_tag_size = ti.calculate_field_id_size()
# Format: {field_num, offset, encoder, sizer, force_encode, wire_type, precalced_field_id_size, {decoder}}
decoder_field = (
f".decode_varint = {decoder}"
if wire_type == 0
else f".decode_length = {decoder}"
if wire_type == 2
else f".decode_32bit = {decoder}"
if wire_type == 5
else f".decode_64bit = {decoder}"
)
regular_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), {encoder}, {sizer}, {force}, {wire_type}, {field_tag_size}, {{{decoder_field}}}}}"
)
elif isinstance(ti, EnumType):
# Handle enum fields with template
enum_type = ti.cpp_type
field_tag_size = ti.calculate_field_id_size()
regular_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"&encode_enum_field<{enum_type}>, &size_enum_field<{enum_type}>, {force}, 0, {field_tag_size}, {{.decode_varint = &decode_enum_field<{enum_type}>}}}}"
)
elif isinstance(ti, MessageType):
# Skip nested messages for now - they need special handling
pass
# Store metadata info for later generation outside the class
metadata_info = {
"regular_fields": regular_fields,
"repeated_fields": repeated_fields,
"class_name": desc.name,
}
# Also generate V2 metadata
# Generate V2 metadata
for field in desc.field:
if field.label == 3: # Repeated field
ti = RepeatedTypeInfo(field)
@ -1386,7 +1302,7 @@ def build_message_type(
field_tag_size = ti.calculate_field_id_size()
if field.type == descriptor.FieldDescriptorProto.TYPE_MESSAGE:
# For messages, generate function pointers
repeated_fields_v2.append(
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"{field_type}, {field_tag_size}, "
f"{{.message = {{&encode_repeated_message_field<{ti._ti.type_name}>, "
@ -1395,18 +1311,18 @@ def build_message_type(
)
else:
# Non-message types don't need handler info
repeated_fields_v2.append(
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"{field_type}, {field_tag_size}, {{}}}}"
)
elif isinstance(ti._ti, EnumType):
enum_type_id = get_message_type_id(ti._ti.type_name)
repeated_fields_v2.append(
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"ProtoFieldType::TYPE_ENUM, {ti.calculate_field_id_size()}, {{.enum_id = {enum_type_id}}}}}"
)
elif isinstance(ti._ti, MessageType):
repeated_fields_v2.append(
repeated_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"ProtoFieldType::TYPE_MESSAGE, {ti.calculate_field_id_size()}, "
f"{{.message = {{&encode_repeated_message_field<{ti._ti.type_name}>, "
@ -1422,7 +1338,7 @@ def build_message_type(
field_tag_size = ti.calculate_field_id_size()
if field.type == descriptor.FieldDescriptorProto.TYPE_MESSAGE:
# For messages, generate function pointers
regular_fields_v2.append(
regular_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"{field_type}, {force}, {field_tag_size}, "
f"{{.message = {{&encode_message_field<{ti.type_name}>, "
@ -1431,7 +1347,7 @@ def build_message_type(
)
else:
# Non-message types don't need handler info
regular_fields_v2.append(
regular_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"{field_type}, {force}, {field_tag_size}, {{}}}}"
)
@ -1439,14 +1355,14 @@ def build_message_type(
field_tag_size = ti.calculate_field_id_size()
# For enums, use the enum name as type ID
enum_type_id = get_message_type_id(ti.type_name)
regular_fields_v2.append(
regular_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"ProtoFieldType::TYPE_ENUM, {force}, {field_tag_size}, {{.enum_id = {enum_type_id}}}}}"
)
elif isinstance(ti, MessageType):
field_tag_size = ti.calculate_field_id_size()
# For messages, generate function pointers
regular_fields_v2.append(
regular_fields.append(
f"{{{field.number}, PROTO_FIELD_OFFSET({desc.name}, {ti.field_name}), "
f"ProtoFieldType::TYPE_MESSAGE, {force}, {field_tag_size}, "
f"{{.message = {{&encode_message_field<{ti.type_name}>, "
@ -1454,8 +1370,12 @@ def build_message_type(
f"&decode_message_field<{ti.type_name}>}}}}}}"
)
metadata_info["regular_fields_v2"] = regular_fields_v2
metadata_info["repeated_fields_v2"] = repeated_fields_v2
# Store metadata info for later generation outside the class
metadata_info = {
"regular_fields": regular_fields,
"repeated_fields": repeated_fields,
"class_name": desc.name,
}
# Only generate decode methods for classes not using metadata approach
if not use_metadata:
@ -1509,41 +1429,20 @@ def build_message_type(
# Add static declarations inside the class (definitions will be in cpp file)
if regular_fields:
public_content.append(
f"static const FieldMeta FIELDS[{len(regular_fields)}];"
f"static const FieldMetaV2 FIELDS_V2[{len(regular_fields)}];"
)
public_content.append(
f"static constexpr size_t FIELD_COUNT = {len(regular_fields)};"
)
else:
public_content.append("static constexpr size_t FIELD_COUNT = 0;")
if repeated_fields:
public_content.append(
f"static const RepeatedFieldMeta REPEATED_FIELDS[{len(repeated_fields)}];"
)
public_content.append(
f"static constexpr size_t REPEATED_COUNT = {len(repeated_fields)};"
)
else:
public_content.append("static constexpr size_t REPEATED_COUNT = 0;")
# Add V2 metadata arrays
if regular_fields_v2:
public_content.append(
f"static const FieldMetaV2 FIELDS_V2[{len(regular_fields_v2)}];"
)
public_content.append(
f"static constexpr size_t FIELD_COUNT_V2 = {len(regular_fields_v2)};"
f"static constexpr size_t FIELD_COUNT_V2 = {len(regular_fields)};"
)
else:
public_content.append("static constexpr size_t FIELD_COUNT_V2 = 0;")
if repeated_fields_v2:
if repeated_fields:
public_content.append(
f"static const RepeatedFieldMetaV2 REPEATED_FIELDS_V2[{len(repeated_fields_v2)}];"
f"static const RepeatedFieldMetaV2 REPEATED_FIELDS_V2[{len(repeated_fields)}];"
)
public_content.append(
f"static constexpr size_t REPEATED_COUNT_V2 = {len(repeated_fields_v2)};"
f"static constexpr size_t REPEATED_COUNT_V2 = {len(repeated_fields)};"
)
else:
public_content.append("static constexpr size_t REPEATED_COUNT_V2 = 0;")
@ -1551,31 +1450,6 @@ def build_message_type(
# Add virtual getter methods that return the metadata
public_content.append("// Virtual metadata getters")
if regular_fields:
public_content.append(
"const FieldMeta *get_field_metadata() const override { return FIELDS; }"
)
else:
public_content.append(
"const FieldMeta *get_field_metadata() const override { return nullptr; }"
)
public_content.append(
"size_t get_field_count() const override { return FIELD_COUNT; }"
)
if repeated_fields:
public_content.append(
"const RepeatedFieldMeta *get_repeated_field_metadata() const override { return REPEATED_FIELDS; }"
)
else:
public_content.append(
"const RepeatedFieldMeta *get_repeated_field_metadata() const override { return nullptr; }"
)
public_content.append(
"size_t get_repeated_field_count() const override { return REPEATED_COUNT; }"
)
# Add V2 metadata getters
if regular_fields_v2:
public_content.append(
"const FieldMetaV2 *get_field_metadata_v2() const override { return FIELDS_V2; }"
)
@ -1587,7 +1461,7 @@ def build_message_type(
"size_t get_field_count_v2() const override { return FIELD_COUNT_V2; }"
)
if repeated_fields_v2:
if repeated_fields:
public_content.append(
"const RepeatedFieldMetaV2 *get_repeated_field_metadata_v2() const override { return REPEATED_FIELDS_V2; }"
)
@ -2057,8 +1931,9 @@ namespace api {
cpp += f"#ifdef {msg_ifdef}\n"
current_ifdef = msg_ifdef
# Generate V2 metadata arrays
if regular_fields:
cpp += f"const FieldMeta {class_name}::FIELDS[{len(regular_fields)}] = {{\n"
cpp += f"const FieldMetaV2 {class_name}::FIELDS_V2[{len(regular_fields)}] = {{\n"
for i, field in enumerate(regular_fields):
if i < len(regular_fields) - 1:
cpp += f" {field},\n"
@ -2067,7 +1942,7 @@ namespace api {
cpp += "};\n"
if repeated_fields:
cpp += f"const RepeatedFieldMeta {class_name}::REPEATED_FIELDS[{len(repeated_fields)}] = {{\n"
cpp += f"const RepeatedFieldMetaV2 {class_name}::REPEATED_FIELDS_V2[{len(repeated_fields)}] = {{\n"
for i, field in enumerate(repeated_fields):
if i < len(repeated_fields) - 1:
cpp += f" {field},\n"
@ -2075,28 +1950,6 @@ namespace api {
cpp += f" {field}\n"
cpp += "};\n"
# Generate V2 metadata arrays
regular_fields_v2 = meta.get("regular_fields_v2", [])
repeated_fields_v2 = meta.get("repeated_fields_v2", [])
if regular_fields_v2:
cpp += f"const FieldMetaV2 {class_name}::FIELDS_V2[{len(regular_fields_v2)}] = {{\n"
for i, field in enumerate(regular_fields_v2):
if i < len(regular_fields_v2) - 1:
cpp += f" {field},\n"
else:
cpp += f" {field}\n"
cpp += "};\n"
if repeated_fields_v2:
cpp += f"const RepeatedFieldMetaV2 {class_name}::REPEATED_FIELDS_V2[{len(repeated_fields_v2)}] = {{\n"
for i, field in enumerate(repeated_fields_v2):
if i < len(repeated_fields_v2) - 1:
cpp += f" {field},\n"
else:
cpp += f" {field}\n"
cpp += "};\n"
# Close last ifdef for metadata
if current_ifdef is not None:
cpp += "#endif\n"