Settings variable abstract base, additional validation, and reading/writing JSON

This commit is contained in:
Dan Paulat 2022-12-17 00:38:20 -06:00
parent 1ad67de71b
commit 46c4dd3780
7 changed files with 408 additions and 17 deletions

View file

@ -3,6 +3,11 @@
#include <scwx/qt/settings/settings_variable.hpp>
#include <scwx/util/logger.hpp>
#include <optional>
#include <boost/json.hpp>
#include <fmt/ostream.h>
namespace scwx
{
namespace qt
@ -11,16 +16,16 @@ namespace settings
{
static const std::string logPrefix_ = "scwx::qt::settings::settings_variable";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
template<class T>
class SettingsVariable<T>::Impl
{
public:
explicit Impl(const std::string& name) : name_ {name} {}
explicit Impl() {}
~Impl() {}
const std::string name_;
T value_ {};
T default_ {};
std::optional<T> staged_ {};
@ -31,7 +36,7 @@ public:
template<class T>
SettingsVariable<T>::SettingsVariable(const std::string& name) :
p(std::make_unique<Impl>(name))
SettingsVariableBase(name), p(std::make_unique<Impl>())
{
}
template<class T>
@ -44,9 +49,16 @@ SettingsVariable<T>&
SettingsVariable<T>::operator=(SettingsVariable&&) noexcept = default;
template<class T>
std::string SettingsVariable<T>::name() const
inline auto FormatParameter(const T& value)
{
return p->name_;
if constexpr (std::is_integral_v<T> || std::is_same_v<T, std::string>)
{
return value;
}
else
{
return fmt::join(value, ", ");
}
}
template<class T>
@ -81,14 +93,26 @@ bool SettingsVariable<T>::SetValueOrDefault(const T& value)
}
else if (p->minimum_.has_value() && value < p->minimum_)
{
logger_->warn("{0} less than minimum ({1} < {2}), setting to: {2}",
name(),
FormatParameter<T>(value),
FormatParameter<T>(*p->minimum_));
p->value_ = *p->minimum_;
}
else if (p->maximum_.has_value() && value > p->maximum_)
{
logger_->warn("{0} greater than maximum ({1} > {2}), setting to: {2}",
name(),
FormatParameter<T>(value),
FormatParameter<T>(*p->maximum_));
p->value_ = *p->maximum_;
}
else
{
logger_->warn("{} validation failed ({}), setting to default: {}",
name(),
FormatParameter<T>(value),
FormatParameter<T>(p->default_));
p->value_ = p->default_;
}
@ -164,6 +188,59 @@ bool SettingsVariable<T>::Validate(const T& value) const
(p->validator_ == nullptr || p->validator_(value))); // User-validation
}
template<class T>
bool SettingsVariable<T>::ReadValue(const boost::json::object& json)
{
const boost::json::value* jv = json.if_contains(name());
bool validated = false;
if (jv != nullptr)
{
try
{
validated = SetValueOrDefault(boost::json::value_to<T>(*jv));
}
catch (const std::exception& ex)
{
logger_->warn("{} is invalid ({}), setting to default: {}",
name(),
ex.what(),
FormatParameter<T>(p->default_));
p->value_ = p->default_;
}
}
else
{
logger_->debug("{} is not present, setting to default: {}",
name(),
FormatParameter<T>(p->default_));
p->value_ = p->default_;
}
return validated;
}
template<class T>
void SettingsVariable<T>::WriteValue(boost::json::object& json) const
{
json[name()] = boost::json::value_from<T&>(p->value_);
}
template<class T>
bool SettingsVariable<T>::Equals(const SettingsVariableBase& o) const
{
// This is only ever called with SettingsVariable<T>, so static_cast is safe
const SettingsVariable<T>& v = static_cast<const SettingsVariable<T>&>(o);
// Don't compare validator
return SettingsVariableBase::Equals(o) && //
p->value_ == v.p->value_ && //
p->default_ == v.p->default_ && //
p->staged_ == v.p->staged_ && //
p->minimum_ == v.p->minimum_ && //
p->maximum_ == v.p->maximum_;
}
} // namespace settings
} // namespace qt
} // namespace scwx