Program Listing for File Interface.ipp¶
↰ Return to documentation for file (uconfig/impl/Interface.ipp
)
#pragma once
namespace uconfig {
template <typename Format>
template <typename... FormatTs>
ConfigIface<Format>::ConfigIface(const std::string& parse_path, Config<FormatTs...>* config)
: path_(parse_path)
{
if (!config) {
throw std::runtime_error("invalid section pointer to parse");
}
config->Reset();
config->template SetFormat<Format>();
config->Init(Path());
cfg_optional_ = config->Optional();
cfg_interfaces_ = &config->template Interfaces<format_type>();
cfg_validate_ = [config]() { config->Validate(); };
}
template <typename Format>
bool ConfigIface<Format>::Parse(const format_type& parser, const source_type* source, bool throw_on_fail)
{
bool config_parsed = false;
for (auto& iface : *cfg_interfaces_) {
bool iface_parsed;
try {
iface_parsed = iface->Parse(parser, source, throw_on_fail);
} catch (const Error& ex) {
iface_parsed = false;
if (!Optional() && throw_on_fail) {
throw ParseError(ex.what());
}
}
// section considered parsed if at least one of its' interfaces parsed
config_parsed |= iface_parsed;
}
try {
cfg_validate_();
} catch (const Error& ex) {
if (throw_on_fail) {
throw ParseError(ex.what());
}
} catch (const std::exception& ex) {
if (throw_on_fail) {
throw ParseError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what());
}
}
return config_parsed;
}
template <typename Format>
void ConfigIface<Format>::Emit(const format_type& emitter, dest_type* dest, bool throw_on_fail)
{
for (auto& iface : *cfg_interfaces_) {
try {
iface->Emit(emitter, dest, throw_on_fail);
} catch (const Error& ex) {
if (!Optional() && throw_on_fail) {
throw EmitError(ex.what());
}
}
}
}
template <typename Format>
const std::string& ConfigIface<Format>::Path() const noexcept
{
return path_;
}
template <typename Format>
bool ConfigIface<Format>::Initialized() const noexcept
{
for (const auto& iface : *cfg_interfaces_) {
if (!iface->Initialized() && !iface->Optional()) {
return false;
}
}
return true;
}
template <typename Format>
bool ConfigIface<Format>::Optional() const noexcept
{
return cfg_optional_;
}
template <typename T, typename Format>
ValueIface<T, Format>::ValueIface(const std::string& variable_path, T* value)
: path_(variable_path)
, initialized_(false)
, value_ptr_(value)
{
if (!value_ptr_) {
throw std::runtime_error("invalid variable pointer to parse");
}
}
template <typename T, typename Format>
bool ValueIface<T, Format>::Parse(const format_type& parser, const source_type* source, bool throw_on_fail)
{
std::optional<T> result_opt = parser.template Parse<T>(source, Path());
if (!result_opt) {
if (!Optional() && throw_on_fail) {
throw ParseError(format_type::name + " config '" + Path() + "' is not valid: variable is not set");
}
return false;
}
*value_ptr_ = std::move(*result_opt);
initialized_ = true;
return true;
}
template <typename T, typename Format>
void ValueIface<T, Format>::Emit(const format_type& emitter, dest_type* dest, bool /*throw_on_fail*/)
{
emitter.Emit(dest, Path(), *value_ptr_);
}
template <typename T, typename Format>
const std::string& ValueIface<T, Format>::Path() const noexcept
{
return path_;
}
template <typename T, typename Format>
bool ValueIface<T, Format>::Initialized() const noexcept
{
return initialized_;
}
template <typename T, typename Format>
bool ValueIface<T, Format>::Optional() const noexcept
{
return false;
}
template <typename T, typename Format>
VariableIface<T, Format>::VariableIface(const std::string& variable_path, Variable<T>* variable)
: path_(variable_path)
, variable_ptr_(variable)
{
if (!variable_ptr_) {
throw std::runtime_error("invalid variable pointer to parse");
}
}
template <typename T, typename Format>
bool VariableIface<T, Format>::Parse(const format_type& parser, const source_type* source, bool throw_on_fail)
{
std::optional<T> result_opt = parser.template Parse<T>(source, Path());
if (!result_opt) {
if (!Initialized() && throw_on_fail) {
throw ParseError(format_type::name + " config '" + Path() + "' is not valid: variable is not set");
}
return false;
}
*variable_ptr_ = std::move(*result_opt);
try {
variable_ptr_->Validate();
} catch (const Error& ex) {
if (throw_on_fail) {
throw ParseError(ex.what());
}
} catch (const std::exception& ex) {
if (throw_on_fail) {
throw ParseError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what());
}
}
return true;
}
template <typename T, typename Format>
void VariableIface<T, Format>::Emit(const format_type& emitter, dest_type* dest, bool throw_on_fail)
{
try {
emitter.Emit(dest, Path(), variable_ptr_->Get());
} catch (const std::exception& ex) {
if (throw_on_fail) {
throw EmitError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what());
}
return;
}
}
template <typename T, typename Format>
const std::string& VariableIface<T, Format>::Path() const noexcept
{
return path_;
}
template <typename T, typename Format>
bool VariableIface<T, Format>::Initialized() const noexcept
{
return variable_ptr_->Initialized();
}
template <typename T, typename Format>
bool VariableIface<T, Format>::Optional() const noexcept
{
return variable_ptr_->Optional();
}
template <typename T, typename Format>
VectorIface<T, Format>::VectorIface(const std::string& vector_path, Vector<T>* vector)
: path_(vector_path)
, vector_ptr_(vector)
{
if (!vector_ptr_) {
throw std::runtime_error("invalid list pointer to parse");
}
}
template <typename T, typename Format>
bool VectorIface<T, Format>::Parse(const format_type& parser, const source_type* source, bool throw_on_fail)
{
using elem_iface_type = detail::deduce_iface_t<T, Format>;
std::size_t index = 0;
std::optional<Error> last_error;
while (true) {
T element;
bool elem_parsed = false;
elem_iface_type elem_iface(parser.VectorElementPath(Path(), index), &element);
try {
elem_parsed = elem_iface.Parse(parser, source, true);
} catch (const Error& ex) {
last_error = ex;
break;
}
// always stop on fail to prevent looping
if (!elem_parsed || last_error) {
break;
}
// we are about to emplace first parsed value, vector should be empty-initialized to do so
if (!Initialized() || index == 0) {
vector_ptr_->value_ = std::vector<T>();
}
vector_ptr_->value_->emplace_back(std::move(element));
++index;
}
if (!Initialized() && !Optional()) {
// notify that mandatory vector was not parsed
if (last_error) {
throw ParseError(last_error->what());
} else {
throw ParseError(format_type::name + " config '" + Path() + "' is not valid: vector is not set");
}
}
try {
vector_ptr_->Validate();
} catch (const Error& ex) {
if (throw_on_fail) {
throw ParseError(ex.what());
}
} catch (const std::exception& ex) {
if (throw_on_fail) {
throw ParseError(format_type::name + " config '" + Path() + "' is not valid: " + ex.what());
}
}
return index > 0;
}
template <typename T, typename Format>
void VectorIface<T, Format>::Emit(const format_type& emitter, dest_type* dest, bool throw_on_fail)
{
using elem_iface_type = detail::deduce_iface_t<T, Format>;
std::size_t index = 0;
while (true) {
T* elem = nullptr;
std::string elem_path = emitter.VectorElementPath(Path(), index);
try {
elem = &(*vector_ptr_)->at(index);
} catch (const Error& ex) {
if (!Optional() && throw_on_fail) {
throw EmitError(format_type::name + " config '" + elem_path + "' is not valid: " + ex.what());
}
return;
} catch (const std::out_of_range& ex) {
if (!Optional() && throw_on_fail) {
throw EmitError(format_type::name + " config '" + elem_path + "' is not valid: variable is not set");
}
return;
}
elem_iface_type iface(elem_path, elem);
iface.Emit(emitter, dest, throw_on_fail);
if (++index >= (*vector_ptr_)->size()) {
return;
}
}
}
template <typename T, typename Format>
const std::string& VectorIface<T, Format>::Path() const noexcept
{
return path_;
}
template <typename T, typename Format>
bool VectorIface<T, Format>::Initialized() const noexcept
{
return vector_ptr_->Initialized();
}
template <typename T, typename Format>
bool VectorIface<T, Format>::Optional() const noexcept
{
return vector_ptr_->Optional();
}
} // namespace uconfig