/* * 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 #include "modelvalue.hpp" namespace ox { template class ModelHandlerInterface { private: Handler &m_handler; public: constexpr explicit ModelHandlerInterface(Handler &handler) noexcept: m_handler(handler) { } template constexpr ox::Error setTypeInfo( CString name = T::TypeName, int version = T::TypeVersion, Vector const &typeParams = {}) noexcept { return m_handler.template setTypeInfo(name, version, typeParams, ModelFieldCount_v); } template constexpr ox::Error setTypeInfo( CString name, int version, Vector const &typeParams, size_t fields) noexcept { return m_handler.template setTypeInfo(name, version, typeParams, fields); } template constexpr Error fieldCString(CString name, char val[len]) noexcept { return m_handler.fieldCString(name, &val[0], len); } template constexpr Error fieldCString(CString name, char const 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(CString name, char **val) noexcept { return m_handler.fieldCString(name, val); } constexpr Error fieldCString(CString name, char const *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(CString name, 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(CString name, char **val, size_t buffLen) noexcept { return m_handler.fieldCString(name, val, buffLen); } constexpr Error fieldCString(CString name, char const **val, 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(CString name, char *val, size_t buffLen) noexcept { return m_handler.fieldCString(name, val, buffLen); } constexpr Error fieldModelValue(char const *name, CommonPtrWith auto *v) noexcept { switch (v->type()) { case ModelValue::Type::Undefined: break; case ModelValue::Type::Bool: return m_handler.field(name, &v->template get()); case ModelValue::Type::UnsignedInteger8: return m_handler.field(name, &v->template get()); case ModelValue::Type::UnsignedInteger16: return m_handler.field(name, &v->template get()); case ModelValue::Type::UnsignedInteger32: return m_handler.field(name, &v->template get()); case ModelValue::Type::UnsignedInteger64: return m_handler.field(name, &v->template get()); case ModelValue::Type::SignedInteger8: return m_handler.field(name, &v->template get()); case ModelValue::Type::SignedInteger16: return m_handler.field(name, &v->template get()); case ModelValue::Type::SignedInteger32: return m_handler.field(name, &v->template get()); case ModelValue::Type::SignedInteger64: return m_handler.field(name, &v->template get()); case ModelValue::Type::String: return m_handler.field(name, &v->template get()); case ModelValue::Type::Object: return m_handler.field(name, &v->template get()); case ModelValue::Type::Union: { auto &u = v->template get(); if constexpr(opType_v == OpType::Read) { u.setActiveField(whichFieldPresent(m_handler, name, u)); return m_handler.field(name, UnionView(&u, u.unionIdx())); } else { return m_handler.field(name, UnionView(&u, u.unionIdx())); } } case ModelValue::Type::Vector: return m_handler.field(name, &v->template get()); case ModelValue::Type::InlineArray: return m_handler.field(name, &v->template get()); } oxErrf("invalid type: {}: {}\n", name, static_cast(v->type())); ox::panic("invalid type"); return ox::Error(1, "invalid type"); } // array handler, with callback to allow handling individual elements template constexpr Error field(CString name, Callback cb) noexcept { return m_handler.template field(name, cb); } template constexpr Error field(CString name, const T *v) noexcept { if constexpr(ox::is_same_v) { return fieldModelValue(name, v); } else { return m_handler.field(name, v); } } template constexpr Error field(CString name, T *v) noexcept { if constexpr(ox::is_same_v) { return fieldModelValue(name, v); } else { return m_handler.field(name, v); } } template constexpr Error field(CString name, UnionView val) noexcept { return m_handler.field(name, val); } constexpr Error field(CString name, auto *val, size_t len) noexcept { return m_handler.field(name, val, len); } /** * Reads an array length from the current location in the buffer. * @param name * @param pass indicates that the parsing should iterate past the array length */ [[nodiscard]] constexpr auto arrayLength(CString 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(CString name) noexcept { return m_handler.stringLength(name); } [[nodiscard]] static constexpr auto opType() noexcept { return Handler::opType(); } [[nodiscard]] constexpr auto handler() noexcept { return m_handler; } private: template static constexpr int whichFieldPresent(H &h, CString name, ModelUnion const &u) noexcept requires(H::opType() == OpType::Read) { return h.whichFieldPresent(name, u); } template static constexpr int whichFieldPresent(H&, CString, ModelUnion const&) noexcept requires(H::opType() != OpType::Read) { return 0; } }; template class ModelHandlerBase { private: ModelHandlerInterface m_interface{*static_cast(this)}; public: [[nodiscard]] constexpr auto interface() noexcept { return &m_interface; } [[nodiscard]] static constexpr OpType opType() noexcept { return opType_v; } }; constexpr ox::Error resizeVector(auto &vec, size_t sz) { if constexpr(ox::is_same_v) { return vec.resize(sz); } else { vec.resize(sz); return {}; } } }