[ox] Make model type version mandatory

This commit is contained in:
Gary Talent 2022-05-29 22:21:05 -05:00
parent 3834de3318
commit c4a1655a8f
14 changed files with 89 additions and 76 deletions

View File

@ -28,9 +28,11 @@ class FileAddress {
public:
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
static constexpr auto TypeVersion = 1;
union Data {
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress.Data";
static constexpr auto TypeVersion = 1;
char *path = nullptr;
const char *constPath;
uint64_t inode;
@ -129,8 +131,14 @@ constexpr const char *getModelTypeName<FileAddress>() noexcept {
template<typename T>
constexpr Error model(T *io, FileAddress::Data *obj) noexcept {
io->template setTypeInfo<FileAddress::Data>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
String dummy;
oxReturnError(io->field("path", &dummy));
oxReturnError(io->field("constPath", &dummy));
} else {
oxReturnError(io->field("path", SerStr(&obj->path)));
oxReturnError(io->field("constPath", SerStr(&obj->path)));
}
oxReturnError(io->field("inode", &obj->inode));
return OxError(0);
}
@ -138,10 +146,16 @@ constexpr Error model(T *io, FileAddress::Data *obj) noexcept {
template<typename T>
constexpr Error model(T *io, FileAddress *fa) noexcept {
io->template setTypeInfo<FileAddress>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
int8_t type = 0;
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, 0)));
} else {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return OxError(0);
}

View File

@ -95,9 +95,7 @@ class MetalClawReader {
StringLength stringLength(const char *name) noexcept;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo() noexcept;
constexpr void setTypeInfo(const char *name, int fields) noexcept;
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept;
/**
* Returns a MetalClawReader to parse a child object.
@ -237,7 +235,7 @@ Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) noexc
// read the list
if (valLen >= len) {
auto reader = child("");
reader.setTypeInfo("List", static_cast<int>(len));
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(reader.field("", &val[i]));
}
@ -264,7 +262,7 @@ Error MetalClawReader::field(const char*, HashMap<String, T> *val) noexcept {
m_buffIt += bytesRead;
// read the list
auto reader = child("");
reader.setTypeInfo("List", static_cast<int>(len));
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = reader.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
@ -292,7 +290,7 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
// read the list
auto reader = child("");
reader.setTypeInfo("List", static_cast<int>(len));
reader.setTypeInfo("List", 0, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
T val;
oxReturnError(reader.field("", &val));
@ -305,11 +303,7 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
}
template<typename T>
constexpr void MetalClawReader::setTypeInfo() noexcept {
setTypeInfo(ModelTypeName_v<T>, countFields<T>());
}
constexpr void MetalClawReader::setTypeInfo(const char*, int fields) noexcept {
constexpr void MetalClawReader::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields;
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
m_fieldPresence.setFields(fields);

View File

@ -16,6 +16,7 @@
union TestUnion {
static constexpr auto TypeName = "TestUnion";
static constexpr auto TypeVersion = 1;
bool Bool;
uint32_t Int = 5;
char CString[32];
@ -23,6 +24,7 @@ union TestUnion {
struct TestStructNest {
static constexpr auto TypeName = "TestStructNest";
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> BString = "";
@ -30,6 +32,7 @@ struct TestStructNest {
struct TestStruct {
static constexpr auto TypeName = "TestStruct";
static constexpr auto TypeVersion = 1;
bool Bool = false;
int32_t Int = 0;
int32_t Int1 = 0;

View File

@ -77,7 +77,7 @@ class MetalClawWriter {
Error field(const char*, UnionView<U> val) noexcept;
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int fields = countFields<T>()) noexcept;
void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept;
[[nodiscard]]
std::size_t size() const noexcept;
@ -171,7 +171,7 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
writer.setTypeInfo<T>("List", len);
writer.setTypeInfo<T>("List", 0, len);
// write the array
for (std::size_t i = 0; i < len; i++) {
@ -205,7 +205,7 @@ Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
// double len for both key and value
writer.setTypeInfo("Map", len * 2);
writer.setTypeInfo("Map", 0, len * 2);
// write the array
for (std::size_t i = 0; i < len; i++) {
@ -245,7 +245,7 @@ Error MetalClawWriter::appendInteger(I val) noexcept {
}
template<typename T>
void MetalClawWriter::setTypeInfo(const char*, int fields) noexcept {
void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields;
m_fieldPresence.setFields(fields);
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());

View File

@ -85,6 +85,7 @@ struct DescriptorType {
static constexpr auto TypeVersion = 2;
String typeName;
int typeVersion = 0;
PrimitiveType primitiveType = PrimitiveType::UnsignedInteger;
// fieldList only applies to structs
FieldList fieldList;
@ -117,6 +118,7 @@ template<typename T>
constexpr Error model(T *io, DescriptorType *type) noexcept {
io->template setTypeInfo<DescriptorType>();
oxReturnError(io->field("typeName", &type->typeName));
oxReturnError(io->field("typeVersion", &type->typeVersion));
if constexpr(ox_strcmp(T::opType(), "Reflect") == 0) {
uint8_t pt = 0;
oxReturnError(io->field("primitiveType", &pt));
@ -148,7 +150,7 @@ class TypeDescReader;
template<typename T>
constexpr Error model(TypeDescReader<T> *io, DescriptorField *field) noexcept {
io->template setTypeInfo<DescriptorField>(DescriptorField::TypeName, 4);
io->template setTypeInfo<DescriptorField>(DescriptorField::TypeName, DescriptorField::TypeVersion, 4);
oxReturnError(io->field("typeName", &field->typeName));
auto &typeStore = io->typeStore();
auto &[type, err] = typeStore->at(field->typeName).value;

View File

@ -59,7 +59,7 @@ class TypeDescWriter {
constexpr Error field(const char *name, T *val) noexcept;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int fields = countFields<T>()) noexcept;
constexpr void setTypeInfo(const char *name = T::TypeName, int fields = ModelFieldCount_v<T>) noexcept;
[[nodiscard]]
constexpr DescriptorType *definition() noexcept {

View File

@ -15,29 +15,31 @@
namespace ox {
namespace detail {
template<typename T>
class FieldCounter {
public:
int fields = 0;
template<typename U = std::nullptr_t>
constexpr void setTypeInfo(const char* = "", int = 0) {
constexpr void setTypeInfo(const char * = "", int = 0, int = 0) {
}
template<typename U>
constexpr ox::Error field(const char*, U) noexcept {
constexpr ox::Error field(const char *, U) noexcept {
++fields;
return OxError(0);
}
template<typename U>
constexpr ox::Error field(const char*, U, std::size_t) noexcept {
constexpr ox::Error field(const char *, U, std::size_t) noexcept {
++fields;
return OxError(0);
}
template<typename U, typename Handler>
constexpr Error field(const char*, Handler) {
constexpr Error field(const char *, Handler) {
++fields;
return OxError(0);
}
@ -47,21 +49,16 @@ class FieldCounter {
}
};
template<typename T>
constexpr int countFields() noexcept {
if (std::is_constant_evaluated()) {
auto a = std::allocator<T>();
auto t = a.allocate(1);
FieldCounter<T> c;
oxIgnoreError(model(&c, t));
a.deallocate(t, 1);
return c.fields;
} else {
T t;
FieldCounter<T> c;
oxIgnoreError(model(&c, &t));
return c.fields;
}
}
template<typename T>
constexpr auto ModelFieldCount_v = [] {
auto a = std::allocator<T>();
auto t = a.allocate(1);
detail::FieldCounter<T> c;
oxAssert(model(&c, t), "Count failed");
a.deallocate(t, 1);
return c.fields;
}();
}

View File

@ -52,7 +52,7 @@ class MemberList {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = countFields<T>()) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = ModelFieldCount_v<T>) noexcept {
}
[[nodiscard]]
@ -172,7 +172,7 @@ class Mover {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = countFields<T>()) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v<T>) noexcept {
}
[[nodiscard]]
@ -262,7 +262,7 @@ class Equals {
template<typename T>
constexpr void moveModel(T *dst, T *src) noexcept {
constexpr auto size = countFields<T>();
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
@ -271,7 +271,7 @@ constexpr void moveModel(T *dst, T *src) noexcept {
template<typename T>
constexpr void copyModel(T *dst, const T *src) noexcept {
constexpr auto size = countFields<T>();
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));

View File

@ -17,7 +17,6 @@ namespace ox {
namespace OpType {
constexpr auto Read = "Read";
constexpr auto Write = "Write";
constexpr auto WriteDefinition = "WriteDefinition";
constexpr auto Reflect = "Reflect";
}
@ -35,11 +34,6 @@ constexpr Error modelWrite(T*, O*) noexcept {
return OxError(1, "Model: modelWrite not implemented");
}
template<typename T, typename O>
constexpr Error modelWriteDefinition(T*, O*) noexcept {
return OxError(1, "Model: modelWriteDefinition not implemented");
}
template<typename T, typename O>
constexpr Error modelReflect(T*, O*) noexcept {
return OxError(1, "Model: modelReflect not implemented");
@ -51,8 +45,6 @@ constexpr Error model(T *io, O *obj) noexcept {
return modelRead(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::Write) == 0) {
return modelWrite(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::WriteDefinition) == 0) {
return modelWriteDefinition(io, obj);
} else if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
return modelReflect(io, obj);
} else {

View File

@ -59,7 +59,7 @@ struct TypeInfoCatcher {
constexpr TypeInfoCatcher() noexcept = default;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion) noexcept {
constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, int = 0) noexcept {
this->name = n;
this->version = v;
}
@ -80,7 +80,7 @@ struct TypeInfoCatcher {
}
static constexpr auto opType() noexcept {
return OpType::WriteDefinition;
return OpType::Reflect;
}
};
@ -135,4 +135,7 @@ consteval auto requireModelTypeName() noexcept {
template<typename T, typename Str = const char*>
constexpr auto ModelTypeName_v = getModelTypeName<T, Str>();
template<typename T, typename Str = const char*>
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
}

View File

@ -17,7 +17,7 @@ namespace ox {
template<typename Reader, typename T>
class DataWalker {
template<typename ReaderBase, typename FH>
friend Error parseField(const DescriptorField &field, ReaderBase *rdr, DataWalker<ReaderBase, FH> *walker) noexcept;
friend constexpr Error parseField(const DescriptorField &field, ReaderBase *rdr, DataWalker<ReaderBase, FH> *walker) noexcept;
private:
Vector<const DescriptorType*> m_typeStack;
@ -26,36 +26,36 @@ class DataWalker {
Vector<String> m_typePath;
public:
DataWalker(DescriptorType *type, T fieldHandler) noexcept;
constexpr DataWalker(DescriptorType *type, T fieldHandler) noexcept;
Result<const DescriptorType*> type() const noexcept;
constexpr Result<const DescriptorType*> type() const noexcept;
Error read(const DescriptorField&, Reader *rdr) noexcept;
constexpr Error read(const DescriptorField&, Reader *rdr) noexcept;
protected:
void pushNamePath(const FieldName &fn) noexcept;
constexpr void pushNamePath(const FieldName &fn) noexcept;
void popNamePath() noexcept;
constexpr void popNamePath() noexcept;
void pushType(const DescriptorType *type) noexcept;
constexpr void pushType(const DescriptorType *type) noexcept;
void popType() noexcept;
constexpr void popType() noexcept;
};
template<typename Reader, typename T>
DataWalker<Reader, T>::DataWalker(DescriptorType *type, T fieldHandler) noexcept: m_fieldHandler(fieldHandler) {
constexpr DataWalker<Reader, T>::DataWalker(DescriptorType *type, T fieldHandler) noexcept: m_fieldHandler(fieldHandler) {
m_typeStack.push_back(type);
}
template<typename Reader, typename T>
Result<const DescriptorType*> DataWalker<Reader, T>::type() const noexcept {
constexpr Result<const DescriptorType*> DataWalker<Reader, T>::type() const noexcept {
oxRequire(out, m_typeStack.back());
return out;
}
template<typename Reader, typename T>
Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rdr) noexcept {
constexpr Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rdr) noexcept {
// get const ref of paths
const auto &pathCr = m_path;
const auto &typePathCr = m_typePath;
@ -63,33 +63,33 @@ Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rdr) noexcep
}
template<typename Reader, typename T>
void DataWalker<Reader, T>::pushNamePath(const FieldName &fn) noexcept {
constexpr void DataWalker<Reader, T>::pushNamePath(const FieldName &fn) noexcept {
m_path.push_back(fn);
}
template<typename Reader, typename T>
void DataWalker<Reader, T>::popNamePath() noexcept {
constexpr void DataWalker<Reader, T>::popNamePath() noexcept {
m_path.pop_back();
}
template<typename Reader, typename T>
void DataWalker<Reader, T>::pushType(const DescriptorType *type) noexcept {
constexpr void DataWalker<Reader, T>::pushType(const DescriptorType *type) noexcept {
m_typeStack.push_back(type);
}
template<typename Reader, typename T>
void DataWalker<Reader, T>::popType() noexcept {
constexpr void DataWalker<Reader, T>::popType() noexcept {
m_typeStack.pop_back();
}
template<typename Reader, typename FH>
static Error parseField(const DescriptorField &field, Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
static constexpr Error parseField(const DescriptorField &field, Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
walker->pushNamePath(field.fieldName);
if (field.subscriptLevels) {
// add array handling
oxRequire(arrayLen, rdr->arrayLength(field.fieldName.c_str(), true));
auto child = rdr->child(field.fieldName.c_str());
child.setTypeInfo(field.fieldName.c_str(), arrayLen);
child.setTypeInfo(field.type->typeName.c_str(), field.type->typeVersion, arrayLen);
DescriptorField f(field); // create mutable copy
--f.subscriptLevels;
String subscript;
@ -134,8 +134,9 @@ template<typename Reader, typename FH>
constexpr Error model(Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
oxRequire(type, walker->type());
auto typeName = type->typeName.c_str();
auto typeVersion = type->typeVersion;
auto &fields = type->fieldList;
rdr->setTypeInfo(typeName, fields.size());
rdr->setTypeInfo(typeName, typeVersion, fields.size());
for (const auto &field : fields) {
oxReturnError(parseField(field, rdr, walker));
}
@ -143,7 +144,7 @@ constexpr Error model(Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
}
template<typename Reader, typename Handler>
Error walkModel(DescriptorType *type, const char *data, std::size_t dataLen, Handler handler) noexcept {
constexpr Error walkModel(DescriptorType *type, const char *data, std::size_t dataLen, Handler handler) noexcept {
DataWalker<Reader, Handler> walker(type, handler);
Reader rdr(reinterpret_cast<const uint8_t*>(data), dataLen);
return model(&rdr, &walker);

View File

@ -96,6 +96,10 @@ class OrganicClawReader {
constexpr void setTypeInfo(const char*, int) noexcept {
}
template<typename T = void>
constexpr void setTypeInfo(const char*, int, int) noexcept {
}
/**
* Returns a OrganicClawReader to parse a child object.
*/

View File

@ -16,6 +16,7 @@
union TestUnion {
static constexpr auto TypeName = "TestUnion";
static constexpr auto TypeVersion = 1;
bool Bool;
uint32_t Int = 5;
char String[32];
@ -23,6 +24,7 @@ union TestUnion {
struct TestStructNest {
static constexpr auto TypeName = "TestStructNest";
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> String = "";
@ -30,6 +32,7 @@ struct TestStructNest {
struct TestStruct {
static constexpr auto TypeName = "TestStruct";
static constexpr auto TypeVersion = 1;
bool Bool = false;
int32_t Int = 0;
int32_t Int1 = 0;

View File

@ -69,7 +69,7 @@ class OrganicClawWriter {
Error field(const char*, T *val) noexcept;
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = countFields<T>()) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v<T>) noexcept {
}
static constexpr auto opType() noexcept {