Commit f6ae028a authored by Dominik Charousset's avatar Dominik Charousset

Simplify config_option interface

parent 3f59e8d4
......@@ -36,11 +36,10 @@ public:
/// Custom vtable-like struct for delegating to type-specific functions and
/// storing type-specific information shared by several config options.
struct meta_state {
/// Checks whether a value matches the option's type.
error (*check)(const config_value&);
/// Stores a value in the given location.
void (*store)(void*, const config_value&);
/// Performs a type check on the config value and then stores the converted
/// value in the given storage location unless the storage pointer was set
/// to `nullptr`.
error (*store)(void*, const config_value&);
/// Tries to extract a value from the given location. Exists for backward
/// compatibility only and will get removed with CAF 0.17.
......@@ -89,12 +88,9 @@ public:
/// Returns the full name for this config option as "<category>.<long name>".
string_view full_name() const noexcept;
/// Checks whether `x` holds a legal value for this option.
error check(const config_value& x) const;
/// Stores `x` in this option unless it is stateless.
/// @pre `check(x) == none`.
void store(const config_value& x) const;
/// Performs a type check for `x` and then stores `x` in this option unless it
/// is stateless.
error store(const config_value& x) const;
/// Returns a human-readable representation of this option's expected type.
string_view type_name() const noexcept;
......
......@@ -30,20 +30,17 @@
#include "caf/pec.hpp"
#include "caf/string_view.hpp"
namespace caf {
namespace detail {
namespace caf::detail {
template <class T>
error check_impl(const config_value& x) {
if (holds_alternative<T>(x))
error store_impl(void* ptr, const config_value& x) {
if (holds_alternative<T>(x)) {
if (ptr)
*static_cast<T*>(ptr) = get<T>(x);
return none;
} else {
return make_error(pec::type_mismatch);
}
template <class T>
void store_impl(void* ptr, const config_value& x) {
*static_cast<T*>(ptr) = get<T>(x);
}
}
template <class T>
......@@ -68,8 +65,8 @@ expected<config_value> parse_impl(T* ptr, string_view str) {
return config_value{trait::convert(*ptr)};
}
CAF_CORE_EXPORT expected<config_value>
parse_impl(std::string* ptr, string_view str);
CAF_CORE_EXPORT expected<config_value> parse_impl(std::string* ptr,
string_view str);
template <class T>
expected<config_value> parse_impl_delegate(void* ptr, string_view str) {
......@@ -79,13 +76,15 @@ expected<config_value> parse_impl_delegate(void* ptr, string_view str) {
template <class T>
config_option::meta_state* option_meta_state_instance() {
using trait = detail::config_value_access_t<T>;
static config_option::meta_state obj{check_impl<T>, store_impl<T>,
get_impl<T>, parse_impl_delegate<T>,
static config_option::meta_state obj{store_impl<T>, get_impl<T>,
parse_impl_delegate<T>,
trait::type_name()};
return &obj;
}
} // namespace detail
} // namespace caf::detail
namespace caf {
/// Creates a config option that synchronizes with `storage`.
template <class T>
......
......@@ -340,11 +340,10 @@ actor_system_config& actor_system_config::set_impl(string_view name,
if (opt == nullptr) {
std::cerr << "*** failed to set config parameter " << name
<< ": invalid name" << std::endl;
} else if (auto err = opt->check(value)) {
} else if (auto err = opt->store(value)) {
std::cerr << "*** failed to set config parameter " << name << ": "
<< to_string(err) << std::endl;
} else {
opt->store(value);
auto category = opt->category();
if (category == "global")
content[opt->long_name()] = std::move(value);
......
......@@ -128,16 +128,9 @@ string_view config_option::full_name() const noexcept {
return buf_slice(buf_[0] == '?' ? 1 : 0, long_name_separator_);
}
error config_option::check(const config_value& x) const {
CAF_ASSERT(meta_->check != nullptr);
return meta_->check(x);
}
void config_option::store(const config_value& x) const {
if (value_ != nullptr) {
error config_option::store(const config_value& x) const {
CAF_ASSERT(meta_->store != nullptr);
meta_->store(value_, x);
}
return meta_->store(value_, x);
}
string_view config_option::type_name() const noexcept {
......
......@@ -156,16 +156,11 @@ void merge_into_place(settings& src, settings& dst) {
} // namespace
pec config_consumer::value_impl(config_value&& x) {
// See whether there's a config_option associated to this key and perform a
// type check if necessary.
const config_option* opt;
if (options_ == nullptr) {
opt = nullptr;
} else {
opt = options_->qualified_name_lookup(category_, current_key_);
if (opt && opt->check(x) != none)
// Sync with config option object if available.
if (options_ != nullptr)
if (auto opt = options_->qualified_name_lookup(category_, current_key_))
if (auto err = opt->store(x))
return pec::type_mismatch;
}
// Insert / replace value in the map.
if (auto dict = get_if<settings>(&x)) {
// Merge values into the destination, because it can already contain any
......@@ -178,13 +173,6 @@ pec config_consumer::value_impl(config_value&& x) {
} else {
cfg_->insert_or_assign(current_key_, std::move(x));
}
// Sync with config option if needed.
if (opt) {
if (auto i = cfg_->find(current_key_); i != cfg_->end())
opt->store(i->second);
else
return pec::invalid_state;
}
return pec::success;
}
......
......@@ -67,28 +67,33 @@ namespace {
using meta_state = config_option::meta_state;
void bool_store_neg(void* ptr, const config_value& x) {
error bool_store_neg(void* ptr, const config_value& x) {
if (holds_alternative<bool>(x)) {
if (ptr)
*static_cast<bool*>(ptr) = !get<bool>(x);
return none;
} else {
return make_error(pec::type_mismatch);
}
}
config_value bool_get_neg(const void* ptr) {
return config_value{!*static_cast<const bool*>(ptr)};
}
meta_state bool_neg_meta{detail::check_impl<bool>, bool_store_neg, bool_get_neg,
nullptr,
meta_state bool_neg_meta{bool_store_neg, bool_get_neg, nullptr,
detail::config_value_access_t<bool>::type_name()};
error check_timespan(const config_value& x) {
if (holds_alternative<timespan>(x))
return none;
return make_error(pec::type_mismatch);
}
template <uint64_t Denominator>
void store_timespan(void* ptr, const config_value& x) {
error store_timespan(void* ptr, const config_value& x) {
if (holds_alternative<timespan>(x)) {
if (ptr)
*static_cast<size_t*>(ptr) = static_cast<size_t>(get<timespan>(x).count())
/ Denominator;
return none;
} else {
return make_error(pec::type_mismatch);
}
}
template <uint64_t Denominator>
config_value get_timespan(const void* ptr) {
......@@ -97,12 +102,10 @@ config_value get_timespan(const void* ptr) {
return config_value{val};
}
meta_state us_res_meta{check_timespan, store_timespan<1000>, get_timespan<1000>,
nullptr,
meta_state us_res_meta{store_timespan<1000>, get_timespan<1000>, nullptr,
detail::config_value_access_t<timespan>::type_name()};
meta_state ms_res_meta{check_timespan, store_timespan<1000000>,
get_timespan<1000000>, nullptr,
meta_state ms_res_meta{store_timespan<1000000>, get_timespan<1000000>, nullptr,
detail::config_value_access_t<timespan>::type_name()};
} // namespace
......
......@@ -51,8 +51,7 @@ optional<T> read(string_view arg) {
auto co = make_config_option<T>(category, name, explanation);
auto res = co.parse(arg);
if (res && holds_alternative<T>(*res)) {
if (co.check(*res) != none)
CAF_ERROR("co.parse() produced the wrong type!");
if (auto err = co.store(*res); !err)
return get<T>(*res);
}
return none;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment