/*
* 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