#pragma once #include #include #include #include #include #include #include "WallpaperEngine/Data/Builders/UserSettingBuilder.h" #include "WallpaperEngine/Data/Builders/VectorBuilder.h" #include "WallpaperEngine/Data/Model/Types.h" #include "WallpaperEngine/Data/Utils/SFINAE.h" #include "WallpaperEngine/Logging/Log.h" namespace WallpaperEngine::Data::JSON { using namespace WallpaperEngine::Data::Builders; using namespace WallpaperEngine::Data::Model; using namespace WallpaperEngine::Data::Utils::SFINAE; class JsonExtensions; using JSON = nlohmann::basic_json< std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, nlohmann::adl_serializer, std::vector, JsonExtensions >; /** * Small extensions class that is used as base class of nlohmann's implementation. * * Provides shorthand methods to reduce the amount of handling required for specific situations * (mainly throwing readable exceptions when a value is missing, optional/default values, user settings...) */ class JsonExtensions { public: using base_type = JSON; template ::value, int> = 0> [[nodiscard]] T get () const { constexpr int length = GlmVecTraits::length; constexpr glm::qualifier qualifier = GlmVecTraits::qualifier; // call the specialized version of the function return get ::type, qualifier> (); } template [[nodiscard]] glm::vec get () const { return VectorBuilder::parse (this->base ().get ()); } [[nodiscard]] base_type require (const std::string& key, const std::string& message) const { auto base = this->base (); auto it = base.find (key); if (it == base.end ()) { sLog.exception (message); } return *it; } template [[nodiscard]] T require (const std::string& key, const std::string& message) const { auto base = this->base (); auto it = base.find (key); if (it == base.end ()) { sLog.exception (message); } return (*it); } [[nodiscard]] std::optional optional (const std::string& key) const noexcept { auto base = this->base (); auto it = base.find (key); auto result = std::optional {}; if (it != base.end ()) { result.emplace (*it); } return result; } template [[nodiscard]] std::optional optional (const std::string& key) const noexcept { auto base = this->base (); auto it = base.find (key); if (it == base.end ()) { return std::nullopt; } return *it; } template [[nodiscard]] T optional (const std::string& key, T defaultValue) const noexcept { auto base = this->base (); auto it = base.find (key); if (it == base.end ()) { return defaultValue; } return (*it); } [[nodiscard]] UserSettingUniquePtr user (const std::string& key, const Properties& properties) const; template [[nodiscard]] UserSettingUniquePtr user (const std::string& key, const Properties& properties, T defaultValue) const { const auto value = this->optional (key); if (!value.has_value ()) { return UserSettingBuilder::fromValue (defaultValue); } // performs a second lookup, but handles the actual call to UserSettingParser outside of this header // this resolving the include loop return this->user (key, properties); } template operator glm::vec () const { return get (); } template ::value> = 0> operator T () const { constexpr int length = GlmVecTraits::length; constexpr glm::qualifier qualifier = GlmVecTraits::qualifier; // call the specialized version of the function return operator glm::vec ::type, qualifier> (); } private: /** * @return The base json object to be used by the extension methods */ [[nodiscard]] const base_type& base () const { return *static_cast (this); } }; } // namespace WallpaperEngine::Data::JSON