[ox] Overhaul serialization/model system and add ModelValue/ModelObject/ModelUnion variant system

This commit is contained in:
2022-06-21 21:43:49 -05:00
parent bc391b45fc
commit ca64f95be3
47 changed files with 2696 additions and 973 deletions

View File

@@ -3,12 +3,13 @@
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/bit.hpp>
@@ -38,49 +39,73 @@ class MetalClawWriter {
uint8_t *m_buff = nullptr;
public:
MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
~MetalClawWriter() noexcept;
constexpr ~MetalClawWriter() noexcept;
Error field(const char*, int8_t *val) noexcept;
Error field(const char*, int16_t *val) noexcept;
Error field(const char*, int32_t *val) noexcept;
Error field(const char*, int64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int8_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int16_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int32_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int64_t> auto *val) noexcept;
Error field(const char*, uint8_t *val) noexcept;
Error field(const char*, uint16_t *val) noexcept;
Error field(const char*, uint32_t *val) noexcept;
Error field(const char*, uint64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept;
Error field(const char*, bool *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<bool> auto *val) noexcept;
template<typename T>
Error field(const char*, T *val, std::size_t len) noexcept;
constexpr Error field(const char*, T *val, std::size_t len) noexcept;
template<typename T>
Error field(const char*, HashMap<String, T> *val) noexcept;
constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept;
template<typename T>
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
template<std::size_t SmallStringSize>
Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
Error field(const char*, BString<L> *val) noexcept;
constexpr Error field(const char*, const BString<L> *val) noexcept;
Error field(const char*, SerStr val) noexcept;
template<std::size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
Error fieldCString(const char *name, char **val, int len) noexcept;
template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept;
constexpr Error fieldCString(const char *name, const char **val) noexcept;
constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept;
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char**>(val), buffLen);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return fieldCString(name, const_cast<const char**>(val));
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char*>(val), buffLen);
}
template<typename T>
Error field(const char*, T *val) noexcept;
constexpr Error field(const char*, T *val) noexcept;
template<typename U>
Error field(const char*, UnionView<U> val) noexcept;
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t>
void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, int fields = ModelFieldCount_v<T>) noexcept;
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
[[nodiscard]]
std::size_t size() const noexcept;
constexpr std::size_t size() const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
@@ -88,13 +113,81 @@ class MetalClawWriter {
}
private:
template<typename I>
Error appendInteger(I val) noexcept;
constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false;
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 {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
};
constexpr 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) {
}
constexpr MetalClawWriter::~MetalClawWriter() noexcept {
if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
}
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept {
return appendInteger(*val);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
}
++m_field;
return OxError(0);
}
template<std::size_t SmallStringSize>
Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noexcept {
constexpr Error MetalClawWriter::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
@@ -116,19 +209,77 @@ Error MetalClawWriter::field(const char*, BasicString<SmallStringSize> *val) noe
}
template<std::size_t L>
Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return field(name, SerStr(val->data(), val->cap()));
constexpr Error MetalClawWriter::field(const char *name, const BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char **val, std::size_t) noexcept {
bool fieldSet = false;
if (m_unionIdx == -1 || m_unionIdx == m_field) {
const auto strLen = *val ? ox_strlen(*val) : 0;
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], *val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept {
return fieldCString(name, val, {});
}
constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
bool fieldSet = false;
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
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<typename T>
Error MetalClawWriter::field(const char*, T *val) noexcept {
constexpr Error MetalClawWriter::field(const char*, T *val) noexcept {
if constexpr(isVector_v<T>) {
return field(nullptr, val->data(), val->size());
} else {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
oxReturnError(model(&writer, val));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
@@ -140,12 +291,13 @@ Error MetalClawWriter::field(const char*, T *val) noexcept {
}
}
template<typename U>
Error MetalClawWriter::field(const char*, UnionView<U> val) noexcept {
template<typename U, bool force>
constexpr Error MetalClawWriter::field(const char*, UnionView<U, force> val) noexcept {
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()));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
@@ -157,7 +309,7 @@ Error MetalClawWriter::field(const char*, UnionView<U> val) noexcept {
}
template<typename T>
Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
@@ -171,11 +323,12 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
writer.setTypeInfo<T>("List", 0, len);
ModelHandlerInterface handler{&writer};
handler.setTypeInfo<T>("List", 0, len);
// write the array
for (std::size_t i = 0; i < len; i++) {
oxReturnError(writer.field("", &val[i]));
oxReturnError(handler.field("", &val[i]));
}
m_buffIt += writer.m_buffIt;
@@ -188,11 +341,10 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
}
template<typename T>
Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept {
constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *val) noexcept {
const auto &keys = val->keys();
const auto len = keys.size();
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
@@ -202,69 +354,57 @@ Error MetalClawWriter::field(const char*, HashMap<String, T> *val) noexcept {
} else {
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer};
// double len for both key and value
writer.setTypeInfo("Map", 0, len * 2);
handler.setTypeInfo("Map", 0, len * 2);
// write the array
for (std::size_t i = 0; i < len; i++) {
const auto &key = keys[i];
const auto keyLen = ox_strlen(key);
auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey, key.c_str(), keyLen + 1);
oxReturnError(writer.field("", SerStr(wkey.get(), keyLen)));
oxReturnError(writer.field("", &(*val)[key]));
oxReturnError(handler.fieldCString("", wkey.get(), keyLen));
oxReturnError(handler.field("", val->at(key).value));
}
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<typename I>
Error MetalClawWriter::appendInteger(I val) noexcept {
bool fieldSet = false;
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 {
return OxError(MC_BUFFENDED);
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<typename T>
void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
}
template<typename T>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
m_fields = fields;
m_fieldPresence.setFields(fields);
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());
ox_memset(m_buff, 0, m_buffIt);
}
template<typename T>
Result<Buffer> writeMC(T *val) noexcept {
constexpr std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
}
Result<Buffer> writeMC(auto *val) noexcept {
Buffer buff(10 * units::MB);
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size());
oxReturnError(model(&writer, val));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
buff.resize(writer.size());
return buff;
}
template<typename T>
Error writeMC(char *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) noexcept {
Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept {
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen);
auto err = model(&writer, val);
ModelHandlerInterface handler(&writer);
auto err = model(&handler, val);
if (sizeOut) {
*sizeOut = writer.size();
}