[ox/mc] Fix string support in MC and add support for ox::BasicString

This commit is contained in:
Gary Talent 2022-01-27 20:58:33 -06:00
parent fd7510d14f
commit df782129bb
6 changed files with 119 additions and 51 deletions

View File

@ -109,6 +109,10 @@ Error MetalClawReader::field(const char*, SerStr val) noexcept {
return OxError(0);
}
Error MetalClawReader::fieldCString(const char *name, char **val, int len) noexcept {
return field(name, SerStr(val, len));
}
Result<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length

View File

@ -72,11 +72,16 @@ class MetalClawReader {
template<typename U>
Error field(const char*, UnionView<U> val) noexcept;
template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept;
Error field(const char*, SerStr val) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept;
/**
* Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length
@ -158,6 +163,38 @@ Error MetalClawReader::field(const char*, UnionView<U> val) noexcept {
return OxError(0);
}
template<std::size_t SmallStringSize>
Error MetalClawReader::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(size, mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
const auto cap = size;
*val = BasicString<SmallStringSize>(cap);
auto data = val->data();
// read the string
if (static_cast<StringLength>(cap) < size) {
return OxError(MC_OUTBUFFENDED);
}
if (m_buffIt + size > m_buffLen) {
return OxError(MC_BUFFENDED);
}
memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
*val = "";
}
}
++m_field;
return OxError(0);
}
template<std::size_t L>
Error MetalClawReader::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap()));
@ -201,7 +238,7 @@ Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) noexc
if (valLen >= len) {
auto reader = child("");
reader.setTypeInfo("List", static_cast<int>(len));
for (std::size_t i = 0; i < len; i++) {
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(reader.field("", &val[i]));
}
} else {
@ -225,15 +262,14 @@ Error MetalClawReader::field(const char*, HashMap<String, T> *val) noexcept {
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
// read the list
auto reader = child("");
reader.setTypeInfo("List", static_cast<int>(len));
for (std::size_t i = 0; i < len; i++) {
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = reader.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
oxReturnError(reader.field("", SerStr(&wkeyPtr, static_cast<int>(keyLen))));
oxReturnError(reader.fieldCString("", &wkeyPtr, static_cast<int>(keyLen + 1)));
oxReturnError(reader.field("", &val->operator[](wkey.get())));
}
}
@ -257,7 +293,7 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept {
// read the list
auto reader = child("");
reader.setTypeInfo("List", static_cast<int>(len));
for (std::size_t i = 0; i < len; i++) {
for (std::size_t i = 0; i < len; ++i) {
T val;
oxReturnError(reader.field("", &val));
oxReturnError(handler(i, &val));

View File

@ -23,7 +23,7 @@ union TestUnion {
static constexpr auto Fields = 3;
bool Bool;
uint32_t Int = 5;
char String[32];
char CString[32];
};
struct TestStructNest {
@ -31,7 +31,7 @@ struct TestStructNest {
static constexpr auto Fields = 3;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> String = "";
ox::BString<32> BString = "";
};
struct TestStruct {
@ -48,7 +48,8 @@ struct TestStruct {
int32_t Int7 = 0;
int32_t Int8 = 0;
TestUnion Union;
ox::BString<32> String = "";
ox::String String = "";
ox::BString<32> BString = "";
uint32_t List[4] = {0, 0, 0, 0};
ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct;
@ -60,18 +61,15 @@ constexpr ox::Error model(T *io, TestUnion *obj) noexcept {
io->template setTypeInfo<TestUnion>();
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", ox::SerStr(obj->String)));
oxReturnError(io->field("CString", ox::SerStr(obj->CString)));
return OxError(0);
}
template<typename T>
constexpr ox::Error model(T *io, TestStructNest *obj) noexcept {
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);
}
oxModelBegin(TestStructNest)
oxModelField(Bool)
oxModelField(Int)
oxModelField(BString)
oxModelEnd()
template<typename T>
constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
@ -88,6 +86,7 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept {
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("BString", &obj->BString));
oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("Map", &obj->Map));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
@ -119,7 +118,8 @@ std::map<std::string, ox::Error(*)()> tests = {
testIn.Bool = true;
testIn.Int = 42;
testIn.Union.Int = 42;
testIn.String = "Test String 1";
testIn.String = "Test String 0";
testIn.BString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
@ -128,7 +128,7 @@ std::map<std::string, ox::Error(*)()> tests = {
testIn.Map["aoeu"] = 94;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2";
testIn.Struct.BString = "Test String 2";
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed");
@ -146,6 +146,7 @@ std::map<std::string, ox::Error(*)()> tests = {
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.BString == testOut.BString, "BString value mismatch");
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
@ -154,9 +155,9 @@ std::map<std::string, ox::Error(*)()> tests = {
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
oxAssert(testIn.EmptyStruct.BString == testOut.EmptyStruct.BString, "EmptyStruct.BString value mismatch");
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
oxAssert(testIn.Struct.BString == testOut.Struct.BString, "Struct.BString value mismatch");
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
return OxError(0);
@ -277,14 +278,14 @@ std::map<std::string, ox::Error(*)()> tests = {
testIn.Bool = true;
testIn.Int = 42;
testIn.String = "Test String 1";
testIn.BString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2";
testIn.Struct.BString = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
auto type = ox::buildTypeDef(&testIn);

View File

@ -90,7 +90,7 @@ Error MetalClawWriter::field(const char*, SerStr val) noexcept {
return OxError(0);
}
std::size_t MetalClawWriter::size() noexcept {
std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
}

View File

@ -60,6 +60,9 @@ class MetalClawWriter {
template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept;
template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept;
@ -75,7 +78,7 @@ class MetalClawWriter {
void setTypeInfo(const char *name = T::TypeName, int fields = countFields<T>()) noexcept;
[[nodiscard]]
std::size_t size() noexcept;
std::size_t size() const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
@ -88,6 +91,28 @@ class MetalClawWriter {
};
template<std::size_t SmallStringSize>
Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val->len());
if (m_buffIt + strLen.length + static_cast<std::size_t>(val->len()) < m_buffLen) {
memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
memcpy(&m_buff[m_buffIt], val->c_str(), static_cast<std::size_t>(val->len()));
m_buffIt += static_cast<std::size_t>(val->len());
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
template<std::size_t L>
Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap()));
@ -108,7 +133,7 @@ Error MetalClawWriter::field(const char*, T *val) noexcept {
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
}

View File

@ -94,10 +94,12 @@ class SerStr {
constexpr char *data(std::size_t sz = 0) noexcept {
if (m_tgt && sz) {
if (!*m_tgt || sz > static_cast<std::size_t>(m_cap)) {
*m_tgt = new char[sz];
m_str = *m_tgt;
m_cap = static_cast<int>(sz);
}
}
return m_str;
}