Commit 6df8d506 authored by Dominik Charousset's avatar Dominik Charousset

Implement new settings reader

parent 083126c8
...@@ -158,6 +158,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -158,6 +158,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/sec_strings.cpp src/sec_strings.cpp
src/serializer.cpp src/serializer.cpp
src/settings.cpp src/settings.cpp
src/settings_reader.cpp
src/settings_writer.cpp src/settings_writer.cpp
src/size_based_credit_controller.cpp src/size_based_credit_controller.cpp
src/skip.cpp src/skip.cpp
...@@ -312,6 +313,7 @@ caf_add_test_suites(caf-core-test ...@@ -312,6 +313,7 @@ caf_add_test_suites(caf-core-test
serial_reply serial_reply
serialization serialization
settings settings
settings_reader
settings_writer settings_writer
simple_timeout simple_timeout
span span
......
...@@ -97,6 +97,8 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, float& x); ...@@ -97,6 +97,8 @@ CAF_CORE_EXPORT void parse(string_parser_state& ps, float& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, double& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, double& x);
CAF_CORE_EXPORT void parse(string_parser_state& ps, long double& x);
// -- CAF types ---------------------------------------------------------------- // -- CAF types ----------------------------------------------------------------
CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_address& x); CAF_CORE_EXPORT void parse(string_parser_state& ps, ipv4_address& x);
......
...@@ -145,19 +145,21 @@ enum class sec : uint8_t { ...@@ -145,19 +145,21 @@ enum class sec : uint8_t {
no_tracing_context, no_tracing_context,
/// No request produced a valid result. /// No request produced a valid result.
all_requests_failed, all_requests_failed,
/// Deserialization failed, because an invariant got violated after reading /// Deserialization failed because an invariant got violated after reading
/// the content of a field. /// the content of a field.
field_invariant_check_failed = 55, field_invariant_check_failed = 55,
/// Deserialization failed, because a setter rejected the input. /// Deserialization failed because a setter rejected the input.
field_value_synchronization_failed, field_value_synchronization_failed,
/// Deserialization failed, because the source announced an invalid type. /// Deserialization failed because the source announced an invalid type.
invalid_field_type, invalid_field_type,
/// Serialization failed because a type was flagged as unsafe message type. /// Serialization failed because a type was flagged as unsafe message type.
unsafe_type, unsafe_type,
/// Serialization failed, because a save callback returned `false`. /// Serialization failed because a save callback returned `false`.
save_callback_failed, save_callback_failed,
/// Deserialization failed, because a load callback returned `false`. /// Deserialization failed because a load callback returned `false`.
load_callback_failed, load_callback_failed = 60,
/// Converting between two types failed.
conversion_failed,
}; };
/// @relates sec /// @relates sec
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/sum_type.hpp"
namespace caf { namespace caf {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/deserializer.hpp"
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include <stack>
#include <vector>
namespace caf {
/// Extracts objects from @ref settings.
class settings_reader : public deserializer {
public:
// -- member types------------------------------------------------------------
using super = deserializer;
using key_ptr = const std::string*;
struct absent_field {};
struct sequence {
using list_pointer = const std::vector<config_value>*;
size_t index;
list_pointer ls;
explicit sequence(list_pointer ls) : index(0), ls(ls) {
// nop
}
bool at_end() const noexcept;
const config_value& current();
void advance() {
++index;
}
};
struct associative_array {
settings::const_iterator pos;
settings::const_iterator end;
bool at_end() const noexcept;
const std::pair<const std::string, config_value>& current();
};
using value_type = variant<const settings*, const config_value*, key_ptr,
absent_field, sequence, associative_array>;
using stack_type = std::stack<value_type, std::vector<value_type>>;
// -- constructors, destructors, and assignment operators --------------------
settings_reader(const settings* input, actor_system& sys)
: super(sys), root_(input) {
st_.push(input);
has_human_readable_format_ = true;
}
settings_reader(const settings* input, execution_unit* ctx)
: super(ctx), root_(input) {
has_human_readable_format_ = true;
}
explicit settings_reader(const settings* input)
: settings_reader(input, nullptr) {
// nop
}
~settings_reader() override;
// -- stack access -----------------------------------------------------------
value_type& top() {
return st_.top();
}
void pop() {
return st_.pop();
}
// -- interface functions ----------------------------------------------------
bool fetch_next_object_type(type_id_t& type) override;
bool begin_object(string_view name) override;
bool end_object() override;
bool begin_field(string_view) override;
bool begin_field(string_view name, bool& is_present) override;
bool begin_field(string_view name, span<const type_id_t> types,
size_t& index) override;
bool begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index) override;
bool end_field() override;
bool begin_tuple(size_t size) override;
bool end_tuple() override;
bool begin_key_value_pair() override;
bool end_key_value_pair() override;
bool begin_sequence(size_t& size) override;
bool end_sequence() override;
bool begin_associative_array(size_t& size) override;
bool end_associative_array() override;
bool value(bool& x) override;
bool value(int8_t& x) override;
bool value(uint8_t& x) override;
bool value(int16_t& x) override;
bool value(uint16_t& x) override;
bool value(int32_t& x) override;
bool value(uint32_t& x) override;
bool value(int64_t& x) override;
bool value(uint64_t& x) override;
bool value(float& x) override;
bool value(double& x) override;
bool value(long double& x) override;
bool value(std::string& x) override;
bool value(std::u16string& x) override;
bool value(std::u32string& x) override;
bool value(span<byte> x) override;
private:
bool fetch_object_type(const settings* obj, type_id_t& type);
stack_type st_;
const settings* root_;
};
} // namespace caf
...@@ -142,6 +142,8 @@ PARSE_IMPL(float, floating_point) ...@@ -142,6 +142,8 @@ PARSE_IMPL(float, floating_point)
PARSE_IMPL(double, floating_point) PARSE_IMPL(double, floating_point)
PARSE_IMPL(long double, floating_point)
void parse(string_parser_state& ps, uri& x) { void parse(string_parser_state& ps, uri& x) {
uri_builder builder; uri_builder builder;
if (ps.consume('<')) { if (ps.consume('<')) {
......
...@@ -137,6 +137,8 @@ std::string to_string(sec x) { ...@@ -137,6 +137,8 @@ std::string to_string(sec x) {
return "save_callback_failed"; return "save_callback_failed";
case sec::load_callback_failed: case sec::load_callback_failed:
return "load_callback_failed"; return "load_callback_failed";
case sec::conversion_failed:
return "conversion_failed";
}; };
} }
......
This diff is collapsed.
...@@ -47,6 +47,10 @@ struct point_3d { ...@@ -47,6 +47,10 @@ struct point_3d {
int32_t z; int32_t z;
}; };
[[maybe_unused]] bool operator==(const point_3d& x, const point_3d& y) {
return std::tie(x.x, x.y, x.z) == std::tie(y.x, y.y, y.z);
}
template <class Inspector> template <class Inspector>
bool inspect(Inspector& f, point_3d& x) { bool inspect(Inspector& f, point_3d& x) {
return f.object(x).fields(f.field("x", x.x), f.field("y", x.y), return f.object(x).fields(f.field("x", x.x), f.field("y", x.y),
...@@ -58,6 +62,10 @@ struct line { ...@@ -58,6 +62,10 @@ struct line {
point_3d p2; point_3d p2;
}; };
[[maybe_unused]] bool operator==(const line& x, const line& y) {
return std::tie(x.p1, x.p2) == std::tie(y.p1, y.p2);
}
template <class Inspector> template <class Inspector>
bool inspect(Inspector& f, line& x) { bool inspect(Inspector& f, line& x) {
return f.object(x).fields(f.field("p1", x.p1), f.field("p2", x.p2)); return f.object(x).fields(f.field("p1", x.p1), f.field("p2", x.p2));
...@@ -141,6 +149,11 @@ struct dummy_message { ...@@ -141,6 +149,11 @@ struct dummy_message {
caf::variant<std::string, double> content; caf::variant<std::string, double> content;
}; };
[[maybe_unused]] bool operator==(const dummy_message& x,
const dummy_message& y) {
return x.content == y.content;
}
template <class Inspector> template <class Inspector>
bool inspect(Inspector& f, dummy_message& x) { bool inspect(Inspector& f, dummy_message& x) {
return f.object(x).fields(f.field("content", x.content)); return f.object(x).fields(f.field("content", x.content));
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE settings_reader
#include "caf/settings_reader.hpp"
#include "caf/test/dsl.hpp"
#include "inspector-tests.hpp"
#include "caf/settings_writer.hpp"
using namespace caf;
using namespace std::literals::string_literals;
namespace {
using i64 = int64_t;
constexpr i64 operator""_i64(unsigned long long int x) {
return static_cast<int64_t>(x);
}
using i64_list = std::vector<i64>;
struct fixture {
settings xs;
template <class T>
void deserialize(const settings& src, T& value) {
settings_reader reader{&src};
if (!inspect_object(reader, value))
CAF_FAIL("failed to deserialize from settings: " << reader.get_error());
}
template <class T>
void deserialize(T& value) {
return deserialize(xs, value);
}
template <class T>
optional<T> get(const settings& cfg, string_view key) {
if (auto ptr = get_if<T>(&cfg, key))
return *ptr;
return none;
}
template <class T>
optional<T> get(string_view key) {
return get<T>(xs, key);
}
};
} // namespace
CAF_TEST_FIXTURE_SCOPE(settings_reader_tests, fixture)
CAF_TEST(readers deserialize simple objects from configs) {
put(xs, "foo", "hello");
put(xs, "bar", "world");
foobar fb;
deserialize(fb);
CAF_CHECK_EQUAL(fb.foo(), "hello"s);
CAF_CHECK_EQUAL(fb.bar(), "world"s);
}
CAF_TEST(readers deserialize complex objects from configs) {
CAF_MESSAGE("fill a dictionary with data for a 'basics' object");
put(xs, "v1", settings{});
put(xs, "v2", 42_i64);
put(xs, "v3", i64_list({1, 2, 3, 4}));
settings msg1;
put(msg1, "content", 2.0);
put(msg1, "@content-type", "double");
settings msg2;
put(msg2, "content", "foobar"s);
put(msg2, "@content-type", "std::string");
put(xs, "v4", make_config_value_list(msg1, msg2));
put(xs, "v5", i64_list({10, 20}));
config_value::list v6;
v6.emplace_back(i64{123});
v6.emplace_back(msg1);
put(xs, "v6", v6);
put(xs, "v7.one", i64{1});
put(xs, "v7.two", i64{2});
put(xs, "v7.three", i64{3});
put(xs, "v8", i64_list());
CAF_MESSAGE("deserialize and verify the 'basics' object");
basics obj;
deserialize(obj);
CAF_CHECK_EQUAL(obj.v2, 42);
CAF_CHECK_EQUAL(obj.v3[0], 1);
CAF_CHECK_EQUAL(obj.v3[1], 2);
CAF_CHECK_EQUAL(obj.v3[2], 3);
CAF_CHECK_EQUAL(obj.v3[3], 4);
CAF_CHECK_EQUAL(obj.v4[0], dummy_message{{2.0}});
CAF_CHECK_EQUAL(obj.v4[1], dummy_message{{"foobar"s}});
CAF_CHECK_EQUAL(obj.v5[0], i64{10});
CAF_CHECK_EQUAL(obj.v5[1], i64{20});
CAF_CHECK_EQUAL(obj.v6, std::make_tuple(int32_t{123}, dummy_message{{2.0}}));
CAF_CHECK_EQUAL(obj.v7["one"], 1);
CAF_CHECK_EQUAL(obj.v7["two"], 2);
CAF_CHECK_EQUAL(obj.v7["three"], 3);
}
CAF_TEST(readers deserialize objects from the output of writers) {
CAF_MESSAGE("serialize the 'line' object");
{
line l{{10, 20, 30}, {70, 60, 50}};
settings_writer writer{&xs};
if (!inspect_object(writer, l))
CAF_FAIL("failed two write to settings: " << writer.get_error());
}
CAF_MESSAGE("serialize and verify the 'line' object");
{
line l{{0, 0, 0}, {0, 0, 0}};
deserialize(l);
CAF_CHECK_EQUAL(l.p1.x, 10);
CAF_CHECK_EQUAL(l.p1.y, 20);
CAF_CHECK_EQUAL(l.p1.z, 30);
CAF_CHECK_EQUAL(l.p2.x, 70);
CAF_CHECK_EQUAL(l.p2.y, 60);
CAF_CHECK_EQUAL(l.p2.z, 50);
}
}
CAF_TEST_FIXTURE_SCOPE_END()
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