Files
ox/include/ox/oc/write.hpp
T

286 lines
7.2 KiB
C++

/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* 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 https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/def.hpp>
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
#include <json/json.h>
OX_ALLOW_UNSAFE_BUFFERS_END
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/model/typenamecatcher.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/string.hpp>
#include <ox/std/uuid.hpp>
namespace ox {
class OrganicClawWriter {
friend Result<Buffer> writeOC(const auto &val) noexcept;
friend Result<String> writeOCString(const auto &val) noexcept;
protected:
Json::Value m_json{Json::Value(Json::objectValue)};
Json::ArrayIndex m_fieldIt = 0;
int const m_unionIdx = -1;
public:
explicit OrganicClawWriter(int unionIdx = -1) noexcept;
explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept;
Error field(CString const key, int8_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, int16_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, int32_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, int64_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, uint8_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, uint16_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, uint32_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(CString const key, uint64_t const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
Error field(char const*key, bool const *val) noexcept {
if (targetValid() && (*val || m_json.isArray())) {
value(key) = *val;
}
++m_fieldIt;
return {};
}
template<typename U, bool force = true>
Error field(char const*, UnionView<U, force> val) noexcept;
template<typename T>
Error field(char const*key, HashMap<String, T> const *val) noexcept {
if (targetValid()) {
const auto &keys = val->keys();
OrganicClawWriter w;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
for (size_t i = 0; i < keys.size(); ++i) {
const auto k = keys[i].c_str();
if (k) [[likely]] {
OX_REQUIRE_M(value, val->at(k));
OX_RETURN_ERROR(handler.field(k, value));
}
}
value(key) = w.m_json;
}
++m_fieldIt;
return {};
}
template<size_t L>
Error field(char const*key, IString<L> const *val) noexcept {
if (targetValid() && val->size()) {
value(key) = val->c_str();
}
++m_fieldIt;
return {};
}
template<size_t L>
Error field(char const*key, BasicString<L> const *val) noexcept {
if (targetValid() && val->size()) {
value(key) = val->c_str();
}
++m_fieldIt;
return {};
}
Error fieldCString(CString, CString const *val, int len) noexcept;
Error fieldCString(CString name, CString const*val) noexcept;
Error field(CString key, UUID const *uuid) noexcept;
template<typename T>
Error field(CString, T const *val, size_t len) noexcept;
template<typename T>
Error field(CString, T const *val) noexcept;
template<typename T>
constexpr Error setTypeInfo(
const char* = T::TypeName,
int = T::TypeVersion) noexcept {
return {};
}
template<typename T>
constexpr Error setTypeInfo(
const char*,
int,
Vector<String> const&,
size_t) noexcept {
return {};
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Write;
}
private:
[[nodiscard]]
constexpr bool targetValid() const noexcept {
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
}
[[nodiscard]]
Json::Value &value(CString key) noexcept;
};
template<typename T>
Error OrganicClawWriter::field(CString key, T const *val, size_t const len) noexcept {
if (targetValid() && len) {
OrganicClawWriter w((Json::Value(Json::arrayValue)));
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
for (size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
value(key) = w.m_json;
}
++m_fieldIt;
return {};
}
template<typename T>
Error OrganicClawWriter::field(CString key, T const *val) noexcept {
if constexpr(is_integer_v<T>) {
if (targetValid() && (*val || m_json.isArray())) {
// the int type needs to be normalized because jsoncpp doesn't
// factor in every permutation unsigned long, etc.
if constexpr(is_signed_v<T>) {
value(key) = static_cast<Int<8 * sizeof(*val)>>(*val);
} else {
value(key) = static_cast<Uint<8 * sizeof(*val)>>(*val);
}
}
} else if constexpr(isVector_v<T> || isArray_v<T>) {
return field(key, val->data(), val->size());
} else if (val && targetValid()) {
OrganicClawWriter w;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
OX_RETURN_ERROR(model(&handler, val));
if (!w.m_json.empty() || m_json.isArray()) {
value(key) = w.m_json;
}
}
++m_fieldIt;
return {};
}
template<typename U, bool force>
Error OrganicClawWriter::field(CString key, UnionView<U, force> val) noexcept {
if (targetValid()) {
OrganicClawWriter w(val.idx());
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{w};
OX_RETURN_ERROR(model(&handler, val.get()));
if (!w.m_json.isNull()) {
value(key) = w.m_json;
}
}
++m_fieldIt;
return {};
}
Result<Buffer> writeOC(auto const &val) noexcept {
OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json);
Result<Buffer> buff;
buff.value.resize(str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(buff.value.data(), str.data(), str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_END
return buff;
}
Result<String> writeOCString(auto const &val) noexcept {
OrganicClawWriter writer;
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(writer);
OX_RETURN_ERROR(model(&handler, &val));
Json::StreamWriterBuilder const jsonBuilder;
auto const str = Json::writeString(jsonBuilder, writer.m_json);
Result<String> buff;
buff.value.resize(str.size());
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(buff.value.data(), str.data(), str.size() + 1);
OX_ALLOW_UNSAFE_BUFFERS_END
return buff;
}
}