From 996fdbc0f5f039ddab45fdd816fcea4037848dad Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 18 Aug 2025 00:37:42 +0200 Subject: [PATCH] More overhauling of the proto layer; fluxfile ls now works. --- lib/config/flags.cc | 3 +- lib/config/proto.cc | 84 ++++++++++++++++++++++++++++++++++++-------- lib/config/proto.h | 23 +++++++++--- lib/data/layout.cc | 6 ++-- src/fe-fluxfilels.cc | 24 +++++++++---- tests/build.py | 1 + tests/proto.cc | 6 ++-- 7 files changed, 117 insertions(+), 30 deletions(-) diff --git a/lib/config/flags.cc b/lib/config/flags.cc index cf60a5a8..bc54262a 100644 --- a/lib/config/flags.cc +++ b/lib/config/flags.cc @@ -264,7 +264,8 @@ static void doShowConfig() static void doDoc() { - const auto fields = findAllPossibleProtoFields(globalConfig().base()->GetDescriptor()); + const auto fields = + findAllPossibleProtoFields(globalConfig().base()->GetDescriptor()); for (const auto field : fields) { const std::string& path = field.first; diff --git a/lib/config/proto.cc b/lib/config/proto.cc index dab22a13..f50cb97f 100644 --- a/lib/config/proto.cc +++ b/lib/config/proto.cc @@ -157,7 +157,7 @@ static ProtoField resolveProtoPath( if (!field) fail(); - return ProtoField(message, field, index); + return ProtoField(path, message, field, index); } ProtoField makeProtoPath( @@ -292,6 +292,10 @@ void ProtoField::set(const std::string& value) parseEnum(_field, value)); break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + error("'{}' is a message and can't be directly set", + _field->name()); + default: error("can't set this config value type"); } @@ -339,6 +343,11 @@ void ProtoField::set(const std::string& value) _message, _field, parseEnum(_field, value)); break; + case google::protobuf::FieldDescriptor::TYPE_MESSAGE: + error("'{}[{}]' is a message and can't be directly set", + _field->name(), + _index); + default: error("can't set this config value type"); } @@ -384,7 +393,8 @@ std::string ProtoField::get() const return reflection->GetRepeatedString(*_message, _field, _index); case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - error("cannot fetch message value"); + error("'{}' is a message and can't be directly fetched", + _field->name()); default: error("unknown field type when fetching repeated field '{}'", @@ -431,7 +441,9 @@ std::string ProtoField::get() const } case google::protobuf::FieldDescriptor::TYPE_MESSAGE: - error("cannot fetch message value"); + error("'{}[{}]' is a message and can't be directly set", + _field->name(), + _index); default: error("unknown field type when fetching '{}'", _field->name()); @@ -439,6 +451,48 @@ std::string ProtoField::get() const } } +google::protobuf::Message* ProtoField::getMessage() const +{ + const auto* reflection = _message->GetReflection(); + if (_field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) + { + if (_index == -1) + error("field '{}' is repeated but no index is provided", + _field->name()); + + return reflection->MutableRepeatedMessage(_message, _field, _index); + } + else + { + if (_index != -1) + error("field '{}' is not repeated but an index is provided", + _field->name()); + + return reflection->MutableMessage(_message, _field); + } +} + +std::string ProtoField::getBytes() const +{ + const auto* reflection = _message->GetReflection(); + if (_field->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) + { + if (_index == -1) + error("field '{}' is repeated but no index is provided", + _field->name()); + + return reflection->GetRepeatedString(*_message, _field, _index); + } + else + { + if (_index != -1) + error("field '{}' is not repeated but an index is provided", + _field->name()); + + return reflection->GetString(*_message, _field); + } +} + void setProtoByString(google::protobuf::Message* message, const std::string& path, const std::string& value) @@ -494,17 +548,16 @@ findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor) return fields; } -std::map -findAllProtoFields(const google::protobuf::Message& message) +std::vector findAllProtoFields(google::protobuf::Message* message) { - std::map allFields; + std::vector allFields; - std::function - recurse = [&](auto& message, const auto& name) + std::function + recurse = [&](auto* message, const auto& name) { - const auto* reflection = message.GetReflection(); + const auto* reflection = message->GetReflection(); std::vector fields; - reflection->ListFields(message, &fields); + reflection->ListFields(*message, &fields); for (const auto* f : fields) { @@ -515,22 +568,23 @@ findAllProtoFields(const google::protobuf::Message& message) if (f->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) { - for (int i = 0; i < reflection->FieldSize(message, f); i++) + for (int i = 0; i < reflection->FieldSize(*message, f); i++) { const auto n = fmt::format("{}[{}]", basename, i); if (shouldRecurse(f)) recurse( - reflection->GetRepeatedMessage(message, f, i), n); + reflection->MutableRepeatedMessage(message, f, i), + n); else - allFields[n] = f; + allFields.push_back(ProtoField(n, message, f, i)); } } else { if (shouldRecurse(f)) - recurse(reflection->GetMessage(message, f), basename); + recurse(reflection->MutableMessage(message, f), basename); else - allFields[basename] = f; + allFields.push_back(ProtoField(basename, message, f)); } } }; diff --git a/lib/config/proto.h b/lib/config/proto.h index 60274cae..d529a414 100644 --- a/lib/config/proto.h +++ b/lib/config/proto.h @@ -17,9 +17,11 @@ public: class ProtoField { public: - ProtoField(google::protobuf::Message* message, + ProtoField(const std::string& path, + google::protobuf::Message* message, const google::protobuf::FieldDescriptor* field, - int index): + int index = -1): + _path(path), _message(message), _field(field), _index(index) @@ -28,11 +30,24 @@ public: void set(const std::string& value); std::string get() const; + google::protobuf::Message* getMessage() const; + std::string getBytes() const; bool operator==(const ProtoField& other) const = default; std::strong_ordering operator<=>(const ProtoField& other) const = default; + const std::string& path() const + { + return _path; + } + + const google::protobuf::FieldDescriptor* descriptor() const + { + return _field; + } + private: + std::string _path; google::protobuf::Message* _message; const google::protobuf::FieldDescriptor* _field; int _index; @@ -56,8 +71,8 @@ extern std::set iterate(unsigned start, unsigned count); extern std::map findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor); -extern std::map -findAllProtoFields(const google::protobuf::Message& message); +extern std::vector findAllProtoFields( + google::protobuf::Message* message); template static inline const T parseProtoBytes(const std::string_view& bytes) diff --git a/lib/data/layout.cc b/lib/data/layout.cc index 82eef8a8..9fc1a6f7 100644 --- a/lib/data/layout.cc +++ b/lib/data/layout.cc @@ -29,7 +29,8 @@ static unsigned getTrackStep() { case DRIVETYPE_40TRACK: error( - "you can't read/write an 80 track image from/to a 40 track " + "you can't read/write an 80 track image from/to a 40 " + "track " "drive"); case DRIVETYPE_80TRACK: @@ -37,7 +38,8 @@ static unsigned getTrackStep() case DRIVETYPE_APPLE2: error( - "you can't read/write an 80 track image from/to an Apple II " + "you can't read/write an 80 track image from/to an " + "Apple II " "drive"); } } diff --git a/src/fe-fluxfilels.cc b/src/fe-fluxfilels.cc index edf829f0..cbbaaf99 100644 --- a/src/fe-fluxfilels.cc +++ b/src/fe-fluxfilels.cc @@ -24,14 +24,26 @@ int mainFluxfileLs(int argc, const char* argv[]) fmt::print("Contents of {}:\n", filename); FluxFileProto f = loadFl2File(filename); - auto fields = findAllProtoFields(f); - std::set> fieldsSorted; - for (const auto& e : fields) - fieldsSorted.insert(e.first); + auto fields = findAllProtoFields(&f); + std::ranges::sort(fields, + [](const auto& o1, const auto& o2) + { + return doj::alphanum_comp(o1.path(), o2.path()) < 0; + }); - for (const auto& e : fieldsSorted) + for (const auto& pf : fields) { - fmt::print("{}: {}\n", e, getProtoByString(&f, e)); + auto path = pf.path(); + if (pf.descriptor()->options().GetExtension(::isflux)) + { + Fluxmap fluxmap(pf.getBytes()); + fmt::print("{}: {:0.3f} ms of flux in {} bytes\n", + path, + fluxmap.duration() / 1000000.0, + fluxmap.bytes()); + } + else + fmt::print("{}: {}\n", path, pf.get()); } } diff --git a/tests/build.py b/tests/build.py index f5f0da8a..f062658c 100644 --- a/tests/build.py +++ b/tests/build.py @@ -68,6 +68,7 @@ export( "lib/config", "lib/core", "lib/fluxsource+proto_lib", + "dep/alphanum", ], ), ) diff --git a/tests/proto.cc b/tests/proto.cc index 680ba69d..991969ef 100644 --- a/tests/proto.cc +++ b/tests/proto.cc @@ -4,6 +4,7 @@ #include "lib/config/config.pb.h" #include "lib/config/proto.h" #include "snowhouse/snowhouse.h" +#include "dep/alphanum/alphanum.h" #include #include #include @@ -206,10 +207,11 @@ static void test_findallfields(void) if (!google::protobuf::TextFormat::MergeFromString(cleanup(s), &proto)) error("couldn't load test proto"); - auto fields = findAllProtoFields(proto); + auto fields = findAllProtoFields(&proto); std::vector fieldNames; for (const auto& e : fields) - fieldNames.push_back(e.first); + fieldNames.push_back(e.path()); + std::ranges::sort(fieldNames, doj::alphanum_less()); AssertThat(fieldNames, Equals(std::vector{"d",