278 lines
7.2 KiB
C++
278 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 <json/json.h>
|
|
|
|
#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<ox::Buffer> writeOC(const auto &val) noexcept;
|
|
friend Result<ox::String> writeOCString(const auto &val) noexcept;
|
|
|
|
protected:
|
|
Json::Value m_json{Json::Value(Json::objectValue)};
|
|
Json::ArrayIndex m_fieldIt = 0;
|
|
int m_unionIdx = -1;
|
|
|
|
public:
|
|
explicit OrganicClawWriter(int unionIdx = -1) noexcept;
|
|
|
|
explicit OrganicClawWriter(Json::Value json, int unionIdx = -1) noexcept;
|
|
|
|
Error field(const char *key, const int8_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error field(const char *key, const int16_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error field(const char *key, const int32_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error field(const char *key, const int64_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
|
|
Error field(const char *key, const uint8_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error field(const char *key, const uint16_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error field(const char *key, const uint32_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error field(const char *key, const uint64_t *val) noexcept {
|
|
if (targetValid() && (*val || m_json.isArray())) {
|
|
value(key) = *val;
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
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 (std::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<std::size_t L>
|
|
Error field(char const*key, IString<L> const*val) noexcept {
|
|
if (targetValid() && val->len()) {
|
|
value(key) = val->c_str();
|
|
}
|
|
++m_fieldIt;
|
|
return {};
|
|
}
|
|
|
|
template<std::size_t L>
|
|
Error field(char const*key, BasicString<L> const*val) noexcept {
|
|
if (targetValid() && val->len()) {
|
|
value(key) = val->c_str();
|
|
}
|
|
++m_fieldIt;
|
|
return ox::Error(0);
|
|
}
|
|
|
|
Error fieldCString(const char*, const char *const*val, int len) noexcept;
|
|
|
|
Error fieldCString(const char *name, const char *const*val) noexcept;
|
|
|
|
Error field(const char *key, const UUID *uuid) noexcept;
|
|
|
|
template<typename T>
|
|
Error field(const char*, const T *val, std::size_t len) noexcept;
|
|
|
|
template<typename T>
|
|
Error field(const char*, const T *val) noexcept;
|
|
|
|
template<typename T>
|
|
constexpr ox::Error setTypeInfo(
|
|
const char* = T::TypeName,
|
|
int = T::TypeVersion) noexcept {
|
|
return {};
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr ox::Error setTypeInfo(
|
|
const char*,
|
|
int,
|
|
const Vector<String>&,
|
|
std::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(const char *key) noexcept;
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
Error OrganicClawWriter::field(const char *key, const T *val, std::size_t len) noexcept {
|
|
if (targetValid() && len) {
|
|
OrganicClawWriter w((Json::Value(Json::arrayValue)));
|
|
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler{&w};
|
|
for (std::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 ox::Error(0);
|
|
}
|
|
|
|
template<typename T>
|
|
Error OrganicClawWriter::field(const char *key, const T *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(ox::is_signed_v<T>) {
|
|
value(key) = static_cast<ox::Int<8 * sizeof(*val)>>(*val);
|
|
} else {
|
|
value(key) = static_cast<ox::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 ox::Error(0);
|
|
}
|
|
|
|
template<typename U, bool force>
|
|
Error OrganicClawWriter::field(const char *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 ox::Error(0);
|
|
}
|
|
|
|
Result<ox::Buffer> writeOC(const auto &val) noexcept {
|
|
OrganicClawWriter writer;
|
|
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(&writer);
|
|
OX_RETURN_ERROR(model(&handler, &val));
|
|
Json::StreamWriterBuilder const jsonBuilder;
|
|
const auto str = Json::writeString(jsonBuilder, writer.m_json);
|
|
Result<Buffer> buff;
|
|
buff.value.resize(str.size() + 1);
|
|
memcpy(buff.value.data(), str.data(), str.size() + 1);
|
|
return buff;
|
|
}
|
|
|
|
Result<ox::String> writeOCString(const auto &val) noexcept {
|
|
OrganicClawWriter writer;
|
|
ModelHandlerInterface<OrganicClawWriter, OpType::Write> handler(&writer);
|
|
OX_RETURN_ERROR(model(&handler, &val));
|
|
Json::StreamWriterBuilder const jsonBuilder;
|
|
const auto str = Json::writeString(jsonBuilder, writer.m_json);
|
|
Result<ox::String> buff;
|
|
buff.value.resize(str.size());
|
|
memcpy(buff.value.data(), str.data(), str.size() + 1);
|
|
return buff;
|
|
}
|
|
|
|
}
|