From 9ff3e3b42a93b706bbc9ff3eef25ee1d6a3efd43 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 17 Aug 2025 23:04:14 +0200 Subject: [PATCH] Finally make the getters and setters work with repeated fields. --- lib/config/proto.cc | 223 ++++++++++++++++++++++++-------------------- lib/config/proto.h | 26 +++++- tests/proto.cc | 9 +- 3 files changed, 147 insertions(+), 111 deletions(-) diff --git a/lib/config/proto.cc b/lib/config/proto.cc index da2c24d5..dab22a13 100644 --- a/lib/config/proto.cc +++ b/lib/config/proto.cc @@ -157,7 +157,7 @@ static ProtoField resolveProtoPath( if (!field) fail(); - return std::make_tuple(message, field, index); + return ProtoField(message, field, index); } ProtoField makeProtoPath( @@ -210,207 +210,232 @@ static void updateRepeatedField( mrfr.Set(index, value); } -void setProtoFieldFromString(ProtoField& protoField, const std::string& value) +void ProtoField::set(const std::string& value) { - auto& [message, field, index] = protoField; - - const auto* reflection = message->GetReflection(); - if (field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) + const auto* reflection = _message->GetReflection(); + if (_field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { - if (index == -1) + if (_index == -1) error("field '{}' is repeated but no index is provided"); - switch (field->type()) + switch (_field->type()) { case google::protobuf::FieldDescriptor::TYPE_FLOAT: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, toFloat(value)); break; case google::protobuf::FieldDescriptor::TYPE_DOUBLE: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, toDouble(value)); break; case google::protobuf::FieldDescriptor::TYPE_INT32: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, (int32_t)toInt64(value)); break; case google::protobuf::FieldDescriptor::TYPE_INT64: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, toInt64(value)); break; case google::protobuf::FieldDescriptor::TYPE_UINT32: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, (uint32_t)toUint64(value)); break; case google::protobuf::FieldDescriptor::TYPE_UINT64: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, toUint64(value)); break; case google::protobuf::FieldDescriptor::TYPE_STRING: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, value); break; case google::protobuf::FieldDescriptor::TYPE_BOOL: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, + _message, _field), + _index, parseBoolean(value)); break; case google::protobuf::FieldDescriptor::TYPE_ENUM: updateRepeatedField( reflection->GetMutableRepeatedFieldRef( - message, field), - index, - parseEnum(field, value)); + _message, _field), + _index, + parseEnum(_field, value)); break; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - if (field->message_type() == RangeProto::descriptor()) - { - setRange((RangeProto*)reflection->MutableRepeatedMessage( - message, field, index), - value); - break; - } - /* fall through */ default: error("can't set this config value type"); } } else { - if (index != -1) + if (_index != -1) error("field '{}' is not repeated but an index is provided"); - switch (field->type()) + switch (_field->type()) { case google::protobuf::FieldDescriptor::TYPE_FLOAT: - reflection->SetFloat(message, field, toFloat(value)); + reflection->SetFloat(_message, _field, toFloat(value)); break; case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - reflection->SetDouble(message, field, toDouble(value)); + reflection->SetDouble(_message, _field, toDouble(value)); break; case google::protobuf::FieldDescriptor::TYPE_INT32: - reflection->SetInt32(message, field, toInt64(value)); + reflection->SetInt32(_message, _field, toInt64(value)); break; case google::protobuf::FieldDescriptor::TYPE_INT64: - reflection->SetInt64(message, field, toInt64(value)); + reflection->SetInt64(_message, _field, toInt64(value)); break; case google::protobuf::FieldDescriptor::TYPE_UINT32: - reflection->SetUInt32(message, field, toUint64(value)); + reflection->SetUInt32(_message, _field, toUint64(value)); break; case google::protobuf::FieldDescriptor::TYPE_UINT64: - reflection->SetUInt64(message, field, toUint64(value)); + reflection->SetUInt64(_message, _field, toUint64(value)); break; case google::protobuf::FieldDescriptor::TYPE_STRING: - reflection->SetString(message, field, value); + reflection->SetString(_message, _field, value); break; case google::protobuf::FieldDescriptor::TYPE_BOOL: - reflection->SetBool(message, field, parseBoolean(value)); + reflection->SetBool(_message, _field, parseBoolean(value)); break; case google::protobuf::FieldDescriptor::TYPE_ENUM: - reflection->SetEnumValue(message, field, parseEnum(field, value)); + reflection->SetEnumValue( + _message, _field, parseEnum(_field, value)); break; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - if (field->message_type() == RangeProto::descriptor()) - { - setRange( - (RangeProto*)reflection->MutableMessage(message, field), - value); - break; - } - if (field->containing_oneof() && value.empty()) - { - reflection->MutableMessage(message, field); - break; - } - /* fall through */ default: error("can't set this config value type"); } } } -std::string getProtoFieldValue(ProtoField& protoField) +std::string ProtoField::get() const { - auto& [message, field, index] = protoField; - - const auto* reflection = message->GetReflection(); - switch (field->type()) + const auto* reflection = _message->GetReflection(); + if (_field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return fmt::format("{}", reflection->GetFloat(*message, field)); + if (_index == -1) + error("field '{}' is repeated but no index is provided", + _field->name()); - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return fmt::format("{}", reflection->GetDouble(*message, field)); - - case google::protobuf::FieldDescriptor::TYPE_INT32: - return std::to_string(reflection->GetInt32(*message, field)); - - case google::protobuf::FieldDescriptor::TYPE_INT64: - return std::to_string(reflection->GetInt64(*message, field)); - - case google::protobuf::FieldDescriptor::TYPE_UINT32: - return std::to_string(reflection->GetUInt32(*message, field)); - - case google::protobuf::FieldDescriptor::TYPE_UINT64: - return std::to_string(reflection->GetUInt64(*message, field)); - - case google::protobuf::FieldDescriptor::TYPE_STRING: - return reflection->GetString(*message, field); - - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return std::to_string(reflection->GetBool(*message, field)); - - case google::protobuf::FieldDescriptor::TYPE_ENUM: + switch (_field->type()) { - const auto* enumvalue = reflection->GetEnum(*message, field); - return enumvalue->name(); + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + return fmt::format("{:g}", + reflection->GetRepeatedFloat(*_message, _field, _index)); + + case google::protobuf::FieldDescriptor::TYPE_DOUBLE: + return fmt::format("{:g}", + reflection->GetRepeatedDouble(*_message, _field, _index)); + + case google::protobuf::FieldDescriptor::TYPE_INT32: + return std::to_string( + reflection->GetRepeatedInt32(*_message, _field, _index)); + + case google::protobuf::FieldDescriptor::TYPE_INT64: + return std::to_string( + reflection->GetRepeatedInt64(*_message, _field, _index)); + + case google::protobuf::FieldDescriptor::TYPE_UINT32: + return std::to_string( + reflection->GetRepeatedUInt32(*_message, _field, _index)); + + case google::protobuf::FieldDescriptor::TYPE_UINT64: + return std::to_string( + reflection->GetRepeatedUInt64(*_message, _field, _index)); + + case google::protobuf::FieldDescriptor::TYPE_STRING: + return reflection->GetRepeatedString(*_message, _field, _index); + + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + error("cannot fetch message value"); + + default: + error("unknown field type when fetching repeated field '{}'", + _field->name()); } + } + else + { + if (_index != -1) + error("field '{}' is not repeated but an index is provided", + _field->name()); + switch (_field->type()) + { + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + return fmt::format( + "{:g}", reflection->GetFloat(*_message, _field)); - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - error("cannot fetch message value"); + case google::protobuf::FieldDescriptor::TYPE_DOUBLE: + return fmt::format( + "{:g}", reflection->GetDouble(*_message, _field)); - default: - error("unknown field type when fetching"); + case google::protobuf::FieldDescriptor::TYPE_INT32: + return std::to_string(reflection->GetInt32(*_message, _field)); + + case google::protobuf::FieldDescriptor::TYPE_INT64: + return std::to_string(reflection->GetInt64(*_message, _field)); + + case google::protobuf::FieldDescriptor::TYPE_UINT32: + return std::to_string(reflection->GetUInt32(*_message, _field)); + + case google::protobuf::FieldDescriptor::TYPE_UINT64: + return std::to_string(reflection->GetUInt64(*_message, _field)); + + case google::protobuf::FieldDescriptor::TYPE_STRING: + return reflection->GetString(*_message, _field); + + case google::protobuf::FieldDescriptor::TYPE_BOOL: + return std::to_string(reflection->GetBool(*_message, _field)); + + case google::protobuf::FieldDescriptor::TYPE_ENUM: + { + const auto* enumvalue = reflection->GetEnum(*_message, _field); + return enumvalue->name(); + } + + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + error("cannot fetch message value"); + + default: + error("unknown field type when fetching '{}'", _field->name()); + } } } @@ -418,15 +443,13 @@ void setProtoByString(google::protobuf::Message* message, const std::string& path, const std::string& value) { - ProtoField protoField = makeProtoPath(message, path); - setProtoFieldFromString(protoField, value); + makeProtoPath(message, path).set(value); } std::string getProtoByString( google::protobuf::Message* message, const std::string& path) { - ProtoField protoField = findProtoPath(message, path); - return getProtoFieldValue(protoField); + return findProtoPath(message, path).get(); } std::set iterate(unsigned start, unsigned count) diff --git a/lib/config/proto.h b/lib/config/proto.h index 6b0a3ef1..60274cae 100644 --- a/lib/config/proto.h +++ b/lib/config/proto.h @@ -14,9 +14,29 @@ public: } }; -typedef std::tuple - ProtoField; +class ProtoField +{ +public: + ProtoField(google::protobuf::Message* message, + const google::protobuf::FieldDescriptor* field, + int index): + _message(message), + _field(field), + _index(index) + { + } + + void set(const std::string& value); + std::string get() const; + + bool operator==(const ProtoField& other) const = default; + std::strong_ordering operator<=>(const ProtoField& other) const = default; + +private: + google::protobuf::Message* _message; + const google::protobuf::FieldDescriptor* _field; + int _index; +}; extern ProtoField makeProtoPath( google::protobuf::Message* message, const std::string& path); diff --git a/tests/proto.cc b/tests/proto.cc index 29281ceb..680ba69d 100644 --- a/tests/proto.cc +++ b/tests/proto.cc @@ -157,12 +157,11 @@ static void test_fields(void) "i32", "i64", "m", - "m.r[]", + "m.r[]", "m.s", "r[]", "r[].r[]", "r[].s", - "range", "secondoption", "secondoption.r[]", "secondoption.s", @@ -201,11 +200,6 @@ static void test_findallfields(void) secondoption { s: "2" } - range { - start: 1 - step: 2 - end: 3 - } )M"; TestProto proto; @@ -225,7 +219,6 @@ static void test_findallfields(void) "m.s", "r[0].s", "r[1].s", - "range", "secondoption.s", "u32", "u64"}));