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()
{
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;

View File

@@ -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<std::string, const google::protobuf::FieldDescriptor*>
findAllProtoFields(const google::protobuf::Message& message)
std::vector<ProtoField> findAllProtoFields(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&)>
recurse = [&](auto& message, const auto& name)
std::function<void(google::protobuf::Message*, const std::string&)>
recurse = [&](auto* message, const auto& name)
{
const auto* reflection = message.GetReflection();
const auto* reflection = message->GetReflection();
std::vector<const google::protobuf::FieldDescriptor*> 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));
}
}
};

View File

@@ -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<unsigned> iterate(unsigned start, unsigned count);
extern std::map<std::string, const google::protobuf::FieldDescriptor*>
findAllPossibleProtoFields(const google::protobuf::Descriptor* descriptor);
extern std::map<std::string, const google::protobuf::FieldDescriptor*>
findAllProtoFields(const google::protobuf::Message& message);
extern std::vector<ProtoField> findAllProtoFields(
google::protobuf::Message* message);
template <class T>
static inline const T parseProtoBytes(const std::string_view& bytes)

View File

@@ -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");
}
}

View File

@@ -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<std::string, doj::alphanum_less<std::string>> 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());
}
}

View File

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

View File

@@ -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 <google/protobuf/text_format.h>
#include <assert.h>
#include <regex>
@@ -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<std::string> fieldNames;
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,
Equals(std::vector<std::string>{"d",