[ox/model] Harmonize make the interface for walking over models

This commit is contained in:
Gary Talent 2020-04-09 22:49:56 -05:00
parent a4000f6497
commit 5d95b188d8
17 changed files with 376 additions and 254 deletions

View File

@ -11,5 +11,4 @@
#include "intops.hpp" #include "intops.hpp"
#include "read.hpp" #include "read.hpp"
#include "types.hpp" #include "types.hpp"
#include "walk.hpp"
#include "write.hpp" #include "write.hpp"

View File

@ -81,6 +81,7 @@ Error MetalClawReader::field(const char*, SerStr val) {
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) { if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
if (m_buffIt + size <= m_buffLen) { if (m_buffIt + size <= m_buffLen) {
ox_memcpy(val.data(), &m_buff[m_buffIt], size); ox_memcpy(val.data(), &m_buff[m_buffIt], size);
val.data()[size] = 0;
m_buffIt += size; m_buffIt += size;
} else { } else {
return OxError(MC_BUFFENDED); return OxError(MC_BUFFENDED);
@ -94,7 +95,7 @@ Error MetalClawReader::field(const char*, SerStr val) {
return OxError(0); return OxError(0);
} }
[[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(bool pass) { [[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) {
if (m_fieldPresence.get(m_field)) { if (m_fieldPresence.get(m_field)) {
// read the length // read the length
if (m_buffIt >= m_buffLen) { if (m_buffIt >= m_buffLen) {
@ -110,7 +111,7 @@ Error MetalClawReader::field(const char*, SerStr val) {
return OxError(1); return OxError(1);
} }
[[nodiscard]] StringLength MetalClawReader::stringLength() { [[nodiscard]] StringLength MetalClawReader::stringLength(const char*) {
if (m_fieldPresence.get(m_field)) { if (m_fieldPresence.get(m_field)) {
// read the length // read the length
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
@ -127,11 +128,11 @@ void MetalClawReader::setTypeInfo(const char*, int fields) {
m_fieldPresence.setMaxLen(m_buffIt); m_fieldPresence.setMaxLen(m_buffIt);
} }
MetalClawReader MetalClawReader::child() { MetalClawReader MetalClawReader::child(const char*) {
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, this); return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, this);
} }
bool MetalClawReader::fieldPresent() const { bool MetalClawReader::fieldPresent(const char*) const {
return m_fieldPresence.get(m_field).value; return m_fieldPresence.get(m_field).value;
} }

View File

@ -77,24 +77,24 @@ class MetalClawReader {
* 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
*/ */
[[nodiscard]] ValErr<ArrayLength> arrayLength(bool pass = true); [[nodiscard]] ValErr<ArrayLength> arrayLength(const char *name, bool pass = true);
/** /**
* Reads an string length from the current location in the buffer. * Reads an string length from the current location in the buffer.
*/ */
[[nodiscard]] StringLength stringLength(); [[nodiscard]] StringLength stringLength(const char *name);
void setTypeInfo(const char *name, int fields); void setTypeInfo(const char *name, int fields);
/** /**
* Returns a MetalClawReader to parse a child object. * Returns a MetalClawReader to parse a child object.
*/ */
[[nodiscard]] MetalClawReader child(); [[nodiscard]] MetalClawReader child(const char *name);
/** /**
* Indicates whether or not the next field to be read is present. * Indicates whether or not the next field to be read is present.
*/ */
bool fieldPresent() const; bool fieldPresent(const char *name) const;
/** /**
* Indicates whether or not the given field is present. * Indicates whether or not the given field is present.
@ -103,7 +103,7 @@ class MetalClawReader {
void nextField() noexcept; void nextField() noexcept;
static constexpr OpType opType() { static constexpr auto opType() {
return OpType::Read; return OpType::Read;
} }
@ -116,7 +116,7 @@ class MetalClawReader {
template<typename T> template<typename T>
Error MetalClawReader::field(const char*, T *val) { Error MetalClawReader::field(const char*, T *val) {
if (val && m_fieldPresence.get(m_field++)) { if (val && m_fieldPresence.get(m_field++)) {
auto reader = child(); auto reader = child("");
oxReturnError(model(&reader, val)); oxReturnError(model(&reader, val));
} }
return OxError(0); return OxError(0);
@ -160,7 +160,7 @@ Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) {
// read the list // read the list
if (valLen >= len.value) { if (valLen >= len.value) {
auto reader = child(); auto reader = child("");
reader.setTypeInfo("List", len.value); reader.setTypeInfo("List", len.value);
for (std::size_t i = 0; i < len.value; i++) { for (std::size_t i = 0; i < len.value; i++) {
oxReturnError(reader.field("", &val[i])); oxReturnError(reader.field("", &val[i]));
@ -186,7 +186,7 @@ Error MetalClawReader::field(const char*, Handler handler) {
oxReturnError(len.error); oxReturnError(len.error);
// read the list // read the list
auto reader = child(); auto reader = child("");
reader.setTypeInfo("List", len.value); reader.setTypeInfo("List", len.value);
for (std::size_t i = 0; i < len.value; i++) { for (std::size_t i = 0; i < len.value; i++) {
T val; T val;
@ -200,7 +200,7 @@ Error MetalClawReader::field(const char*, Handler handler) {
template<typename T> template<typename T>
Error MetalClawReader::field(const char* name, ox::Vector<T> *val) { Error MetalClawReader::field(const char* name, ox::Vector<T> *val) {
if (m_fieldPresence.get(m_field)) { if (m_fieldPresence.get(m_field)) {
const auto [len, err] = arrayLength(false); const auto [len, err] = arrayLength(name, false);
oxReturnError(err); oxReturnError(err);
val->resize(len); val->resize(len);
return field(name, val->data(), val->size()); return field(name, val->data(), val->size());

View File

@ -109,7 +109,7 @@ std::map<std::string, ox::Error(*)()> tests = {
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed"); oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed"); oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed");
std::cout << testIn.Int << " " << testOut.Int << '\n'; //std::cout << testIn.String.c_str() << "|" << testOut.String.c_str() << "|\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");
@ -260,9 +260,9 @@ std::map<std::string, ox::Error(*)()> tests = {
testIn.Struct.String = "Test String 2"; testIn.Struct.String = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
auto type = ox::buildMCDef(&testIn); auto type = ox::buildTypeDef(&testIn);
oxAssert(type.error, "Descriptor write failed"); oxAssert(type.error, "Descriptor write failed");
ox::walkMC<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen, ox::walkModel<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error { [](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
//std::cout << f.fieldName.c_str() << '\n'; //std::cout << f.fieldName.c_str() << '\n';
auto fieldName = f.fieldName.c_str(); auto fieldName = f.fieldName.c_str();
@ -334,7 +334,7 @@ std::map<std::string, ox::Error(*)()> tests = {
break; break;
} }
case ox::PrimitiveType::String: { case ox::PrimitiveType::String: {
ox::Vector<char> v(rdr->stringLength()); ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
//std::cout << rdr->stringLength() << '\n'; //std::cout << rdr->stringLength() << '\n';
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed."); 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: " << v.data() << '\n';

View File

@ -1,22 +0,0 @@
/*
* Copyright 2015 - 2018 gtalent2@gmail.com
*
* 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/.
*/
#pragma once
#include <ox/model/walk.hpp>
namespace ox {
template<typename Reader, typename Handler>
ox::Error walkMC(DescriptorType *type, uint8_t *data, std::size_t dataLen, Handler handler) {
DataWalker<Reader, Handler> walker(type, handler);
Reader rdr(data, dataLen);
return model(&rdr, &walker);
}
}

View File

@ -65,14 +65,14 @@ Error MetalClawWriter::field(const char*, SerStr val) {
bool fieldSet = false; bool fieldSet = false;
if (val.cap()) { if (val.cap()) {
// write the length // write the length
const auto strLen = mc::encodeInteger(val.bytes()); const auto strLen = mc::encodeInteger(val.len());
if (m_buffIt + strLen.length + val.bytes() < m_buffLen) { if (m_buffIt + strLen.length + val.len() < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length); ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length; m_buffIt += strLen.length;
// write the string // write the string
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.bytes()); ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.len());
m_buffIt += val.bytes(); m_buffIt += val.len();
fieldSet = true; fieldSet = true;
} else { } else {
err = OxError(MC_BUFFENDED); err = OxError(MC_BUFFENDED);

View File

@ -68,13 +68,14 @@ class MetalClawWriter {
std::size_t size(); std::size_t size();
static constexpr OpType opType() { static constexpr auto opType() {
return OpType::Write; return OpType::Write;
} }
private: private:
template<typename I> template<typename I>
Error appendInteger(I val); Error appendInteger(I val);
}; };
template<std::size_t L> template<std::size_t L>

View File

@ -78,7 +78,7 @@ class TypeDescWriter {
return m_type; return m_type;
} }
static constexpr OpType opType() { static constexpr auto opType() {
return OpType::WriteDefinition; return OpType::WriteDefinition;
} }
@ -163,18 +163,18 @@ DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
} }
template<typename T> template<typename T>
[[nodiscard]] ValErr<DescriptorType*> buildMCDef(T *val) { [[nodiscard]] ValErr<DescriptorType*> buildTypeDef(T *val) {
TypeDescWriter writer; TypeDescWriter writer;
Error err = model(&writer, val); Error err = model(&writer, val);
return {writer.definition(), err}; return {writer.definition(), err};
} }
template<typename T> template<typename T>
Error writeMCDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) { Error writeTypeDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
auto def = buildMCDef(val); auto def = buildTypeDef(val);
auto err = def.error; auto err = def.error;
if (!err) { if (!err) {
err |= writeMC(buff, buffLen, def.value, sizeOut); oxReturnError(writeType(buff, buffLen, def.value, sizeOut));
} }
delete def.value; delete def.value;
return err; return err;

View File

@ -9,14 +9,15 @@
#pragma once #pragma once
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/strops.hpp>
namespace ox { namespace ox {
enum class OpType { namespace OpType {
Read = 1, constexpr auto Read = "Read";
Write = 2, constexpr auto Write = "Write";
WriteDefinition = 3, constexpr auto WriteDefinition = "WriteDefinition";
}; }
// empty default implementations of model functions // empty default implementations of model functions
@ -37,11 +38,11 @@ ox::Error modelWriteDefinition(T*, O*) {
template<typename T, typename O> template<typename T, typename O>
ox::Error model(T *io, O *obj) { ox::Error model(T *io, O *obj) {
if constexpr(T::opType() == ox::OpType::Read) { if constexpr(ox_strcmp(T::opType(), ox::OpType::Read) == 0) {
return modelRead(io, obj); return modelRead(io, obj);
} else if constexpr(T::opType() == ox::OpType::Write) { } else if constexpr(ox_strcmp(T::opType(), ox::OpType::Write) == 0) {
return modelWrite(io, obj); return modelWrite(io, obj);
} else if constexpr(T::opType() == ox::OpType::WriteDefinition) { } else if constexpr(ox_strcmp(T::opType(), ox::OpType::WriteDefinition) == 0) {
return modelWriteDefinition(io, obj); return modelWriteDefinition(io, obj);
} }
return OxError(1); return OxError(1);

View File

@ -45,10 +45,6 @@ class SerStr {
return ox_strlen(m_str); return ox_strlen(m_str);
} }
constexpr int bytes() noexcept {
return ox_strlen(m_str) + 1; // adds 1 for \0
}
constexpr int cap() noexcept { constexpr int cap() noexcept {
return m_cap; return m_cap;
} }

View File

@ -86,14 +86,14 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
walker->pushNamePath(field.fieldName); walker->pushNamePath(field.fieldName);
if (field.subscriptLevels) { if (field.subscriptLevels) {
// add array handling // add array handling
const auto [arrayLen, err] = rdr->arrayLength(true); const auto [arrayLen, err] = rdr->arrayLength(field.fieldName.c_str(), true);
oxReturnError(err); oxReturnError(err);
auto child = rdr->child(); auto child = rdr->child(field.fieldName.c_str());
child.setTypeInfo(field.fieldName.c_str(), arrayLen); child.setTypeInfo(field.fieldName.c_str(), arrayLen);
DescriptorField f(field); // create mutable copy DescriptorField f(field); // create mutable copy
--f.subscriptLevels; --f.subscriptLevels;
BString<100> subscript; BString<100> subscript;
for (ArrayLength i = 0; i < arrayLen; i++) { for (std::size_t i = 0; i < arrayLen; i++) {
subscript = "["; subscript = "[";
subscript += i; subscript += i;
subscript += "]"; subscript += "]";
@ -111,8 +111,8 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
oxReturnError(walker->read(field, rdr)); oxReturnError(walker->read(field, rdr));
break; break;
case PrimitiveType::Struct: case PrimitiveType::Struct:
if (rdr->fieldPresent()) { if (rdr->fieldPresent(field.fieldName.c_str())) {
auto child = rdr->child(); auto child = rdr->child(field.fieldName.c_str());
walker->pushType(field.type); walker->pushType(field.type);
oxReturnError(model(&child, walker)); oxReturnError(model(&child, walker));
walker->popType(); walker->popType();
@ -120,7 +120,7 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
} else { } else {
// skip and discard absent field // skip and discard absent field
int discard; int discard;
oxReturnError(rdr->field("", &discard)); oxReturnError(rdr->field(field.fieldName.c_str(), &discard));
} }
break; break;
} }
@ -144,4 +144,11 @@ ox::Error model(Reader *rdr, DataWalker<Reader, FH> *walker) {
return OxError(0); return OxError(0);
} }
template<typename Reader, typename Handler>
ox::Error walkModel(DescriptorType *type, uint8_t *data, std::size_t dataLen, Handler handler) {
DataWalker<Reader, Handler> walker(type, handler);
Reader rdr(data, dataLen);
return model(&rdr, &walker);
}
} }

View File

@ -1,108 +1,220 @@
/* /*
* Copyright 2015 - 2018 gtalent2@gmail.com * Copyright 2015 - 2020 gtalent2@gmail.com
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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 http://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/bit.hpp>
#include "read.hpp" #include "read.hpp"
namespace ox { namespace ox {
template<typename Key> template<typename Key>
OrganicClawReader<Key>::OrganicClawReader(Json::Value json) { OrganicClawReader<Key>::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) {
auto json = bit_cast<const char*>(buff);
auto jsonLen = ox_strnlen(json, buffSize);
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw OxError(1, "Could not parse JSON");
}
}
template<typename Key>
OrganicClawReader<Key>::OrganicClawReader(const char *json, std::size_t jsonLen) {
Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
throw OxError(1, "Could not parse JSON");
}
}
template<typename Key>
OrganicClawReader<Key>::OrganicClawReader(const Json::Value &json) {
m_json = json; m_json = json;
} }
template<typename Key>
OrganicClawReader<Key>::~OrganicClawReader() {
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, int8_t *val) { Error OrganicClawReader<Key>::field(Key key, int8_t *val) {
*val = static_cast<int8_t>(m_json[key].asInt()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isInt()) {
*val = static_cast<int8_t>(jv.asInt());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, int16_t *val) { Error OrganicClawReader<Key>::field(Key key, int16_t *val) {
*val = static_cast<int16_t>(m_json[key].asInt()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isInt()) {
*val = static_cast<int16_t>(jv.asInt());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, int32_t *val) { Error OrganicClawReader<Key>::field(Key key, int32_t *val) {
*val = static_cast<int32_t>(m_json[key].asInt()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isInt()) {
*val = static_cast<int32_t>(jv.asInt());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, int64_t *val) { Error OrganicClawReader<Key>::field(Key key, int64_t *val) {
*val = static_cast<int64_t>(m_json[key].asInt64()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isInt() || jv.isInt64()) {
*val = static_cast<int64_t>(jv.asInt64());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, uint8_t *val) { Error OrganicClawReader<Key>::field(Key key, uint8_t *val) {
*val = static_cast<uint8_t>(m_json[key].asUInt()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isUInt()) {
*val = static_cast<uint8_t>(jv.asUInt());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, uint16_t *val) { Error OrganicClawReader<Key>::field(Key key, uint16_t *val) {
*val = static_cast<uint16_t>(m_json[key].asUInt()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isUInt()) {
*val = static_cast<uint16_t>(jv.asUInt());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, uint32_t *val) { Error OrganicClawReader<Key>::field(Key key, uint32_t *val) {
*val = static_cast<uint32_t>(m_json[key].asUInt()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isUInt()) {
*val = static_cast<uint32_t>(jv.asUInt());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, uint64_t *val) { Error OrganicClawReader<Key>::field(Key key, uint64_t *val) {
*val = static_cast<uint64_t>(m_json[key].asUInt64()); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isUInt() || jv.isUInt64()) {
*val = static_cast<uint64_t>(jv.asUInt64());
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, bool *val) { Error OrganicClawReader<Key>::field(Key key, bool *val) {
*val = m_json[key].asBool(); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0); return OxError(0);
} }
if (jv.isBool()) {
*val = jv.asBool();
return OxError(0);
}
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
Error OrganicClawReader<Key>::field(Key key, SerStr val) { Error OrganicClawReader<Key>::field(Key key, SerStr val) {
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
m_json[key].getString(&begin, &end); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0);
}
if (jv.isString()) {
jv.getString(&begin, &end);
auto strSize = end - begin; auto strSize = end - begin;
if (strSize >= val.cap()) { if (strSize >= val.cap()) {
return OxError(1); return OxError(1, "String size exceeds capacity of destination");
} }
ox_memcpy(val.data(), begin, static_cast<std::size_t>(strSize)); ox_memcpy(val.data(), begin, static_cast<std::size_t>(strSize));
val.data()[strSize] = 0; val.data()[strSize] = 0;
return OxError(0); return OxError(0);
} }
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
[[nodiscard]] std::size_t OrganicClawReader<Key>::arrayLength(Key key, bool) { [[nodiscard]] ValErr<std::size_t> OrganicClawReader<Key>::arrayLength(Key key, bool) {
return m_json[key].size(); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return 0;
}
if (jv.isArray()) {
return jv.size();
}
return OxError(1, "Type mismatch");
} }
template<typename Key> template<typename Key>
[[nodiscard]] std::size_t OrganicClawReader<Key>::stringLength(Key key) { [[nodiscard]] std::size_t OrganicClawReader<Key>::stringLength(Key key) {
const char *begin = nullptr, *end = nullptr; const char *begin = nullptr, *end = nullptr;
m_json[key].getString(&begin, &end); const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return 0;
}
if (jv.isString()) {
jv.getString(&begin, &end);
return static_cast<std::size_t>(end - begin); return static_cast<std::size_t>(end - begin);
} }
return OxError(1, "Type mismatch");
}
template<typename Key> template<typename Key>
void OrganicClawReader<Key>::setTypeInfo(const char*, int fields) { void OrganicClawReader<Key>::setTypeInfo(const char*, int) {
m_fields = fields;
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
} }
template<typename Key> template<typename Key>
@ -110,6 +222,20 @@ OrganicClawReader<Key> OrganicClawReader<Key>::child(Key key) {
return OrganicClawReader<Key>(m_json[key]); return OrganicClawReader<Key>(m_json[key]);
} }
template<typename Key>
bool OrganicClawReader<Key>::fieldPresent(Key key) {
return !m_json[key].empty();
}
template<typename Key>
Json::Value &OrganicClawReader<Key>::value(Key key) {
if (m_json.isArray()) {
return m_json[m_fieldIt];
} else {
return m_json[key];
}
}
template class OrganicClawReader<const char*>; template class OrganicClawReader<const char*>;
template class OrganicClawReader<Json::ArrayIndex>; template class OrganicClawReader<Json::ArrayIndex>;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2018 gtalent2@gmail.com * Copyright 2015 - 2020 gtalent2@gmail.com
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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 http://mozilla.org/MPL/2.0/.
@ -23,16 +23,16 @@ class OrganicClawReader {
private: private:
Json::Value m_json; Json::Value m_json;
int m_fields = 0; Json::ArrayIndex m_fieldIt = 0;
int m_field = 0;
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
uint8_t *m_buff = nullptr;
public: public:
OrganicClawReader(Json::Value json = {}); OrganicClawReader() = default;
~OrganicClawReader(); OrganicClawReader(const uint8_t *buff, std::size_t buffSize);
OrganicClawReader(const char *json, std::size_t buffSize);
OrganicClawReader(const Json::Value &json);
[[nodiscard]] Error field(Key key, int8_t *val); [[nodiscard]] Error field(Key key, int8_t *val);
[[nodiscard]] Error field(Key key, int16_t *val); [[nodiscard]] Error field(Key key, int16_t *val);
@ -65,7 +65,7 @@ class OrganicClawReader {
* 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
*/ */
[[nodiscard]] std::size_t arrayLength(Key key, bool pass = true); [[nodiscard]] ValErr<std::size_t> arrayLength(Key key, bool pass = true);
/** /**
* Reads an string length from the current location in the buffer. * Reads an string length from the current location in the buffer.
@ -79,18 +79,34 @@ class OrganicClawReader {
*/ */
[[nodiscard]] OrganicClawReader child(Key key); [[nodiscard]] OrganicClawReader child(Key key);
static constexpr OpType opType() { // compatibility stub
constexpr void nextField() noexcept {}
bool fieldPresent(Key key);
static constexpr auto opType() {
return OpType::Read; return OpType::Read;
} }
private:
Json::Value &value(Key key);
}; };
template<typename Key> template<typename Key>
template<typename T> template<typename T>
Error OrganicClawReader<Key>::field(Key key, T *val) { Error OrganicClawReader<Key>::field(Key key, T *val) {
if (val) { if (val) {
const auto &jv = value(key);
++m_fieldIt;
if (jv.empty()) {
return OxError(0);
}
if (jv.isObject()) {
auto reader = child(key); auto reader = child(key);
oxReturnError(model(&reader, val)); return model(&reader, val);
}
} }
return OxError(0); return OxError(0);
} }
@ -110,9 +126,9 @@ Error OrganicClawReader<Key>::field(Key key, T *val, std::size_t valLen) {
if (srcSize > valLen) { if (srcSize > valLen) {
return OxError(1); return OxError(1);
} }
OrganicClawReader<Json::ArrayIndex> r(srcVal); OrganicClawReader<const char*> r(srcVal);
for (decltype(srcSize) i = 0; i < srcSize; ++i) { for (decltype(srcSize) i = 0; i < srcSize; ++i) {
oxReturnError(r.field(i, &val[i])); oxReturnError(r.field("", &val[i]));
} }
return OxError(0); return OxError(0);
} }
@ -124,16 +140,28 @@ Error OrganicClawReader<Key>::field(Key key, ox::Vector<T> *val) {
} }
template<typename T> template<typename T>
ValErr<T> readOC(const char *json) { Error readOC(const char *json, std::size_t jsonSize, T *val) noexcept {
// OrganicClawReader constructor can throw, but readOC should return its errors.
try {
Json::Value doc; Json::Value doc;
Json::CharReaderBuilder parserBuilder; Json::CharReaderBuilder parserBuilder;
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader()); auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
if (!parser->parse(json, json + ox_strlen(json), &doc, nullptr)) { if (!parser->parse(json, json + jsonSize, &doc, nullptr)) {
return OxError(1, "Could not parse JSON"); return OxError(1, "Could not parse JSON");
} }
OrganicClawReader<const char*> reader(doc); OrganicClawReader<const char*> reader(json, jsonSize);
return model(&reader, val);
} catch (Error err) {
return err;
} catch (...) {
return OxError(1, "Unkown Error");
}
}
template<typename T>
ValErr<T> readOC(const char *json) {
T val; T val;
oxReturnError(model(&reader, &val)); oxReturnError(readOC(json, ox_strlen(json), &val));
return {std::move(val), OxError(0)}; return {std::move(val), OxError(0)};
} }

View File

@ -10,3 +10,4 @@ target_link_libraries(
add_test("Test\\ OcTest\\ Writer" OcTest OrganicClawWriter) add_test("Test\\ OcTest\\ Writer" OcTest OrganicClawWriter)
add_test("Test\\ OcTest\\ Reader" OcTest OrganicClawReader) add_test("Test\\ OcTest\\ Reader" OcTest OrganicClawReader)
add_test("Test\\ OcTest\\ OrganicClawDef" OcTest OrganicClawDef)

View File

@ -8,14 +8,12 @@
#undef NDEBUG #undef NDEBUG
#include <assert.h>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <vector>
#include <ox/oc/oc.hpp>
#include <ox/model/model.hpp> #include <ox/model/model.hpp>
#include <ox/oc/oc.hpp>
#include <ox/std/std.hpp> #include <ox/std/std.hpp>
struct TestStructNest { struct TestStructNest {
@ -128,119 +126,115 @@ std::map<std::string, ox::Error(*)()> tests = {
return OxError(0); return OxError(0);
} }
}, },
//{ {
// "OrganicClawDef", "OrganicClawDef",
// [] { [] {
// auto err = OxError(0); TestStruct testIn, testOut;
// //constexpr size_t descBuffLen = 1024;
// //uint8_t descBuff[descBuffLen];
// constexpr size_t dataBuffLen = 1024;
// uint8_t dataBuff[dataBuffLen];
// TestStruct testIn, testOut;
// testIn.Bool = true; testIn.Bool = true;
// testIn.Int = 42; testIn.Int = 42;
// testIn.String = "Test String 1"; testIn.String = "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.String = "Test String 2";
// oxAssert(ox::writeOC(&testIn), "Data generation failed"); auto [oc, ocErr] = ox::writeOC(&testIn);
// auto type = ox::buildMCDef(&testIn); oxAssert(ocErr, "Data generation failed");
// oxAssert(type.error, "Descriptor write failed"); auto type = ox::buildTypeDef(&testIn);
// ox::walkMC<ox::OrganicClawReader<const char*>>(type.value, dataBuff, dataBuffLen, oxAssert(type.error, "Descriptor write failed");
// [](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::OrganicClawReader<const char*> *rdr) -> ox::Error { ox::walkModel<ox::OrganicClawReader<const char*>>(type.value, ox::bit_cast<uint8_t*>(oc.c_str()), oc.len() + 1,
// //std::cout << f.fieldName.c_str() << '\n'; [](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::OrganicClawReader<const char*> *rdr) -> ox::Error {
// auto fieldName = f.fieldName.c_str(); //std::cout << f.fieldName.c_str() << '\n';
// switch (f.type->primitiveType) { auto fieldName = f.fieldName.c_str();
// case ox::PrimitiveType::UnsignedInteger: switch (f.type->primitiveType) {
// std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t"; case ox::PrimitiveType::UnsignedInteger:
// switch (f.type->length) { std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t";
// case 1: { switch (f.type->length) {
// uint8_t i = {}; case 1: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); uint8_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// case 2: { }
// uint16_t i = {}; case 2: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); uint16_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// case 4: { }
// uint32_t i = {}; case 4: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); uint32_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// case 8: { }
// uint64_t i = {}; case 8: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); uint64_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// } }
// std::cout << '\n'; }
// break; std::cout << '\n';
// case ox::PrimitiveType::SignedInteger: break;
// std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t"; case ox::PrimitiveType::SignedInteger:
// switch (f.type->length) { std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t";
// case 1: { switch (f.type->length) {
// int8_t i = {}; case 1: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); int8_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// case 2: { }
// int16_t i = {}; case 2: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); int16_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// case 4: { }
// int32_t i = {}; case 4: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); int32_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// case 8: { }
// int64_t i = {}; case 8: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); int64_t i = {};
// std::cout << i; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << i;
// } break;
// } }
// std::cout << '\n'; }
// break; std::cout << '\n';
// case ox::PrimitiveType::Bool: { break;
// bool i = {}; case ox::PrimitiveType::Bool: {
// oxAssert(rdr->field(fieldName, &i), "Walking model failed."); bool i = {};
// std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n'; oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
// break; std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n';
// } break;
// case ox::PrimitiveType::String: { }
// ox::Vector<char> v(rdr->stringLength()); case ox::PrimitiveType::String: {
// //std::cout << rdr->stringLength() << '\n'; ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
// oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed."); //std::cout << rdr->stringLength() << '\n';
// std::cout << fieldName << ":\t" << "string: " << v.data() << '\n'; oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
// break; std::cout << fieldName << ":\t" << "string: " << v.data() << '\n';
// } break;
// case ox::PrimitiveType::Struct: }
// break; case ox::PrimitiveType::Struct:
// } break;
// return OxError(0); }
// } return OxError(0);
// ); }
// delete type.value; );
delete type.value;
// return err; return OxError(0);
// } }
//}, },
} }
}; };

View File

@ -15,10 +15,6 @@ OrganicClawWriter<Key>::OrganicClawWriter(Json::Value json) {
m_json = json; m_json = json;
} }
template<typename Key>
OrganicClawWriter<Key>::~OrganicClawWriter() {
}
template<typename Key> template<typename Key>
Error OrganicClawWriter<Key>::field(Key key, int8_t *val) { Error OrganicClawWriter<Key>::field(Key key, int8_t *val) {
if (*val) { if (*val) {
@ -109,8 +105,7 @@ Error OrganicClawWriter<Key>::field(Key key, SerStr val) {
} }
template<typename Key> template<typename Key>
void OrganicClawWriter<Key>::setTypeInfo(const char*, int fields) { void OrganicClawWriter<Key>::setTypeInfo(const char*, int) {
m_fields = fields;
} }
template class OrganicClawWriter<const char*>; template class OrganicClawWriter<const char*>;

View File

@ -26,17 +26,12 @@ class OrganicClawWriter {
protected: protected:
Json::Value m_json; Json::Value m_json;
int m_fields = 0;
int m_field = 0;
uint8_t *m_buff = nullptr;
public: public:
OrganicClawWriter() = default; OrganicClawWriter() = default;
OrganicClawWriter(Json::Value json); OrganicClawWriter(Json::Value json);
~OrganicClawWriter();
Error field(Key, int8_t *val); Error field(Key, int8_t *val);
Error field(Key, int16_t *val); Error field(Key, int16_t *val);
Error field(Key, int32_t *val); Error field(Key, int32_t *val);
@ -67,7 +62,7 @@ class OrganicClawWriter {
void setTypeInfo(const char *name, int fields); void setTypeInfo(const char *name, int fields);
static constexpr OpType opType() { static constexpr auto opType() {
return OpType::Write; return OpType::Write;
} }