232 lines
7.5 KiB
C++
232 lines
7.5 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/utility.hpp>
|
|
|
|
#include "modelvalue.hpp"
|
|
|
|
namespace ox {
|
|
|
|
template<typename Handler, OpType opType_v = Handler::opType()>
|
|
class ModelHandlerInterface {
|
|
private:
|
|
Handler *m_handler = nullptr;
|
|
|
|
public:
|
|
constexpr explicit ModelHandlerInterface(Handler *handler) noexcept: m_handler(handler) {
|
|
}
|
|
|
|
template<typename T = std::nullptr_t>
|
|
constexpr ox::Error setTypeInfo(
|
|
const char* name = T::TypeName,
|
|
int version = T::TypeVersion,
|
|
const Vector<String>& typeParams = {}) noexcept {
|
|
return m_handler->template setTypeInfo<T>(name, version, typeParams, ModelFieldCount_v<T>);
|
|
}
|
|
|
|
template<typename T = std::nullptr_t>
|
|
constexpr ox::Error setTypeInfo(
|
|
const char *name,
|
|
int version,
|
|
const Vector<String>& typeParams,
|
|
std::size_t fields) noexcept {
|
|
return m_handler->template setTypeInfo<T>(name, version, typeParams, fields);
|
|
}
|
|
|
|
template<std::size_t len>
|
|
constexpr Error fieldCString(const char *name, char val[len]) noexcept {
|
|
return m_handler->fieldCString(name, &val[0], len);
|
|
}
|
|
|
|
template<std::size_t len>
|
|
constexpr Error fieldCString(const char *name, const char val[len]) noexcept requires(opType_v != OpType::Read) {
|
|
if constexpr(opType_v != OpType::Read) {
|
|
return m_handler->fieldCString(name, &val[0], len);
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
constexpr Error fieldCString(const char *name, char **val) noexcept {
|
|
return m_handler->fieldCString(name, val);
|
|
}
|
|
|
|
constexpr Error fieldCString(const char *name, const char *const*val) noexcept requires(opType_v != OpType::Read) {
|
|
// this check looks pointless, but it's to address a Clang bug
|
|
if constexpr(opType_v != OpType::Read) {
|
|
return m_handler->fieldCString(name, val);
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
constexpr Error fieldCString(const char *name, const char **val) noexcept requires(opType_v != OpType::Read) {
|
|
// this check looks pointless, but it's to address a Clang bug
|
|
if constexpr(opType_v != OpType::Read) {
|
|
return m_handler->fieldCString(name, val);
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
|
|
return m_handler->fieldCString(name, val, buffLen);
|
|
}
|
|
|
|
constexpr Error fieldCString(const char *name, const char **val, std::size_t buffLen) noexcept requires(opType_v != OpType::Read) {
|
|
// this check looks pointless, but it's to address a Clang bug
|
|
if constexpr(opType_v != OpType::Read) {
|
|
return m_handler->fieldCString(name, val, buffLen);
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
|
|
return m_handler->fieldCString(name, val, buffLen);
|
|
}
|
|
|
|
constexpr Error fieldModelValue(const char *name, CommonPtrWith<ModelValue> auto *v) noexcept {
|
|
switch (v->type()) {
|
|
case ModelValue::Type::Undefined:
|
|
break;
|
|
case ModelValue::Type::Bool:
|
|
return m_handler->field(name, &v->template get<bool>());
|
|
case ModelValue::Type::UnsignedInteger8:
|
|
return m_handler->field(name, &v->template get<uint8_t>());
|
|
case ModelValue::Type::UnsignedInteger16:
|
|
return m_handler->field(name, &v->template get<uint16_t>());
|
|
case ModelValue::Type::UnsignedInteger32:
|
|
return m_handler->field(name, &v->template get<uint32_t>());
|
|
case ModelValue::Type::UnsignedInteger64:
|
|
return m_handler->field(name, &v->template get<uint64_t>());
|
|
case ModelValue::Type::SignedInteger8:
|
|
return m_handler->field(name, &v->template get<int8_t>());
|
|
case ModelValue::Type::SignedInteger16:
|
|
return m_handler->field(name, &v->template get<int16_t>());
|
|
case ModelValue::Type::SignedInteger32:
|
|
return m_handler->field(name, &v->template get<int32_t>());
|
|
case ModelValue::Type::SignedInteger64:
|
|
return m_handler->field(name, &v->template get<int64_t>());
|
|
case ModelValue::Type::String:
|
|
return m_handler->field(name, &v->template get<String>());
|
|
case ModelValue::Type::Object:
|
|
return m_handler->field(name, &v->template get<ModelObject>());
|
|
case ModelValue::Type::Union:
|
|
{
|
|
auto &u = v->template get<ModelUnion>();
|
|
if constexpr(opType_v == OpType::Read) {
|
|
u.setActiveField(m_handler->whichFieldPresent(name, u));
|
|
return m_handler->field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
|
|
} else {
|
|
return m_handler->field(name, UnionView<const ModelUnion, true>(&u, u.unionIdx()));
|
|
}
|
|
}
|
|
case ModelValue::Type::Vector:
|
|
return m_handler->field(name, &v->template get<ModelValueVector>());
|
|
case ModelValue::Type::InlineArray:
|
|
return m_handler->field(name, &v->template get<ModelValueArray>());
|
|
}
|
|
oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type()));
|
|
oxPanic(ox::Error(1), "invalid type");
|
|
return ox::Error(1, "invalid type");
|
|
}
|
|
|
|
// array handler, with callback to allow handling individual elements
|
|
template<typename T, typename Callback>
|
|
constexpr Error field(const char *name, Callback cb) noexcept {
|
|
return m_handler->template field<T, Callback>(name, cb);
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr Error field(const char *name, const T *v) noexcept {
|
|
if constexpr(ox::is_same_v<T, ModelValue>) {
|
|
return fieldModelValue(name, v);
|
|
} else {
|
|
return m_handler->field(name, v);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr Error field(const char *name, T *v) noexcept {
|
|
if constexpr(ox::is_same_v<T, ModelValue>) {
|
|
return fieldModelValue(name, v);
|
|
} else {
|
|
return m_handler->field(name, v);
|
|
}
|
|
}
|
|
|
|
template<typename U, bool force = false>
|
|
constexpr Error field(const char *name, UnionView<U, force> val) noexcept {
|
|
return m_handler->field(name, val);
|
|
}
|
|
|
|
constexpr Error field(const char *name, auto *val, std::size_t len) noexcept {
|
|
return m_handler->field(name, val, len);
|
|
}
|
|
|
|
/**
|
|
* Reads an array length from the current location in the buffer.
|
|
* @param pass indicates that the parsing should iterate past the array length
|
|
*/
|
|
[[nodiscard]]
|
|
constexpr auto arrayLength(const char *name, bool pass = true) noexcept {
|
|
return m_handler->arrayLength(name, pass);
|
|
}
|
|
|
|
/**
|
|
* Reads an string length from the current location in the buffer.
|
|
*/
|
|
[[nodiscard]]
|
|
constexpr auto stringLength(const char *name) noexcept {
|
|
return m_handler->stringLength(name);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
static constexpr auto opType() noexcept {
|
|
return Handler::opType();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr auto handler() noexcept {
|
|
return m_handler;
|
|
}
|
|
};
|
|
|
|
template<typename Handler, ox::OpType opType_v = Handler::opType()>
|
|
class ModelHandlerBase {
|
|
private:
|
|
ModelHandlerInterface<Handler, opType_v> m_interface;
|
|
public:
|
|
constexpr ModelHandlerBase() noexcept: m_interface(static_cast<Handler*>(this)) {}
|
|
constexpr ModelHandlerBase(const ModelHandlerBase&) noexcept: m_interface(static_cast<Handler*>(this)) {}
|
|
constexpr ModelHandlerBase(ModelHandlerBase&&) noexcept: m_interface(static_cast<Handler*>(this)) {}
|
|
[[nodiscard]]
|
|
constexpr auto interface() noexcept {
|
|
return &m_interface;
|
|
}
|
|
[[nodiscard]]
|
|
static constexpr ox::OpType opType() noexcept {
|
|
return opType_v;
|
|
}
|
|
};
|
|
|
|
|
|
constexpr ox::Error resizeVector(auto &vec, size_t sz) {
|
|
if constexpr(ox::is_same_v<decltype(vec.resize(0)), ox::Error>) {
|
|
return vec.resize(sz);
|
|
} else {
|
|
vec.resize(sz);
|
|
return {};
|
|
}
|
|
}
|
|
|
|
}
|