More overhauling of the proto layer; fluxfile ls now works.

This commit is contained in:
David Given
2025-08-18 00:37:42 +02:00
parent 9ff3e3b42a
commit 996fdbc0f5
7 changed files with 117 additions and 30 deletions

View File

@@ -264,7 +264,8 @@ static void doShowConfig()
static void doDoc() static void doDoc()
{ {
const auto fields = findAllPossibleProtoFields(globalConfig().base()->GetDescriptor()); const auto fields =
findAllPossibleProtoFields(globalConfig().base()->GetDescriptor());
for (const auto field : fields) for (const auto field : fields)
{ {
const std::string& path = field.first; const std::string& path = field.first;

View File

@@ -157,7 +157,7 @@ static ProtoField resolveProtoPath(
if (!field) if (!field)
fail(); fail();
return ProtoField(message, field, index); return ProtoField(path, message, field, index);
} }
ProtoField makeProtoPath( ProtoField makeProtoPath(
@@ -292,6 +292,10 @@ void ProtoField::set(const std::string& value)
parseEnum(_field, value)); parseEnum(_field, value));
break; break;
case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
error("'{}' is a message and can't be directly set",
_field->name());
default: default:
error("can't set this config value type"); error("can't set this config value type");
} }
@@ -339,6 +343,11 @@ void ProtoField::set(const std::string& value)
_message, _field, parseEnum(_field, value)); _message, _field, parseEnum(_field, value));
break; break;
case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
error("'{}[{}]' is a message and can't be directly set",
_field->name(),
_index);
default: default:
error("can't set this config value type"); error("can't set this config value type");
} }
@@ -384,7 +393,8 @@ std::string ProtoField::get() const
return reflection->GetRepeatedString(*_message, _field, _index); return reflection->GetRepeatedString(*_message, _field, _index);
case google::protobuf::FieldDescriptor::TYPE_MESSAGE: case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
error("cannot fetch message value"); error("'{}' is a message and can't be directly fetched",
_field->name());
default: default:
error("unknown field type when fetching repeated field '{}'", error("unknown field type when fetching repeated field '{}'",
@@ -431,7 +441,9 @@ std::string ProtoField::get() const
} }
case google::protobuf::FieldDescriptor::TYPE_MESSAGE: 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: default:
error("unknown field type when fetching '{}'", _field->name()); 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, void setProtoByString(google::protobuf::Message* message,
const std::string& path, const std::string& path,
const std::string& value) const std::string& value)
@@ -494,17 +548,16 @@ findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor)
return fields; return fields;
} }
std::map<std::string, const google::protobuf::FieldDescriptor*> std::vector<ProtoField> findAllProtoFields(google::protobuf::Message* message)
findAllProtoFields(const google::protobuf::Message& message)
{ {
std::map<std::string, const google::protobuf::FieldDescriptor*> allFields; std::vector<ProtoField> allFields;
std::function<void(const google::protobuf::Message&, const std::string&)> std::function<void(google::protobuf::Message*, const std::string&)>
recurse = [&](auto& message, const auto& name) recurse = [&](auto* message, const auto& name)
{ {
const auto* reflection = message.GetReflection(); const auto* reflection = message->GetReflection();
std::vector<const google::protobuf::FieldDescriptor*> fields; std::vector<const google::protobuf::FieldDescriptor*> fields;
reflection->ListFields(message, &fields); reflection->ListFields(*message, &fields);
for (const auto* f : fields) for (const auto* f : fields)
{ {
@@ -515,22 +568,23 @@ findAllProtoFields(const google::protobuf::Message& message)
if (f->label() == google::protobuf::FieldDescriptor::LABEL_REPEATED) 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); const auto n = fmt::format("{}[{}]", basename, i);
if (shouldRecurse(f)) if (shouldRecurse(f))
recurse( recurse(
reflection->GetRepeatedMessage(message, f, i), n); reflection->MutableRepeatedMessage(message, f, i),
n);
else else
allFields[n] = f; allFields.push_back(ProtoField(n, message, f, i));
} }
} }
else else
{ {
if (shouldRecurse(f)) if (shouldRecurse(f))
recurse(reflection->GetMessage(message, f), basename); recurse(reflection->MutableMessage(message, f), basename);
else else
allFields[basename] = f; allFields.push_back(ProtoField(basename, message, f));
} }
} }
}; };

View File

@@ -17,9 +17,11 @@ public:
class ProtoField class ProtoField
{ {
public: public:
ProtoField(google::protobuf::Message* message, ProtoField(const std::string& path,
google::protobuf::Message* message,
const google::protobuf::FieldDescriptor* field, const google::protobuf::FieldDescriptor* field,
int index): int index = -1):
_path(path),
_message(message), _message(message),
_field(field), _field(field),
_index(index) _index(index)
@@ -28,11 +30,24 @@ public:
void set(const std::string& value); void set(const std::string& value);
std::string get() const; std::string get() const;
google::protobuf::Message* getMessage() const;
std::string getBytes() const;
bool operator==(const ProtoField& other) const = default; bool operator==(const ProtoField& other) const = default;
std::strong_ordering 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: private:
std::string _path;
google::protobuf::Message* _message; google::protobuf::Message* _message;
const google::protobuf::FieldDescriptor* _field; const google::protobuf::FieldDescriptor* _field;
int _index; int _index;
@@ -56,8 +71,8 @@ extern std::set<unsigned> iterate(unsigned start, unsigned count);
extern std::map<std::string, const google::protobuf::FieldDescriptor*> extern std::map<std::string, const google::protobuf::FieldDescriptor*>
findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor); findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor);
extern std::map<std::string, const google::protobuf::FieldDescriptor*> extern std::vector<ProtoField> findAllProtoFields(
findAllProtoFields(const google::protobuf::Message& message); google::protobuf::Message* message);
template <class T> template <class T>
static inline const T parseProtoBytes(const std::string_view& bytes) static inline const T parseProtoBytes(const std::string_view& bytes)

View File

@@ -29,7 +29,8 @@ static unsigned getTrackStep()
{ {
case DRIVETYPE_40TRACK: case DRIVETYPE_40TRACK:
error( 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"); "drive");
case DRIVETYPE_80TRACK: case DRIVETYPE_80TRACK:
@@ -37,7 +38,8 @@ static unsigned getTrackStep()
case DRIVETYPE_APPLE2: case DRIVETYPE_APPLE2:
error( 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"); "drive");
} }
} }

View File

@@ -24,14 +24,26 @@ int mainFluxfileLs(int argc, const char* argv[])
fmt::print("Contents of {}:\n", filename); fmt::print("Contents of {}:\n", filename);
FluxFileProto f = loadFl2File(filename); FluxFileProto f = loadFl2File(filename);
auto fields = findAllProtoFields(f); auto fields = findAllProtoFields(&f);
std::set<std::string, doj::alphanum_less<std::string>> fieldsSorted; std::ranges::sort(fields,
for (const auto& e : fields) [](const auto& o1, const auto& o2)
fieldsSorted.insert(e.first); {
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());
} }
} }

View File

@@ -68,6 +68,7 @@ export(
"lib/config", "lib/config",
"lib/core", "lib/core",
"lib/fluxsource+proto_lib", "lib/fluxsource+proto_lib",
"dep/alphanum",
], ],
), ),
) )

View File

@@ -4,6 +4,7 @@
#include "lib/config/config.pb.h" #include "lib/config/config.pb.h"
#include "lib/config/proto.h" #include "lib/config/proto.h"
#include "snowhouse/snowhouse.h" #include "snowhouse/snowhouse.h"
#include "dep/alphanum/alphanum.h"
#include <google/protobuf/text_format.h> #include <google/protobuf/text_format.h>
#include <assert.h> #include <assert.h>
#include <regex> #include <regex>
@@ -206,10 +207,11 @@ static void test_findallfields(void)
if (!google::protobuf::TextFormat::MergeFromString(cleanup(s), &proto)) if (!google::protobuf::TextFormat::MergeFromString(cleanup(s), &proto))
error("couldn't load test proto"); error("couldn't load test proto");
auto fields = findAllProtoFields(proto); auto fields = findAllProtoFields(&proto);
std::vector<std::string> fieldNames; std::vector<std::string> fieldNames;
for (const auto& e : fields) for (const auto& e : fields)
fieldNames.push_back(e.first); fieldNames.push_back(e.path());
std::ranges::sort(fieldNames, doj::alphanum_less<std::string>());
AssertThat(fieldNames, AssertThat(fieldNames,
Equals(std::vector<std::string>{"d", Equals(std::vector<std::string>{"d",