[ox] Add support for unions to model and mc

This commit is contained in:
Gary Talent 2020-04-13 02:28:38 -05:00
parent 82a07737ec
commit 1d07890668
14 changed files with 329 additions and 195 deletions

View File

@ -7,6 +7,7 @@
*/
#include <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>
#include "err.hpp"
#include "presenceindicator.hpp"
@ -40,6 +41,7 @@ Error FieldPresenceIndicator::set(std::size_t i, bool on) {
void FieldPresenceIndicator::setFields(int fields) noexcept {
m_fields = fields;
m_maskLen = (fields / 8 + 1) - (fields % 8 == 0);
}
int FieldPresenceIndicator::getFields() const noexcept {

View File

@ -22,9 +22,9 @@ class FieldPresenceIndicator {
public:
FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen);
ValErr<bool> get(std::size_t i) const;
[[nodiscard]] ValErr<bool> get(std::size_t i) const;
Error set(std::size_t i, bool on);
[[nodiscard]] Error set(std::size_t i, bool on);
void setFields(int) noexcept;

View File

@ -14,17 +14,19 @@
namespace ox {
MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent): m_fieldPresence(buff, buffLen) {
m_buff = buff;
m_buffLen = buffLen;
m_parent = parent;
MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, int unionIdx, MetalClawReader *parent) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff),
m_parent(parent) {
}
MetalClawReader::~MetalClawReader() {
MetalClawReader::~MetalClawReader() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
//oxAssert(m_field == m_fields, "MetalClawReader: incorrect fields number given");
oxAssert(m_field == m_fields, "MetalClawReader: incorrect fields number given");
}
Error MetalClawReader::field(const char*, int8_t *val) {
@ -61,42 +63,48 @@ Error MetalClawReader::field(const char*, uint64_t *val) {
}
Error MetalClawReader::field(const char*, bool *val) {
auto valErr = m_fieldPresence.get(m_field++);
*val = valErr.value;
return valErr.error;
if (m_unionIdx == -1 || m_unionIdx == m_field) {
auto valErr = m_fieldPresence.get(m_field);
*val = valErr.value;
oxReturnError(valErr.error);
}
++m_field;
return OxError(0);
}
Error MetalClawReader::field(const char*, SerStr val) {
if (m_fieldPresence.get(m_field++)) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
// read the string
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(val.data(), &m_buff[m_buffIt], size);
val.data()[size] = 0;
m_buffIt += size;
} else {
if ((m_unionIdx == -1 || m_unionIdx == m_field)) {
if (m_fieldPresence.get(m_field)) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
// read the string
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(val.data(), &m_buff[m_buffIt], size);
val.data()[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} else {
return OxError(MC_OUTBUFFENDED);
}
} else {
return OxError(MC_OUTBUFFENDED);
val.data()[0] = 0;
}
} else {
val.data()[0] = 0;
}
++m_field;
return OxError(0);
}
[[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) {
if (m_fieldPresence.get(m_field)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
@ -112,7 +120,7 @@ Error MetalClawReader::field(const char*, SerStr val) {
}
[[nodiscard]] StringLength MetalClawReader::stringLength(const char*) {
if (m_fieldPresence.get(m_field)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
@ -121,15 +129,8 @@ Error MetalClawReader::field(const char*, SerStr val) {
return 0;
}
void MetalClawReader::setTypeInfo(const char*, int fields) {
m_fields = fields;
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
m_fieldPresence.setFields(fields);
m_fieldPresence.setMaxLen(m_buffIt);
}
MetalClawReader MetalClawReader::child(const char*) {
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, this);
MetalClawReader MetalClawReader::child(const char*, int unionIdx) {
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
}
bool MetalClawReader::fieldPresent(const char*) const {

View File

@ -28,50 +28,54 @@ class MetalClawReader {
FieldPresenceIndicator m_fieldPresence;
int m_fields = 0;
int m_field = 0;
int m_unionIdx = -1;
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
uint8_t *m_buff = nullptr;
MetalClawReader *m_parent = nullptr;
public:
MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent = nullptr);
MetalClawReader(uint8_t *buff, std::size_t buffLen, int unionIdx = -1, MetalClawReader *parent = nullptr) noexcept;
~MetalClawReader();
~MetalClawReader() noexcept;
Error field(const char*, int8_t *val);
Error field(const char*, int16_t *val);
Error field(const char*, int32_t *val);
Error field(const char*, int64_t *val);
[[nodiscard]] Error field(const char*, int8_t *val);
[[nodiscard]] Error field(const char*, int16_t *val);
[[nodiscard]] Error field(const char*, int32_t *val);
[[nodiscard]] Error field(const char*, int64_t *val);
Error field(const char*, uint8_t *val);
Error field(const char*, uint16_t *val);
Error field(const char*, uint32_t *val);
Error field(const char*, uint64_t *val);
[[nodiscard]] Error field(const char*, uint8_t *val);
[[nodiscard]] Error field(const char*, uint16_t *val);
[[nodiscard]] Error field(const char*, uint32_t *val);
[[nodiscard]] Error field(const char*, uint64_t *val);
Error field(const char*, bool *val);
[[nodiscard]] Error field(const char*, bool *val);
// array handler
template<typename T>
Error field(const char*, T *val, std::size_t len);
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
// array handler, with callback to allow handling individual elements
template<typename T, typename Handler>
Error field(const char*, Handler handler);
[[nodiscard]] Error field(const char*, Handler handler);
// array handler, with callback to allow handling individual elements
template<typename T, typename Handler>
Error field(const char*, Handler handler, ArrayLength len);
[[nodiscard]] Error field(const char*, Handler handler, ArrayLength len);
template<typename T>
Error field(const char*, ox::Vector<T> *val);
[[nodiscard]] Error field(const char*, ox::Vector<T> *val);
template<typename T>
Error field(const char*, T *val);
[[nodiscard]] Error field(const char*, T *val);
template<typename U>
[[nodiscard]] Error field(const char*, UnionView<U> val);
template<std::size_t L>
Error field(const char*, ox::BString<L> *val);
[[nodiscard]] Error field(const char*, ox::BString<L> *val);
Error field(const char*, SerStr val);
[[nodiscard]] Error field(const char*, SerStr val);
/**
* Reads an array length from the current location in the buffer.
@ -84,12 +88,13 @@ class MetalClawReader {
*/
[[nodiscard]] StringLength stringLength(const char *name);
void setTypeInfo(const char *name, int fields);
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
/**
* Returns a MetalClawReader to parse a child object.
*/
[[nodiscard]] MetalClawReader child(const char *name);
[[nodiscard]] MetalClawReader child(const char *name, int unionIdx = -1);
/**
* Indicates whether or not the next field to be read is present.
@ -109,16 +114,27 @@ class MetalClawReader {
private:
template<typename I>
Error readInteger(I *val);
[[nodiscard]] Error readInteger(I *val);
};
template<typename T>
Error MetalClawReader::field(const char*, T *val) {
if (val && m_fieldPresence.get(m_field++)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val && m_fieldPresence.get(m_field)) {
auto reader = child("");
oxReturnError(model(&reader, val));
}
++m_field;
return OxError(0);
}
template<typename U>
Error MetalClawReader::field(const char*, UnionView<U> val) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get() && m_fieldPresence.get(m_field)) {
auto reader = child("", val.idx());
oxReturnError(model(&reader, val.get()));
}
++m_field;
return OxError(0);
}
@ -129,7 +145,7 @@ Error MetalClawReader::field(const char *name, ox::BString<L> *val) {
template<typename I>
Error MetalClawReader::readInteger(I *val) {
if (m_fieldPresence.get(m_field++)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
std::size_t bytesRead = 0;
if (m_buffIt >= m_buffLen) {
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
@ -142,13 +158,14 @@ Error MetalClawReader::readInteger(I *val) {
} else {
*val = 0;
}
++m_field;
return OxError(0);
}
// array handler
template<typename T>
Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) {
if (m_fieldPresence.get(m_field++)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
@ -170,12 +187,13 @@ Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) {
return OxError(MC_OUTBUFFENDED);
}
}
++m_field;
return OxError(0);
}
template<typename T, typename Handler>
Error MetalClawReader::field(const char*, Handler handler) {
if (m_fieldPresence.get(m_field++)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
@ -194,12 +212,13 @@ Error MetalClawReader::field(const char*, Handler handler) {
oxReturnError(handler(i, &val));
}
}
++m_field;
return OxError(0);
}
template<typename T>
Error MetalClawReader::field(const char* name, ox::Vector<T> *val) {
if (m_fieldPresence.get(m_field)) {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
const auto [len, err] = arrayLength(name, false);
oxReturnError(err);
val->resize(len);
@ -208,6 +227,14 @@ Error MetalClawReader::field(const char* name, ox::Vector<T> *val) {
return OxError(0);
}
template<typename T>
void MetalClawReader::setTypeInfo(const char*, int fields) {
m_fields = fields;
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
m_fieldPresence.setFields(fields);
m_fieldPresence.setMaxLen(m_buffIt);
}
template<typename T>
Error readMC(uint8_t *buff, std::size_t buffLen, T *val) {
MetalClawReader reader(buff, buffLen);

View File

@ -18,13 +18,25 @@
#include <ox/model/model.hpp>
#include <ox/std/std.hpp>
union TestUnion {
static constexpr auto TypeName = "TestUnion";
static constexpr auto Fields = 3;
bool Bool;
uint32_t Int = 5;
char String[32];
};
struct TestStructNest {
static constexpr auto TypeName = "TestStructNest";
static constexpr auto Fields = 3;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> String = "";
};
struct TestStruct {
static constexpr auto TypeName = "TestStruct";
static constexpr auto Fields = 15;
bool Bool = false;
int32_t Int = 0;
int32_t Int1 = 0;
@ -35,41 +47,50 @@ struct TestStruct {
int32_t Int6 = 0;
int32_t Int7 = 0;
int32_t Int8 = 0;
TestUnion Union;
ox::BString<32> String = "";
uint32_t List[4] = {0, 0, 0 , 0};
uint32_t List[4] = {0, 0, 0, 0};
TestStructNest EmptyStruct;
TestStructNest Struct;
};
template<typename T>
ox::Error model(T *io, TestUnion *obj) {
io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", ox::SerStr(obj->String)));
return OxError(0);
}
template<typename T>
ox::Error model(T *io, TestStructNest *obj) {
auto err = OxError(0);
io->setTypeInfo("TestStructNest", 3);
err |= io->field("Bool", &obj->Bool);
err |= io->field("Int", &obj->Int);
err |= io->field("String", &obj->String);
return err;
io->template setTypeInfo<TestStructNest>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", &obj->String));
return OxError(0);
}
template<typename T>
ox::Error model(T *io, TestStruct *obj) {
auto err = OxError(0);
io->setTypeInfo("TestStruct", 14);
err |= io->field("Bool", &obj->Bool);
err |= io->field("Int", &obj->Int);
err |= io->field("Int1", &obj->Int1);
err |= io->field("Int2", &obj->Int2);
err |= io->field("Int3", &obj->Int3);
err |= io->field("Int4", &obj->Int4);
err |= io->field("Int5", &obj->Int5);
err |= io->field("Int6", &obj->Int6);
err |= io->field("Int7", &obj->Int7);
err |= io->field("Int8", &obj->Int8);
err |= io->field("String", &obj->String);
err |= io->field("List", obj->List, 4);
err |= io->field("EmptyStruct", &obj->EmptyStruct);
err |= io->field("Struct", &obj->Struct);
return err;
io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("Int1", &obj->Int1));
oxReturnError(io->field("Int2", &obj->Int2));
oxReturnError(io->field("Int3", &obj->Int3));
oxReturnError(io->field("Int4", &obj->Int4));
oxReturnError(io->field("Int5", &obj->Int5));
oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
oxReturnError(io->field("Struct", &obj->Struct));
return OxError(0);
}
std::map<std::string, ox::Error(*)()> tests = {
@ -81,12 +102,11 @@ std::map<std::string, ox::Error(*)()> tests = {
// doesn't segfault
constexpr size_t buffLen = 1024;
uint8_t buff[buffLen];
auto err = ox::Error(0);
TestStruct ts;
err |= ox::writeMC(buff, buffLen, &ts);
oxReturnError(ox::writeMC(buff, buffLen, &ts));
return err;
return OxError(0);
}
},
{
@ -98,6 +118,7 @@ std::map<std::string, ox::Error(*)()> tests = {
testIn.Bool = true;
testIn.Int = 42;
testIn.Union.Int = 42;
testIn.String = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
@ -109,7 +130,7 @@ std::map<std::string, ox::Error(*)()> tests = {
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed");
//std::cout << testIn.String.c_str() << "|" << testOut.String.c_str() << "|\n";
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
@ -121,6 +142,7 @@ std::map<std::string, ox::Error(*)()> tests = {
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch");
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
@ -241,7 +263,6 @@ std::map<std::string, ox::Error(*)()> tests = {
{
"MetalClawDef",
[] {
auto err = OxError(0);
//constexpr size_t descBuffLen = 1024;
//uint8_t descBuff[descBuffLen];
constexpr size_t dataBuffLen = 1024;
@ -330,25 +351,26 @@ std::map<std::string, ox::Error(*)()> tests = {
case ox::PrimitiveType::Bool: {
bool i = {};
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n';
std::cout << fieldName << ":\t" << "bool:\t\t" << (i ? "true" : "false") << '\n';
break;
}
case ox::PrimitiveType::String: {
ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
//std::cout << rdr->stringLength() << '\n';
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
std::cout << fieldName << ":\t" << "string: " << v.data() << '\n';
std::cout << fieldName << ":\t" << "string:\t\t" << v.data() << '\n';
break;
}
case ox::PrimitiveType::Struct:
break;
case ox::PrimitiveType::Union:
break;
}
return OxError(0);
}
);
delete type.value;
return err;
return OxError(0);
}
},
}

View File

@ -14,83 +14,80 @@
namespace ox {
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen): m_fieldPresence(buff, buffLen) {
m_buff = buff;
m_buffLen = buffLen;
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
}
MetalClawWriter::~MetalClawWriter() noexcept {
oxAssert(m_field == m_fields, "MetalClawWriter: incorrect fields number given");
}
Error MetalClawWriter::field(const char*, int8_t *val) {
Error MetalClawWriter::field(const char*, int8_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int16_t *val) {
Error MetalClawWriter::field(const char*, int16_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int32_t *val) {
Error MetalClawWriter::field(const char*, int32_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, int64_t *val) {
Error MetalClawWriter::field(const char*, int64_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint8_t *val) {
Error MetalClawWriter::field(const char*, uint8_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint16_t *val) {
Error MetalClawWriter::field(const char*, uint16_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint32_t *val) {
Error MetalClawWriter::field(const char*, uint32_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, uint64_t *val) {
Error MetalClawWriter::field(const char*, uint64_t *val) noexcept {
return appendInteger(*val);
}
Error MetalClawWriter::field(const char*, bool *val) {
return m_fieldPresence.set(m_field++, *val);
Error MetalClawWriter::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(m_field, *val));
}
++m_field;
return OxError(0);
}
Error MetalClawWriter::field(const char*, SerStr val) {
auto err = OxError(0);
Error MetalClawWriter::field(const char*, SerStr val) noexcept {
bool fieldSet = false;
if (val.cap()) {
if (val.cap() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val.len());
if (m_buffIt + strLen.length + val.len() < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.len());
m_buffIt += val.len();
fieldSet = true;
} else {
err = OxError(MC_BUFFENDED);
return OxError(MC_BUFFENDED);
}
}
err |= m_fieldPresence.set(m_field, fieldSet);
m_field++;
return err;
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
++m_field;
return OxError(0);
}
void MetalClawWriter::setTypeInfo(const char*, int fields) {
m_fields = fields;
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
m_fieldPresence.setFields(fields);
m_fieldPresence.setMaxLen(m_buffIt);
}
std::size_t MetalClawWriter::size() {
std::size_t MetalClawWriter::size() noexcept {
return m_buffIt;
}

View File

@ -29,44 +29,49 @@ class MetalClawWriter {
FieldPresenceIndicator m_fieldPresence;
int m_fields = 0;
int m_field = 0;
int m_unionIdx = -1;
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
uint8_t *m_buff = nullptr;
public:
MetalClawWriter(uint8_t *buff, std::size_t buffLen);
MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
~MetalClawWriter() noexcept;
Error field(const char*, int8_t *val);
Error field(const char*, int16_t *val);
Error field(const char*, int32_t *val);
Error field(const char*, int64_t *val);
[[nodiscard]] Error field(const char*, int8_t *val) noexcept;
[[nodiscard]] Error field(const char*, int16_t *val) noexcept;
[[nodiscard]] Error field(const char*, int32_t *val) noexcept;
[[nodiscard]] Error field(const char*, int64_t *val) noexcept;
Error field(const char*, uint8_t *val);
Error field(const char*, uint16_t *val);
Error field(const char*, uint32_t *val);
Error field(const char*, uint64_t *val);
[[nodiscard]] Error field(const char*, uint8_t *val) noexcept;
[[nodiscard]] Error field(const char*, uint16_t *val) noexcept;
[[nodiscard]] Error field(const char*, uint32_t *val) noexcept;
[[nodiscard]] Error field(const char*, uint64_t *val) noexcept;
Error field(const char*, bool *val);
[[nodiscard]] Error field(const char*, bool *val) noexcept;
template<typename T>
Error field(const char*, T *val, std::size_t len);
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
template<typename T>
Error field(const char*, ox::Vector<T> *val);
[[nodiscard]] Error field(const char*, ox::Vector<T> *val);
template<std::size_t L>
Error field(const char*, ox::BString<L> *val);
[[nodiscard]] Error field(const char*, ox::BString<L> *val) noexcept;
Error field(const char*, SerStr val);
[[nodiscard]] Error field(const char*, SerStr val) noexcept;
template<typename T>
Error field(const char*, T *val);
[[nodiscard]] Error field(const char*, T *val);
void setTypeInfo(const char *name, int fields);
template<typename U>
[[nodiscard]] Error field(const char*, UnionView<U> val);
std::size_t size();
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
std::size_t size() noexcept;
static constexpr auto opType() {
return OpType::Write;
@ -74,20 +79,20 @@ class MetalClawWriter {
private:
template<typename I>
Error appendInteger(I val);
[[nodiscard]] Error appendInteger(I val) noexcept;
};
template<std::size_t L>
Error MetalClawWriter::field(const char *name, ox::BString<L> *val) {
Error MetalClawWriter::field(const char *name, ox::BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap()));
}
template<typename T>
Error MetalClawWriter::field(const char*, T *val) {
bool fieldSet = false;
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
if (val) {
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
oxReturnError(model(&writer, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
@ -99,27 +104,42 @@ Error MetalClawWriter::field(const char*, T *val) {
return OxError(0);
}
template<typename U>
Error MetalClawWriter::field(const char*, UnionView<U> val) {
bool fieldSet = false;
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
oxReturnError(model(&writer, val.get()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
}
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
m_field++;
return OxError(0);
}
template<typename T>
Error MetalClawWriter::field(const char*, T *val, std::size_t len) {
auto err = OxError(0);
bool fieldSet = false;
if (len) {
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
if (m_buffIt + arrLen.length < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
m_buffIt += arrLen.length;
} else {
err = OxError(MC_BUFFENDED);
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
writer.setTypeInfo("List", len);
writer.setTypeInfo<T>("List", len);
// write the array
for (std::size_t i = 0; i < len; i++) {
err |= writer.field("", &val[i]);
oxReturnError(writer.field("", &val[i]));
}
m_buffIt += writer.m_buffIt;
@ -128,7 +148,7 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) {
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
m_field++;
return err;
return OxError(0);
}
template<typename T>
@ -137,22 +157,30 @@ Error MetalClawWriter::field(const char*, ox::Vector<T> *val) {
}
template<typename I>
Error MetalClawWriter::appendInteger(I val) {
auto err = OxError(0);
Error MetalClawWriter::appendInteger(I val) noexcept {
bool fieldSet = false;
if (val) {
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
err |= OxError(MC_BUFFENDED);
oxReturnError(OxError(MC_BUFFENDED));
}
}
err |= m_fieldPresence.set(m_field, fieldSet);
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
m_field++;
return err;
return OxError(0);
;
}
template<typename T>
void MetalClawWriter::setTypeInfo(const char*, int fields) {
m_fields = fields;
m_fieldPresence.setFields(fields);
m_buffIt = m_fieldPresence.getMaxLen();
memset(m_buff, 0, m_buffIt);
}
template<typename T>

View File

@ -26,6 +26,7 @@ enum class PrimitiveType: uint8_t {
// Float = 3, reserved, but not implemented
String = 4,
Struct = 5,
Union = 6,
};
struct DescriptorField {

View File

@ -115,16 +115,6 @@ DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) {
return getType(TypeName, PT, Bytes, alreadyExisted);
}
void TypeDescWriter::setTypeInfo(const char *name, int) {
auto &t = m_typeStore->at(name);
if (!t) {
t = new DescriptorType;
}
m_type = t;
m_type->typeName = name;
m_type->primitiveType = PrimitiveType::Struct;
}
DescriptorType *TypeDescWriter::getType(TypeName tn, PrimitiveType pt, int b, bool *alreadyExisted) {
if (m_typeStore->contains(tn)) {
*alreadyExisted = true;

View File

@ -38,17 +38,18 @@ class TypeDescWriter {
TypeName name;
constexpr void setTypeInfo(const char *n, int) noexcept {
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *n = T::TypeName, int = T::Fields) noexcept {
this->name = n;
}
template<typename T>
constexpr ox::Error field(const char*, T*, std::size_t) noexcept {
[[nodiscard]] constexpr ox::Error field(const char*, T*, std::size_t) noexcept {
return OxError(0);
}
template<typename T>
constexpr ox::Error field(const char*, T*) noexcept {
[[nodiscard]] constexpr ox::Error field(const char*, T) noexcept {
return OxError(0);
}
@ -64,15 +65,16 @@ class TypeDescWriter {
~TypeDescWriter();
template<typename T>
ox::Error field(const char *name, T *val, std::size_t valLen);
[[nodiscard]] ox::Error field(const char *name, T *val, std::size_t valLen);
template<typename T>
ox::Error field(const char *name, ox::Vector<T> *val);
[[nodiscard]] ox::Error field(const char *name, T val);
template<typename T>
ox::Error field(const char *name, T *val);
[[nodiscard]] ox::Error field(const char *name, T *val);
void setTypeInfo(const char *name, int fields);
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
[[nodiscard]] DescriptorType *definition() noexcept {
return m_type;
@ -105,6 +107,9 @@ class TypeDescWriter {
template<typename T>
DescriptorType *type(T *val, bool *alreadyExisted);
template<typename U>
DescriptorType *type(UnionView<U> val, bool *alreadyExisted);
DescriptorType *getType(TypeName tn, PrimitiveType t, int b, bool *alreadyExisted);
};
@ -126,8 +131,15 @@ ox::Error TypeDescWriter::field(const char *name, T *val, std::size_t) {
}
template<typename T>
ox::Error TypeDescWriter::field(const char *name, ox::Vector<T> *val) {
return field(name, val->data(), val->size());
ox::Error TypeDescWriter::field(const char *name, T val) {
if (m_type) {
bool alreadyExisted = false;
const auto t = type(val, &alreadyExisted);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted);
return OxError(0);
}
return OxError(1);
}
template<typename T>
@ -150,7 +162,7 @@ DescriptorType *TypeDescWriter::type(BString<sz> *val, bool *alreadyExisted) {
template<typename T>
DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
NameCatcher nc;
model(&nc, val);
oxLogError(model(&nc, val));
if (m_typeStore->contains(nc.name)) {
*alreadyExisted = true;
return m_typeStore->at(nc.name);
@ -162,6 +174,26 @@ DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
}
}
template<typename U>
DescriptorType *TypeDescWriter::type(UnionView<U> val, bool *alreadyExisted) {
return type(val.get(), alreadyExisted);
}
template<typename T>
void TypeDescWriter::setTypeInfo(const char *name, int) {
auto &t = m_typeStore->at(name);
if (!t) {
t = new DescriptorType;
}
m_type = t;
m_type->typeName = name;
if (ox::is_union_v<T>) {
m_type->primitiveType = PrimitiveType::Union;
} else {
m_type->primitiveType = PrimitiveType::Struct;
}
}
template<typename T>
[[nodiscard]] ValErr<DescriptorType*> buildTypeDef(T *val) {
TypeDescWriter writer;

View File

@ -8,6 +8,7 @@
#pragma once
#include <ox/std/assert.hpp>
#include <ox/std/error.hpp>
#include <ox/std/strops.hpp>
@ -22,30 +23,32 @@ namespace OpType {
// empty default implementations of model functions
template<typename T, typename O>
ox::Error modelRead(T*, O*) {
return OxError(1);
[[nodiscard]] ox::Error modelRead(T*, O*) {
return OxError(1, "Model: modelRead not implemented");
}
template<typename T, typename O>
ox::Error modelWrite(T*, O*) {
return OxError(1);
[[nodiscard]] ox::Error modelWrite(T*, O*) {
return OxError(1, "Model: modelWrite not implemented");
}
template<typename T, typename O>
ox::Error modelWriteDefinition(T*, O*) {
return OxError(1);
[[nodiscard]] ox::Error modelWriteDefinition(T*, O*) {
return OxError(1, "Model: modelWriteDefinition not implemented");
}
template<typename T, typename O>
ox::Error model(T *io, O *obj) {
[[nodiscard]] ox::Error model(T *io, O *obj) {
ox::Error err;
if constexpr(ox_strcmp(T::opType(), ox::OpType::Read) == 0) {
return modelRead(io, obj);
err = modelRead(io, obj);
} else if constexpr(ox_strcmp(T::opType(), ox::OpType::Write) == 0) {
return modelWrite(io, obj);
err = modelWrite(io, obj);
} else if constexpr(ox_strcmp(T::opType(), ox::OpType::WriteDefinition) == 0) {
return modelWriteDefinition(io, obj);
err = modelWriteDefinition(io, obj);
}
return OxError(1);
oxAssert(err, "Missing model function");
return err;
}
}

View File

@ -11,6 +11,7 @@
#include <ox/std/bstring.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>
namespace ox {
@ -32,6 +33,12 @@ class SerStr {
m_cap = cap;
}
template<std::size_t cap>
constexpr SerStr(char (&str)[cap]) noexcept {
m_str = str;
m_cap = cap;
}
constexpr const char *c_str() noexcept {
return m_str;
}
@ -51,4 +58,25 @@ class SerStr {
};
template<typename Union>
class UnionView {
protected:
int m_idx = -1;
typename enable_if<is_union_v<Union>, Union>::type *m_union = nullptr;
public:
constexpr UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
}
constexpr auto idx() noexcept {
return m_idx;
}
constexpr Union *get() noexcept {
return m_union;
}
};
}

View File

@ -30,7 +30,7 @@ class DataWalker {
[[nodiscard]] const DescriptorType *type() const noexcept;
ox::Error read(const DescriptorField&, Reader *rdr);
[[nodiscard]] ox::Error read(const DescriptorField&, Reader *rdr);
protected:
void pushNamePath(FieldName fn);
@ -111,6 +111,7 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
oxReturnError(walker->read(field, rdr));
break;
case PrimitiveType::Struct:
case PrimitiveType::Union:
if (rdr->fieldPresent(field.fieldName.c_str())) {
auto child = rdr->child(field.fieldName.c_str());
walker->pushType(field.type);

View File

@ -226,6 +226,8 @@ std::map<std::string, ox::Error(*)()> tests = {
}
case ox::PrimitiveType::Struct:
break;
case ox::PrimitiveType::Union:
break;
}
return OxError(0);
}