/* * Copyright (C) 2022 Riyyi * * SPDX-License-Identifier: MIT */ #pragma once #if 0 #include // int32_t, uint32_t #include // std::optional #include // std::vector #include "nlohmann/json.hpp" #include "ruc/meta/assert.h" #include "ruc/format/log.h" namespace Inferno { using json = nlohmann::json; using json_const_iterator = nlohmann::json::const_iterator; class Json { public: static const json& getValue(json_const_iterator& it) { return it.value(); } template static std::optional getPropertyValue(const json& json, json::value_t check) { if (json.type() == check) { return json.get(); } return {}; } template static std::optional getPropertyValue(const json& json, std::vector checks) { bool valid = false; // Check values with all allowed types for (auto check : checks) { if (json.type() == check) { valid = true; break; } } // Get value if valid type if (valid) { return json.get(); } return {}; } // --------------------------------- static bool hasProperty(const json& json, const char* property) { return json.find(property) != json.end(); } static bool hasProperty(const json& json, json_const_iterator& it, const char* property) { it = json.find(property); return it != json.end(); } // --------------------------------- template static std::optional parseProperty(const json& json, const char* property, bool required, json::value_t check) { return parseProperty(json, property, required, std::vector { check }); } template static std::optional parseProperty(const json& json, const char* property, bool required, std::vector checks) { bool exists; json_const_iterator it; // Has property exists = hasProperty(json, it, property); VERIFY(!required || (required && exists), "Json could not find required property '{}'", property); if (!exists) { return {}; } // Return data found in iterator, empty if incorrect type return getPropertyValue(getValue(it), checks); } template static std::optional> parseArrayProperty(const json& json, const char* property, bool required, json::value_t check) { return parseArrayProperty(json, property, required, std::vector { check }); } template static std::optional> parseArrayProperty(const json& json, const char* property, bool required, std::vector checks) { bool exists; json_const_iterator it; // Has property exists = hasProperty(json, it, property); VERIFY(!required || (required && exists), "Json could not find required property '{}'", property); if (!exists) { return {}; } // Check if property is array [] VERIFY(getValue(it).is_array(), "Json property is not an array '{}'", property); // Fill array with values std::vector values; for (auto value : getValue(it)) { auto typedValue = getPropertyValue(value, checks); if (typedValue) { values.emplace_back(typedValue.value()); } else { ruc::warn("Json array property '{}' has type inconsistency", property); } } // Return vector if it has any items, uninitialized optional otherwise if (values.size() > 0) return values; return {}; } template static std::optional> parseObjectProperty(const json& json, const char* property, bool required, json::value_t check) { return parseObjectProperty(json, property, required, std::vector { check }); } template static std::optional> parseObjectProperty(const json& json, const char* property, bool required, std::vector checks) { bool exists; json_const_iterator it; // Has property exists = hasProperty(json, it, property); VERIFY(!required || (required && exists), "Json could not find required property '{}'", property); if (!exists) { return {}; } // Check if property is an object {} VERIFY(getValue(it).is_object(), "Json property is not an array '{}'", property); std::map values; for (auto& [key, value] : getValue(it).items()) { auto typedValue = getPropertyValue(value, checks); if (typedValue) { values.emplace(std::move(key), typedValue.value()); } else { ruc::warn("Json array property '{}' has type inconsistency", property); } } // Return map if it has any items, uninitialized optional otherwise if (values.size() > 0) return values; return {}; } static std::optional parseBoolProperty(const json& json, const char* property, bool required) { return parseProperty(json, property, required, json::value_t::boolean); } static std::optional parseFloatProperty(const json& json, const char* property, bool required) { auto result = parseProperty(json, property, required, std::vector { json::value_t::number_integer, json::value_t::number_unsigned, json::value_t::number_float }); if (result) return static_cast(result.value()); return {}; } static std::optional parseIntegerProperty(const json& json, const char* property, bool required) { auto result = parseProperty(json, property, required, json::value_t::number_integer); if (result) return static_cast(result.value()); return {}; } static std::optional parseUnsignedProperty(const json& json, const char* property, bool required) { auto result = parseProperty(json, property, required, json::value_t::number_unsigned); if (result) return static_cast(result.value()); return {}; } static std::optional parseStringProperty(const json& json, const char* property, bool required) { return parseProperty(json, property, required, json::value_t::string); } static std::optional> parseFloatArrayProperty(const json& json, const char* property, bool required) { auto result = parseArrayProperty(json, property, required, std::vector { json::value_t::number_integer, json::value_t::number_unsigned, json::value_t::number_float }); if (result) return std::vector(result.value().begin(), result.value().end()); return {}; } static std::optional> parseIntegerArrayProperty(const json& json, const char* property, bool required) { auto result = parseArrayProperty(json, property, required, json::value_t::number_integer); if (result) return std::vector(result.value().begin(), result.value().end()); return {}; } static std::optional> parseUnsignedArrayProperty(const json& json, const char* property, bool required) { auto result = parseArrayProperty(json, property, required, json::value_t::number_unsigned); if (result) return std::vector(result.value().begin(), result.value().end()); return {}; } static std::optional> parseFloatObjectProperty(const json& json, const char* property, bool required) { auto result = parseObjectProperty(json, property, required, std::vector { json::value_t::number_integer, json::value_t::number_unsigned, json::value_t::number_float }); if (result) return std::map(result.value().begin(), result.value().end()); return {}; } static std::optional> parseIntegerObjectProperty(const json& json, const char* property, bool required) { auto result = parseObjectProperty(json, property, required, json::value_t::number_integer); if (result) return std::map(result.value().begin(), result.value().end()); return {}; } static std::optional> parseUnsignedObjectProperty(const json& json, const char* property, bool required) { auto result = parseObjectProperty(json, property, required, json::value_t::number_unsigned); if (result) return std::map(result.value().begin(), result.value().end()); return {}; } }; } // namespace Inferno #endif // JSON syntax: // [ ] = std::map, array (ordered) // { } = std::vector, object (unordered) // "": = std::string, property (key -> value) // true/false = bool, condition // -3 = int64_t, number // 5 = uint64_t, number // 4.567 = double, number // "thing" = std::string, text