[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); 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 { 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))) { if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length

View File

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

View File

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

View File

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

View File

@ -60,6 +60,9 @@ class MetalClawWriter {
template<typename T> template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept; 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> template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept; 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; void setTypeInfo(const char *name = T::TypeName, int fields = countFields<T>()) noexcept;
[[nodiscard]] [[nodiscard]]
std::size_t size() noexcept; std::size_t size() const noexcept;
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { 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> template<std::size_t L>
Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept { Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap())); 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)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++; ++m_field;
return OxError(0); return OxError(0);
} }
} }

View File

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