diff --git a/deps/ox/src/ox/mc/presenceindicator.cpp b/deps/ox/src/ox/mc/presenceindicator.cpp index b3e7c367..02a311c6 100644 --- a/deps/ox/src/ox/mc/presenceindicator.cpp +++ b/deps/ox/src/ox/mc/presenceindicator.cpp @@ -7,6 +7,7 @@ */ #include +#include #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 { diff --git a/deps/ox/src/ox/mc/presenceindicator.hpp b/deps/ox/src/ox/mc/presenceindicator.hpp index 1a9fbeb1..c9e74bf5 100644 --- a/deps/ox/src/ox/mc/presenceindicator.hpp +++ b/deps/ox/src/ox/mc/presenceindicator.hpp @@ -22,9 +22,9 @@ class FieldPresenceIndicator { public: FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen); - ValErr get(std::size_t i) const; + [[nodiscard]] ValErr 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; diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp index 03704a37..a73ed97c 100644 --- a/deps/ox/src/ox/mc/read.cpp +++ b/deps/ox/src/ox/mc/read.cpp @@ -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(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead); - m_buffIt += bytesRead; - oxReturnError(err); - - // read the string - if (val.cap() > -1 && static_cast(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(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead); + m_buffIt += bytesRead; + oxReturnError(err); + // read the string + if (val.cap() > -1 && static_cast(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 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(&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 { diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index 150f8587..bee0338d 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -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 - 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 - Error field(const char*, Handler handler); + [[nodiscard]] Error field(const char*, Handler handler); // array handler, with callback to allow handling individual elements template - Error field(const char*, Handler handler, ArrayLength len); + [[nodiscard]] Error field(const char*, Handler handler, ArrayLength len); template - Error field(const char*, ox::Vector *val); + [[nodiscard]] Error field(const char*, ox::Vector *val); template - Error field(const char*, T *val); + [[nodiscard]] Error field(const char*, T *val); + + template + [[nodiscard]] Error field(const char*, UnionView val); template - Error field(const char*, ox::BString *val); + [[nodiscard]] Error field(const char*, ox::BString *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 + 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 - Error readInteger(I *val); + [[nodiscard]] Error readInteger(I *val); }; template 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 +Error MetalClawReader::field(const char*, UnionView 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 *val) { template 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 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 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 Error MetalClawReader::field(const char* name, ox::Vector *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 *val) { return OxError(0); } +template +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 Error readMC(uint8_t *buff, std::size_t buffLen, T *val) { MetalClawReader reader(buff, buffLen); diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index 4e3bfb65..f19f2ad5 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -18,13 +18,25 @@ #include #include +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 +ox::Error model(T *io, TestUnion *obj) { + io->template setTypeInfo(); + oxReturnError(io->field("Bool", &obj->Bool)); + oxReturnError(io->field("Int", &obj->Int)); + oxReturnError(io->field("String", ox::SerStr(obj->String))); + return OxError(0); +} + template 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(); + oxReturnError(io->field("Bool", &obj->Bool)); + oxReturnError(io->field("Int", &obj->Int)); + oxReturnError(io->field("String", &obj->String)); + return OxError(0); } template 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(); + 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 tests = { @@ -81,12 +102,11 @@ std::map 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 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 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 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 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 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 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); } }, } diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp index b1276d32..1facd371 100644 --- a/deps/ox/src/ox/mc/write.cpp +++ b/deps/ox/src/ox/mc/write.cpp @@ -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; } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index e58ad043..f1228644 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -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 - Error field(const char*, T *val, std::size_t len); + [[nodiscard]] Error field(const char*, T *val, std::size_t len); template - Error field(const char*, ox::Vector *val); + [[nodiscard]] Error field(const char*, ox::Vector *val); template - Error field(const char*, ox::BString *val); + [[nodiscard]] Error field(const char*, ox::BString *val) noexcept; - Error field(const char*, SerStr val); + [[nodiscard]] Error field(const char*, SerStr val) noexcept; template - Error field(const char*, T *val); + [[nodiscard]] Error field(const char*, T *val); - void setTypeInfo(const char *name, int fields); + template + [[nodiscard]] Error field(const char*, UnionView val); - std::size_t size(); + template + 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 - Error appendInteger(I val); + [[nodiscard]] Error appendInteger(I val) noexcept; }; template -Error MetalClawWriter::field(const char *name, ox::BString *val) { +Error MetalClawWriter::field(const char *name, ox::BString *val) noexcept { return field(name, SerStr(val->data(), val->cap())); } template 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(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 +Error MetalClawWriter::field(const char*, UnionView 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(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 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("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 @@ -137,22 +157,30 @@ Error MetalClawWriter::field(const char*, ox::Vector *val) { } template -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 +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 diff --git a/deps/ox/src/ox/model/desctypes.hpp b/deps/ox/src/ox/model/desctypes.hpp index 83f24020..dda267b7 100644 --- a/deps/ox/src/ox/model/desctypes.hpp +++ b/deps/ox/src/ox/model/desctypes.hpp @@ -26,6 +26,7 @@ enum class PrimitiveType: uint8_t { // Float = 3, reserved, but not implemented String = 4, Struct = 5, + Union = 6, }; struct DescriptorField { diff --git a/deps/ox/src/ox/model/descwrite.cpp b/deps/ox/src/ox/model/descwrite.cpp index d9befca7..93196c8b 100644 --- a/deps/ox/src/ox/model/descwrite.cpp +++ b/deps/ox/src/ox/model/descwrite.cpp @@ -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; diff --git a/deps/ox/src/ox/model/descwrite.hpp b/deps/ox/src/ox/model/descwrite.hpp index 31041d1f..a0feb83c 100644 --- a/deps/ox/src/ox/model/descwrite.hpp +++ b/deps/ox/src/ox/model/descwrite.hpp @@ -38,17 +38,18 @@ class TypeDescWriter { TypeName name; - constexpr void setTypeInfo(const char *n, int) noexcept { + template + constexpr void setTypeInfo(const char *n = T::TypeName, int = T::Fields) noexcept { this->name = n; } template - 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 - 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 - 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 - ox::Error field(const char *name, ox::Vector *val); + [[nodiscard]] ox::Error field(const char *name, T val); template - 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 + 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 DescriptorType *type(T *val, bool *alreadyExisted); + template + DescriptorType *type(UnionView 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 -ox::Error TypeDescWriter::field(const char *name, ox::Vector *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 @@ -150,7 +162,7 @@ DescriptorType *TypeDescWriter::type(BString *val, bool *alreadyExisted) { template 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 +DescriptorType *TypeDescWriter::type(UnionView val, bool *alreadyExisted) { + return type(val.get(), alreadyExisted); +} + +template +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) { + m_type->primitiveType = PrimitiveType::Union; + } else { + m_type->primitiveType = PrimitiveType::Struct; + } +} + template [[nodiscard]] ValErr buildTypeDef(T *val) { TypeDescWriter writer; diff --git a/deps/ox/src/ox/model/optype.hpp b/deps/ox/src/ox/model/optype.hpp index 92e3dac9..11591bfc 100644 --- a/deps/ox/src/ox/model/optype.hpp +++ b/deps/ox/src/ox/model/optype.hpp @@ -8,6 +8,7 @@ #pragma once +#include #include #include @@ -22,30 +23,32 @@ namespace OpType { // empty default implementations of model functions template -ox::Error modelRead(T*, O*) { - return OxError(1); +[[nodiscard]] ox::Error modelRead(T*, O*) { + return OxError(1, "Model: modelRead not implemented"); } template -ox::Error modelWrite(T*, O*) { - return OxError(1); +[[nodiscard]] ox::Error modelWrite(T*, O*) { + return OxError(1, "Model: modelWrite not implemented"); } template -ox::Error modelWriteDefinition(T*, O*) { - return OxError(1); +[[nodiscard]] ox::Error modelWriteDefinition(T*, O*) { + return OxError(1, "Model: modelWriteDefinition not implemented"); } template -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; } } diff --git a/deps/ox/src/ox/model/types.hpp b/deps/ox/src/ox/model/types.hpp index bd19d169..aa60e1c1 100644 --- a/deps/ox/src/ox/model/types.hpp +++ b/deps/ox/src/ox/model/types.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace ox { @@ -32,6 +33,12 @@ class SerStr { m_cap = cap; } + template + 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 +class UnionView { + + protected: + int m_idx = -1; + typename enable_if, 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; + } + +}; + } diff --git a/deps/ox/src/ox/model/walk.hpp b/deps/ox/src/ox/model/walk.hpp index 460f9309..a46d8113 100644 --- a/deps/ox/src/ox/model/walk.hpp +++ b/deps/ox/src/ox/model/walk.hpp @@ -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); diff --git a/deps/ox/src/ox/oc/test/tests.cpp b/deps/ox/src/ox/oc/test/tests.cpp index e6235574..bb58483f 100644 --- a/deps/ox/src/ox/oc/test/tests.cpp +++ b/deps/ox/src/ox/oc/test/tests.cpp @@ -226,6 +226,8 @@ std::map tests = { } case ox::PrimitiveType::Struct: break; + case ox::PrimitiveType::Union: + break; } return OxError(0); }