/* * Copyright 2022 PixlOne * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef LOGID_CONFIG_GROUP_H #define LOGID_CONFIG_GROUP_H #include #include #include #include #include namespace logid::config { template void set(libconfig::Setting& parent, const std::string& name, const T& t); template void set(libconfig::Setting& parent, const T& t); template auto get(const libconfig::Setting& parent, const std::string& name); template void append(libconfig::Setting& list, const T& t); template struct group_io { }; template struct group_io { static void get(const libconfig::Setting&, T*, const std::vector&, const std::size_t) {} static void set(libconfig::Setting&, const T*, const std::vector&, const std::size_t) {} }; template struct group_io { static void get(const libconfig::Setting& s, T* t, const std::vector& names, const std::size_t index, A T::* arg, M T::*... rest) { auto& x = t->*(arg); A old{x}; try { x = config::get(s, names[index]); group_io::get(s, t, names, index + 1, rest...); } catch (libconfig::SettingTypeException& e) { x = old; throw; } catch (libconfig::SettingException& e) { x = old; throw libconfig::SettingTypeException(s); } } static void set(libconfig::Setting& s, const T* t, const std::vector& names, const std::size_t index, A T::* arg, M T::*... rest) { config::set(s, names[index], t->*(arg)); group_io::set(s, t, names, index + 1, rest...); } }; template struct signed_group; struct group { private: const std::vector _names; const std::function&)> _getter; const std::function&)> _setter; template friend struct signed_group; protected: template explicit group(const std::array& names, M T::*... args) : _names(names.begin(), names.end()), _getter([args...](const libconfig::Setting& s, group* g, const std::vector& names) { T* t = dynamic_cast(g); group_io::get(s, t, names, 0, args...); }), _setter([args...](libconfig::Setting& s, const group* g, const std::vector& names) { const T* t = dynamic_cast(g); group_io::set(s, t, names, 0, args...); }) { static_assert(std::is_base_of::value); } group() : _getter([](const libconfig::Setting&, group*, const std::vector&) {}), _setter([](libconfig::Setting&, const group*, const std::vector&) {}) {} public: group(const group& o) = default; group(group&& o) noexcept = default; group& operator=(const group&) { return *this; } group& operator=(group&&) noexcept { return *this; } virtual ~group() = default; virtual void _save(libconfig::Setting& setting) const { _setter(setting, this, _names); } virtual void _load(const libconfig::Setting& setting) { _getter(setting, this, _names); } }; template struct normalize_signature { static const T& make(const T& ret) { return ret; } }; template<> struct normalize_signature { static std::string make(const std::string& data) { std::string ret = data; std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower); return ret; } }; template struct signed_group : public group { private: const std::string _sig_field; const Sign _signature; protected: signed_group(std::string sign_name, const Sign& sign_data) : group(), _sig_field(std::move(sign_name)), _signature(normalize_signature::make(sign_data)) {} template signed_group( std::string sign_name, const Sign& sign_data, const std::array& names, M T::*... args) : group(names, args...), _sig_field(std::move(sign_name)), _signature(normalize_signature::make(sign_data)) {} public: signed_group(const signed_group& o) = default; signed_group(signed_group&& o) noexcept = default; signed_group& operator=(const signed_group&) { return *this; } signed_group& operator=(signed_group&&) noexcept { return *this; } void _save(libconfig::Setting& setting) const override { set(setting, _sig_field, _signature); _setter(setting, this, _names); } void _load(const libconfig::Setting& setting) override { if (normalize_signature::make(get(setting, _sig_field)) != _signature) throw libconfig::SettingTypeException(setting); _getter(setting, this, _names); } }; } #endif //LOGID_CONFIG_GROUP_H