From 89854a584af44ffa75c341a6b620afdb98755431 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 7 Apr 2020 21:54:56 -0500 Subject: [PATCH] [ox/oc] Add OrganicClaw --- deps/ox/src/ox/CMakeLists.txt | 1 + deps/ox/src/ox/oc/CMakeLists.txt | 40 ++++ deps/ox/src/ox/oc/oc.hpp | 12 ++ deps/ox/src/ox/oc/read.cpp | 116 ++++++++++++ deps/ox/src/ox/oc/read.hpp | 140 ++++++++++++++ deps/ox/src/ox/oc/test/CMakeLists.txt | 12 ++ deps/ox/src/ox/oc/test/tests.cpp | 256 ++++++++++++++++++++++++++ deps/ox/src/ox/oc/write.cpp | 119 ++++++++++++ deps/ox/src/ox/oc/write.hpp | 122 ++++++++++++ 9 files changed, 818 insertions(+) create mode 100644 deps/ox/src/ox/oc/CMakeLists.txt create mode 100644 deps/ox/src/ox/oc/oc.hpp create mode 100644 deps/ox/src/ox/oc/read.cpp create mode 100644 deps/ox/src/ox/oc/read.hpp create mode 100644 deps/ox/src/ox/oc/test/CMakeLists.txt create mode 100644 deps/ox/src/ox/oc/test/tests.cpp create mode 100644 deps/ox/src/ox/oc/write.cpp create mode 100644 deps/ox/src/ox/oc/write.hpp diff --git a/deps/ox/src/ox/CMakeLists.txt b/deps/ox/src/ox/CMakeLists.txt index 2cd87399..28ab4e51 100644 --- a/deps/ox/src/ox/CMakeLists.txt +++ b/deps/ox/src/ox/CMakeLists.txt @@ -1,5 +1,6 @@ if(${OX_USE_STDLIB}) add_subdirectory(clargs) + add_subdirectory(oc) endif() add_subdirectory(fs) add_subdirectory(mc) diff --git a/deps/ox/src/ox/oc/CMakeLists.txt b/deps/ox/src/ox/oc/CMakeLists.txt new file mode 100644 index 00000000..f47fe395 --- /dev/null +++ b/deps/ox/src/ox/oc/CMakeLists.txt @@ -0,0 +1,40 @@ +add_library( + OxOrganicClaw + read.cpp + write.cpp +) + +find_package(JsonCpp REQUIRED) + +target_compile_options(OxOrganicClaw PRIVATE -Wsign-conversion) + +target_link_libraries( + OxOrganicClaw PUBLIC + OxModel + JsonCpp::JsonCpp +) + +set_property( + TARGET + OxOrganicClaw + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +install( + FILES + oc.hpp + read.hpp + write.hpp + DESTINATION + include/ox/oc +) + +install(TARGETS OxOrganicClaw + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) + +if(OX_RUN_TESTS STREQUAL "ON") + add_subdirectory(test) +endif() diff --git a/deps/ox/src/ox/oc/oc.hpp b/deps/ox/src/ox/oc/oc.hpp new file mode 100644 index 00000000..3578d6a3 --- /dev/null +++ b/deps/ox/src/ox/oc/oc.hpp @@ -0,0 +1,12 @@ +/* + * 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 "read.hpp" +#include "write.hpp" diff --git a/deps/ox/src/ox/oc/read.cpp b/deps/ox/src/ox/oc/read.cpp new file mode 100644 index 00000000..fef0afc3 --- /dev/null +++ b/deps/ox/src/ox/oc/read.cpp @@ -0,0 +1,116 @@ +/* + * 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/. + */ + +#include "read.hpp" + +namespace ox { + +template +OrganicClawReader::OrganicClawReader(Json::Value json) { + m_json = json; +} + +template +OrganicClawReader::~OrganicClawReader() { +} + +template +Error OrganicClawReader::field(Key key, int8_t *val) { + *val = static_cast(m_json[key].asInt()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, int16_t *val) { + *val = static_cast(m_json[key].asInt()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, int32_t *val) { + *val = static_cast(m_json[key].asInt()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, int64_t *val) { + *val = static_cast(m_json[key].asInt64()); + return OxError(0); +} + + +template +Error OrganicClawReader::field(Key key, uint8_t *val) { + *val = static_cast(m_json[key].asUInt()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, uint16_t *val) { + *val = static_cast(m_json[key].asUInt()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, uint32_t *val) { + *val = static_cast(m_json[key].asUInt()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, uint64_t *val) { + *val = static_cast(m_json[key].asUInt64()); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, bool *val) { + *val = m_json[key].asBool(); + return OxError(0); +} + +template +Error OrganicClawReader::field(Key key, SerStr val) { + const char *begin = nullptr, *end = nullptr; + m_json[key].getString(&begin, &end); + auto strSize = end - begin; + if (strSize >= val.cap()) { + return OxError(1); + } + ox_memcpy(val.data(), begin, static_cast(strSize)); + val.data()[strSize] = 0; + return OxError(0); +} + +template +[[nodiscard]] std::size_t OrganicClawReader::arrayLength(Key key, bool) { + return m_json[key].size(); +} + +template +[[nodiscard]] std::size_t OrganicClawReader::stringLength(Key key) { + const char *begin = nullptr, *end = nullptr; + m_json[key].getString(&begin, &end); + return static_cast(end - begin); +} + +template +void OrganicClawReader::setTypeInfo(const char*, int fields) { + m_fields = fields; + m_buffIt = static_cast((fields / 8 + 1) - (fields % 8 == 0)); +} + +template +OrganicClawReader OrganicClawReader::child(Key key) { + return OrganicClawReader(m_json[key]); +} + +template class OrganicClawReader; +template class OrganicClawReader; + +} diff --git a/deps/ox/src/ox/oc/read.hpp b/deps/ox/src/ox/oc/read.hpp new file mode 100644 index 00000000..378715b3 --- /dev/null +++ b/deps/ox/src/ox/oc/read.hpp @@ -0,0 +1,140 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include + +namespace ox { + +template +class OrganicClawReader { + + private: + Json::Value m_json; + int m_fields = 0; + int m_field = 0; + std::size_t m_buffIt = 0; + std::size_t m_buffLen = 0; + uint8_t *m_buff = nullptr; + + public: + OrganicClawReader(Json::Value json = {}); + + ~OrganicClawReader(); + + [[nodiscard]] Error field(Key key, int8_t *val); + [[nodiscard]] Error field(Key key, int16_t *val); + [[nodiscard]] Error field(Key key, int32_t *val); + [[nodiscard]] Error field(Key key, int64_t *val); + + [[nodiscard]] Error field(Key key, uint8_t *val); + [[nodiscard]] Error field(Key key, uint16_t *val); + [[nodiscard]] Error field(Key key, uint32_t *val); + [[nodiscard]] Error field(Key key, uint64_t *val); + + [[nodiscard]] Error field(Key key, bool *val); + + // array handler + template + [[nodiscard]] Error field(Key key, T *val, std::size_t len); + + template + [[nodiscard]] Error field(Key key, ox::Vector *val); + + template + [[nodiscard]] Error field(Key key, T *val); + + template + [[nodiscard]] Error field(Key key, ox::BString *val); + + [[nodiscard]] Error field(Key key, SerStr val); + + /** + * Reads an array length from the current location in the buffer. + * @param pass indicates that the parsing should iterate past the array length + */ + [[nodiscard]] std::size_t arrayLength(Key key, bool pass = true); + + /** + * Reads an string length from the current location in the buffer. + */ + [[nodiscard]] std::size_t stringLength(Key name); + + void setTypeInfo(const char *name, int fields); + + /** + * Returns a OrganicClawReader to parse a child object. + */ + [[nodiscard]] OrganicClawReader child(Key key); + + static constexpr OpType opType() { + return OpType::Read; + } + +}; + +template +template +Error OrganicClawReader::field(Key key, T *val) { + if (val) { + auto reader = child(key); + oxReturnError(model(&reader, val)); + } + return OxError(0); +} + +template +template +Error OrganicClawReader::field(Key name, ox::BString *val) { + return field(name, SerStr(val->data(), val->cap())); +} + +// array handler +template +template +Error OrganicClawReader::field(Key key, T *val, std::size_t valLen) { + const auto &srcVal = m_json[key]; + auto srcSize = srcVal.size(); + if (srcSize > valLen) { + return OxError(1); + } + OrganicClawReader r(srcVal); + for (decltype(srcSize) i = 0; i < srcSize; ++i) { + oxReturnError(r.field(i, &val[i])); + } + return OxError(0); +} + +template +template +Error OrganicClawReader::field(Key key, ox::Vector *val) { + return field(nullptr, val->data(), val->size()); +} + +template +ValErr readOC(const char *json) { + Json::Value doc; + Json::CharReaderBuilder parserBuilder; + auto parser = std::unique_ptr(parserBuilder.newCharReader()); + if (!parser->parse(json, json + ox_strlen(json), &doc, nullptr)) { + return OxError(1, "Could not parse JSON"); + } + OrganicClawReader reader(doc); + T val; + oxReturnError(model(&reader, &val)); + return {std::move(val), OxError(0)}; +} + +} diff --git a/deps/ox/src/ox/oc/test/CMakeLists.txt b/deps/ox/src/ox/oc/test/CMakeLists.txt new file mode 100644 index 00000000..d4175837 --- /dev/null +++ b/deps/ox/src/ox/oc/test/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable( + OcTest + tests.cpp +) + +target_link_libraries( + OcTest + OxOrganicClaw +) + +add_test("Test\\ OcTest\\ Writer" OcTest OrganicClawWriter) +add_test("Test\\ OcTest\\ Reader" OcTest OrganicClawReader) diff --git a/deps/ox/src/ox/oc/test/tests.cpp b/deps/ox/src/ox/oc/test/tests.cpp new file mode 100644 index 00000000..3bbb84ef --- /dev/null +++ b/deps/ox/src/ox/oc/test/tests.cpp @@ -0,0 +1,256 @@ +/* + * Copyright 2015 - 2020 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/. + */ + +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct TestStructNest { + bool Bool = false; + uint32_t Int = 0; + ox::BString<32> String = ""; +}; + +struct TestStruct { + bool Bool = false; + int32_t Int = 0; + int32_t Int1 = 0; + int32_t Int2 = 0; + int32_t Int3 = 0; + int32_t Int4 = 0; + int32_t Int5 = 0; + int32_t Int6 = 0; + int32_t Int7 = 0; + int32_t Int8 = 0; + ox::BString<32> String = ""; + uint32_t List[4] = {0, 0, 0 , 0}; + TestStructNest EmptyStruct; + TestStructNest Struct; +}; + +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; +} + +template +ox::Error model(T *io, TestStruct *obj) { + io->setTypeInfo("TestStruct", 14); + 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("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 = { + { + { + "OrganicClawWriter", + [] { + // This test doesn't confirm much, but it does show that the writer + // doesn't segfault + TestStruct ts; + return ox::writeOC(&ts).error; + } + }, + { + "OrganicClawReader", + [] { + TestStruct testIn; + testIn.Bool = true; + testIn.Int = 42; + testIn.String = "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"; + + auto [oc, writeErr] = ox::writeOC(&testIn); + oxAssert(writeErr, "writeOC failed"); + std::cout << oc.c_str() << '\n'; + auto [testOut, readErr] = ox::readOC(oc.c_str()); + oxAssert(readErr, "readOC failed"); + + oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); + oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); + oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch"); + oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch"); + oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch"); + oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch"); + oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch"); + 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.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"); + oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch"); + oxAssert(testIn.List[3] == testOut.List[3], "List[3] 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.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch"); + oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch"); + oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch"); + + return OxError(0); + } + }, + //{ + // "OrganicClawDef", + // [] { + // auto err = OxError(0); + // //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.Int = 42; + // testIn.String = "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"; + + // oxAssert(ox::writeOC(&testIn), "Data generation failed"); + // auto type = ox::buildMCDef(&testIn); + // oxAssert(type.error, "Descriptor write failed"); + // ox::walkMC>(type.value, dataBuff, dataBuffLen, + // [](const ox::Vector&, const ox::Vector&, const ox::DescriptorField &f, ox::OrganicClawReader *rdr) -> ox::Error { + // //std::cout << f.fieldName.c_str() << '\n'; + // auto fieldName = f.fieldName.c_str(); + // switch (f.type->primitiveType) { + // case ox::PrimitiveType::UnsignedInteger: + // std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t"; + // switch (f.type->length) { + // case 1: { + // uint8_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // case 2: { + // uint16_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // case 4: { + // uint32_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // case 8: { + // uint64_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // } + // std::cout << '\n'; + // break; + // case ox::PrimitiveType::SignedInteger: + // std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t"; + // switch (f.type->length) { + // case 1: { + // int8_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // case 2: { + // int16_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // case 4: { + // int32_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // case 8: { + // int64_t i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << i; + // break; + // } + // } + // std::cout << '\n'; + // break; + // case ox::PrimitiveType::Bool: { + // bool i = {}; + // oxAssert(rdr->field(fieldName, &i), "Walking model failed."); + // std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n'; + // break; + // } + // case ox::PrimitiveType::String: { + // ox::Vector v(rdr->stringLength()); + // //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'; + // break; + // } + // case ox::PrimitiveType::Struct: + // break; + // } + // return OxError(0); + // } + // ); + // delete type.value; + + // return err; + // } + //}, + } +}; + +int main(int argc, const char **args) { + int retval = -1; + if (argc > 0) { + auto testName = args[1]; + if (tests.find(testName) != tests.end()) { + retval = tests[testName](); + } + } + return retval; +} diff --git a/deps/ox/src/ox/oc/write.cpp b/deps/ox/src/ox/oc/write.cpp new file mode 100644 index 00000000..d9520258 --- /dev/null +++ b/deps/ox/src/ox/oc/write.cpp @@ -0,0 +1,119 @@ +/* + * 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/. + */ + +#include "write.hpp" + +namespace ox { + +template +OrganicClawWriter::OrganicClawWriter(Json::Value json) { + m_json = json; +} + +template +OrganicClawWriter::~OrganicClawWriter() { +} + +template +Error OrganicClawWriter::field(Key key, int8_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, int16_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, int32_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, int64_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + + +template +Error OrganicClawWriter::field(Key key, uint8_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, uint16_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, uint32_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, uint64_t *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, bool *val) { + if (*val) { + m_json[key] = *val; + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, ox::String val) { + if (val.len()) { + m_json[key] = val.c_str(); + } + return OxError(0); +} + +template +Error OrganicClawWriter::field(Key key, SerStr val) { + if (val.len()) { + m_json[key] = val.c_str(); + } + return OxError(0); +} + +template +void OrganicClawWriter::setTypeInfo(const char*, int fields) { + m_fields = fields; +} + +template class OrganicClawWriter; +template class OrganicClawWriter; + +} diff --git a/deps/ox/src/ox/oc/write.hpp b/deps/ox/src/ox/oc/write.hpp new file mode 100644 index 00000000..8959f577 --- /dev/null +++ b/deps/ox/src/ox/oc/write.hpp @@ -0,0 +1,122 @@ +/* + * 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 + +#include +#include +#include +#include + +namespace ox { + +template +class OrganicClawWriter { + friend OrganicClawWriter; + friend OrganicClawWriter; + template + friend ValErr writeOC(T *val); + + protected: + Json::Value m_json; + int m_fields = 0; + int m_field = 0; + uint8_t *m_buff = nullptr; + + public: + OrganicClawWriter() = default; + + OrganicClawWriter(Json::Value json); + + ~OrganicClawWriter(); + + Error field(Key, int8_t *val); + Error field(Key, int16_t *val); + Error field(Key, int32_t *val); + Error field(Key, int64_t *val); + + Error field(Key, uint8_t *val); + Error field(Key, uint16_t *val); + Error field(Key, uint32_t *val); + Error field(Key, uint64_t *val); + + Error field(Key, bool *val); + + template + Error field(Key, T *val, std::size_t len); + + template + Error field(Key, ox::Vector *val); + + template + Error field(Key, ox::BString *val); + + Error field(Key, ox::String val); + + Error field(Key, SerStr val); + + template + Error field(Key, T *val); + + void setTypeInfo(const char *name, int fields); + + static constexpr OpType opType() { + return OpType::Write; + } + +}; + +template +template +Error OrganicClawWriter::field(Key key, T *val, std::size_t len) { + OrganicClawWriter w; + for (std::size_t i = 0; i < len; ++i) { + oxReturnError(w.field(i, &val[i])); + } + m_json[key] = w.m_json; + return OxError(0); +} + +template +template +Error OrganicClawWriter::field(Key key, ox::BString *val) { + return field(key, SerStr(val->data(), val->cap())); +} + +template +template +Error OrganicClawWriter::field(Key key, T *val) { + OrganicClawWriter w; + oxReturnError(model(&w, val)); + if (!w.m_json.isNull()) { + m_json[key] = w.m_json; + } + return OxError(0); +} + +template +template +Error OrganicClawWriter::field(Key key, ox::Vector *val) { + return field(key, val->data(), val->size()); +} + + +template +ValErr writeOC(T *val) { + OrganicClawWriter writer; + oxReturnError(model(&writer, val)); + Json::StreamWriterBuilder jsonBuilder; + return String(Json::writeString(jsonBuilder, writer.m_json).c_str()); +} + +extern template class OrganicClawWriter; +extern template class OrganicClawWriter; + +}