#include #include #include #include #include namespace Nz { struct JsonImpl { nlohmann::json& Top() { return *stack.top(); } bool Pop() { if (stack.empty()) { NazaraAssert(stack.empty(), "Stack is empty"); return false; } stack.pop(); return true; } nlohmann::json json; std::stack stack; }; JsonSerializationContext::JsonSerializationContext() : m_impl(std::make_unique()) {} JsonSerializationContext::~JsonSerializationContext() {} bool JsonSerializationContext::Load(const std::filesystem::path& path) { Nz::File file(path, Nz::OpenMode::Read); return Load(file); } bool JsonSerializationContext::Load(Stream& stream) { if (!stream.IsReadable()) return false; auto size = stream.GetSize(); std::vector content(size); stream.Read(content.data(), content.size()); m_impl->json = nlohmann::json::parse(content.begin(), content.end()); m_impl->stack.push(&m_impl->json); return true; } bool JsonSerializationContext::PushObject(std::string_view name) { if (name.empty()) // special case if name is empty, don't push return true; if (!m_impl->Top().contains(name)) return false; if (!m_impl->Top()[name].is_object()) { NazaraAssert(m_impl->Top()[name].is_object(), "Value is not an object"); return false; } m_impl->stack.push(&m_impl->Top()[name]); return true; } bool JsonSerializationContext::PopObject() { return m_impl->Pop(); } bool JsonSerializationContext::PushArray(std::string_view name) { if (!m_impl->Top()[name].is_array()) { NazaraAssert(m_impl->Top()[name].is_array(), "Value is not an array"); return false; } m_impl->stack.push(&m_impl->Top()[name]); return true; } bool JsonSerializationContext::PopArray() { return m_impl->Pop(); } #define DEF_SERIALIZE(Type, cond) \ bool JsonSerializationContext::Write(std::string_view name, Type value) \ { \ m_impl->Top()[name] = value; \ return true; \ } \ bool JsonSerializationContext::Read(std::string_view name, Type* value) \ { \ if (!m_impl->Top()[name].cond()) \ { \ /*NazaraAssert(m_impl->Top()[name].cond(), "Value failed check: " #cond "()");*/\ return false; \ } \ *value = m_impl->Top()[name].get(); \ return true; \ } \ DEF_SERIALIZE(bool, is_boolean); DEF_SERIALIZE(Nz::Int8, is_number); DEF_SERIALIZE(Nz::Int16, is_number); DEF_SERIALIZE(Nz::Int32, is_number); DEF_SERIALIZE(Nz::Int64, is_number); DEF_SERIALIZE(Nz::UInt8, is_number); DEF_SERIALIZE(Nz::UInt16, is_number); DEF_SERIALIZE(Nz::UInt32, is_number); DEF_SERIALIZE(Nz::UInt64, is_number); DEF_SERIALIZE(float, is_number); DEF_SERIALIZE(double, is_number); #undef DEF_SERIALIZE bool JsonSerializationContext::Write(std::string_view name, const std::string& value) { m_impl->Top()[name] = value; return true; } bool JsonSerializationContext::Read(std::string_view name, std::string* value) { if (!m_impl->Top()[name].is_string()) { NazaraAssert(m_impl->Top()[name].is_string(), "Value failed check: is_string()"); return false; } *value = m_impl->Top()[name].get(); return true; } std::shared_ptr JsonSerializationContext::LoadFromStream(Stream& stream, const JsonSerializationContext::Params&) { std::shared_ptr context = std::make_shared(); if (context->Load(stream)) return context; return {}; } }