Commit 59ed7e08 authored by Dominik Charousset's avatar Dominik Charousset

Implement new settings writer

parent 2d771bf0
...@@ -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_writer.cpp
src/size_based_credit_controller.cpp src/size_based_credit_controller.cpp
src/skip.cpp src/skip.cpp
src/stream_aborter.cpp src/stream_aborter.cpp
...@@ -177,6 +178,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -177,6 +178,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/timestamp.cpp src/timestamp.cpp
src/tracing_data.cpp src/tracing_data.cpp
src/tracing_data_factory.cpp src/tracing_data_factory.cpp
src/type_id.cpp
src/type_id_list.cpp src/type_id_list.cpp
src/uri.cpp src/uri.cpp
src/uri_builder.cpp src/uri_builder.cpp
...@@ -310,6 +312,7 @@ caf_add_test_suites(caf-core-test ...@@ -310,6 +312,7 @@ caf_add_test_suites(caf-core-test
serial_reply serial_reply
serialization serialization
settings settings
settings_writer
simple_timeout simple_timeout
span span
stateful_actor stateful_actor
......
...@@ -138,12 +138,28 @@ public: ...@@ -138,12 +138,28 @@ public:
return ok; return ok;
} }
constexpr bool begin_key_value_pair() noexcept {
return ok;
}
constexpr bool end_key_value_pair() noexcept {
return ok;
}
bool begin_sequence(size_t& list_size) noexcept; bool begin_sequence(size_t& list_size) noexcept;
constexpr bool end_sequence() noexcept { constexpr bool end_sequence() noexcept {
return ok; return ok;
} }
bool begin_associative_array(size_t& size) noexcept {
return begin_sequence(size);
}
bool end_associative_array() noexcept {
return end_sequence();
}
bool value(bool& x) noexcept; bool value(bool& x) noexcept;
bool value(byte& x) noexcept; bool value(byte& x) noexcept;
......
...@@ -124,12 +124,28 @@ public: ...@@ -124,12 +124,28 @@ public:
return ok; return ok;
} }
constexpr bool begin_key_value_pair() {
return ok;
}
constexpr bool end_key_value_pair() {
return ok;
}
bool begin_sequence(size_t list_size); bool begin_sequence(size_t list_size);
constexpr bool end_sequence() { constexpr bool end_sequence() {
return ok; return ok;
} }
bool begin_associative_array(size_t size) {
return begin_sequence(size);
}
bool end_associative_array() {
return end_sequence();
}
bool value(byte x); bool value(byte x);
bool value(bool x); bool value(bool x);
......
...@@ -88,12 +88,29 @@ public: ...@@ -88,12 +88,29 @@ public:
/// Ends processing of a sequence. /// Ends processing of a sequence.
virtual bool end_tuple() = 0; virtual bool end_tuple() = 0;
/// Begins processing of a tuple with two elements, whereas the first element
/// represents the key in an associative array.
/// @note the default implementation calls `begin_tuple(2)`.
virtual bool begin_key_value_pair();
/// Ends processing of a key-value pair after both values were written.
/// @note the default implementation calls `end_tuple()`.
virtual bool end_key_value_pair();
/// Begins processing of a sequence. /// Begins processing of a sequence.
virtual bool begin_sequence(size_t& size) = 0; virtual bool begin_sequence(size_t& size) = 0;
/// Ends processing of a sequence. /// Ends processing of a sequence.
virtual bool end_sequence() = 0; virtual bool end_sequence() = 0;
/// Begins processing of an associative array (map).
/// @note the default implementation calls `begin_sequence(size)`.
virtual bool begin_associative_array(size_t& size);
/// Ends processing of an associative array (map).
/// @note the default implementation calls `end_sequence()`.
virtual bool end_associative_array();
/// Reads primitive value from the input. /// Reads primitive value from the input.
/// @param x The primitive value. /// @param x The primitive value.
/// @returns A non-zero error code on failure, `sec::success` otherwise. /// @returns A non-zero error code on failure, `sec::success` otherwise.
......
...@@ -71,13 +71,33 @@ public: ...@@ -71,13 +71,33 @@ public:
bool end_field(); bool end_field();
bool begin_tuple(size_t size) {
return begin_sequence(size);
}
bool end_tuple() {
return end_sequence();
}
bool begin_key_value_pair() {
return begin_tuple(2);
}
bool end_key_value_pair() {
return end_tuple();
}
bool begin_sequence(size_t size); bool begin_sequence(size_t size);
bool end_sequence(); bool end_sequence();
bool begin_tuple(size_t size); bool begin_associative_array(size_t size) {
return begin_sequence(size);
}
bool end_tuple(); bool end_associative_array() {
return end_sequence();
}
bool value(bool x); bool value(bool x);
......
...@@ -93,6 +93,14 @@ public: ...@@ -93,6 +93,14 @@ public:
return true; return true;
} }
constexpr bool begin_key_value_pair() {
return true;
}
constexpr bool end_key_value_pair() {
return true;
}
constexpr bool begin_sequence(size_t) { constexpr bool begin_sequence(size_t) {
return true; return true;
} }
...@@ -101,6 +109,14 @@ public: ...@@ -101,6 +109,14 @@ public:
return true; return true;
} }
constexpr bool begin_associative_array(size_t) {
return true;
}
constexpr bool end_associative_array() {
return true;
}
template <class Integral> template <class Integral>
std::enable_if_t<std::is_integral<Integral>::value, bool> std::enable_if_t<std::is_integral<Integral>::value, bool>
value(Integral x) noexcept { value(Integral x) noexcept {
......
...@@ -142,22 +142,22 @@ template <class Inspector, class T> ...@@ -142,22 +142,22 @@ template <class Inspector, class T>
bool load_value(Inspector& f, T& x, inspector_access_type::map) { bool load_value(Inspector& f, T& x, inspector_access_type::map) {
x.clear(); x.clear();
size_t size = 0; size_t size = 0;
if (!f.begin_sequence(size)) if (!f.begin_associative_array(size))
return false; return false;
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
auto key = typename T::key_type{}; auto key = typename T::key_type{};
auto val = typename T::mapped_type{}; auto val = typename T::mapped_type{};
if (!(f.begin_tuple(2) // if (!(f.begin_key_value_pair() //
&& load_value(f, key) // && load_value(f, key) //
&& load_value(f, val) // && load_value(f, val) //
&& f.end_tuple())) && f.end_key_value_pair()))
return false; return false;
if (!x.emplace(std::move(key), std::move(val)).second) { if (!x.emplace(std::move(key), std::move(val)).second) {
f.emplace_error(sec::runtime_error, "multiple key definitions"); f.emplace_error(sec::runtime_error, "multiple key definitions");
return false; return false;
} }
} }
return f.end_sequence(); return f.end_associative_array();
} }
template <class Inspector, class T> template <class Inspector, class T>
...@@ -310,17 +310,16 @@ bool save_value(Inspector& f, T& x, inspector_access_type::tuple) { ...@@ -310,17 +310,16 @@ bool save_value(Inspector& f, T& x, inspector_access_type::tuple) {
template <class Inspector, class T> template <class Inspector, class T>
bool save_value(Inspector& f, T& x, inspector_access_type::map) { bool save_value(Inspector& f, T& x, inspector_access_type::map) {
auto size = x.size(); if (!f.begin_associative_array(x.size()))
if (!f.begin_sequence(size))
return false; return false;
for (auto&& kvp : x) { for (auto&& kvp : x) {
if (!(f.begin_tuple(2) // if (!(f.begin_key_value_pair() //
&& save_value(f, kvp.first) // && save_value(f, kvp.first) //
&& save_value(f, kvp.second) // && save_value(f, kvp.second) //
&& f.end_tuple())) && f.end_key_value_pair()))
return false; return false;
} }
return f.end_sequence(); return f.end_associative_array();
} }
template <class Inspector, class T> template <class Inspector, class T>
......
...@@ -93,12 +93,29 @@ public: ...@@ -93,12 +93,29 @@ public:
/// Ends processing of a tuple. /// Ends processing of a tuple.
virtual bool end_tuple() = 0; virtual bool end_tuple() = 0;
/// Begins processing of a tuple with two elements, whereas the first element
/// represents the key in an associative array.
/// @note the default implementation calls `begin_tuple(2)`.
virtual bool begin_key_value_pair();
/// Ends processing of a key-value pair after both values were written.
/// @note the default implementation calls `end_tuple()`.
virtual bool end_key_value_pair();
/// Begins processing of a sequence. Saves the size to the underlying storage. /// Begins processing of a sequence. Saves the size to the underlying storage.
virtual bool begin_sequence(size_t size) = 0; virtual bool begin_sequence(size_t size) = 0;
/// Ends processing of a sequence. /// Ends processing of a sequence.
virtual bool end_sequence() = 0; virtual bool end_sequence() = 0;
/// Begins processing of an associative array (map).
/// @note the default implementation calls `begin_sequence(size)`.
virtual bool begin_associative_array(size_t size);
/// Ends processing of an associative array (map).
/// @note the default implementation calls `end_sequence()`.
virtual bool end_associative_array();
/// Adds the primitive type `x` to the output. /// Adds the primitive type `x` to the output.
/// @param x The primitive value. /// @param x The primitive value.
/// @returns A non-zero error code on failure, `sec::success` otherwise. /// @returns A non-zero error code on failure, `sec::success` otherwise.
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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/config_value.hpp"
#include "caf/serializer.hpp"
#include "caf/settings.hpp"
#include <stack>
#include <vector>
namespace caf {
/// Writes objects into @ref settings.
class settings_writer final : public serializer {
public:
// -- member types------------------------------------------------------------
using super = serializer;
struct present_field {
settings* parent;
string_view name;
string_view type;
};
struct absent_field {};
using value_type
= variant<settings*, absent_field, present_field, config_value::list*>;
using stack_type = std::stack<value_type, std::vector<value_type>>;
// -- constructors, destructors, and assignment operators --------------------
settings_writer(settings* destination, actor_system& sys)
: super(sys), root_(destination) {
st_.push(destination);
has_human_readable_format_ = true;
}
settings_writer(settings* destination, execution_unit* ctx)
: super(ctx), root_(destination) {
has_human_readable_format_ = true;
}
explicit settings_writer(settings* destination)
: settings_writer(destination, nullptr) {
// nop
}
~settings_writer() override;
// -- interface functions ----------------------------------------------------
bool inject_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(string_view x) override;
bool value(const std::u16string& x) override;
bool value(const std::u32string& x) override;
bool value(span<const byte> x) override;
private:
bool push(config_value&& x);
stack_type st_;
string_view type_hint_;
settings* root_;
};
} // namespace caf
...@@ -35,6 +35,22 @@ deserializer::~deserializer() { ...@@ -35,6 +35,22 @@ deserializer::~deserializer() {
// nop // nop
} }
bool deserializer::begin_key_value_pair() {
return begin_tuple(2);
}
bool deserializer::end_key_value_pair() {
return end_tuple();
}
bool deserializer::begin_associative_array(size_t& size) {
return begin_sequence(size);
}
bool deserializer::end_associative_array() {
return end_sequence();
}
bool deserializer::value(std::vector<bool>& x) { bool deserializer::value(std::vector<bool>& x) {
x.clear(); x.clear();
size_t size = 0; size_t size = 0;
......
...@@ -104,14 +104,6 @@ bool stringification_inspector::end_sequence() { ...@@ -104,14 +104,6 @@ bool stringification_inspector::end_sequence() {
return ok; return ok;
} }
bool stringification_inspector::begin_tuple(size_t size) {
return begin_sequence(size);
}
bool stringification_inspector::end_tuple() {
return end_sequence();
}
bool stringification_inspector::value(bool x) { bool stringification_inspector::value(bool x) {
sep(); sep();
result_ += x ? "true" : "false"; result_ += x ? "true" : "false";
......
...@@ -35,6 +35,22 @@ serializer::~serializer() { ...@@ -35,6 +35,22 @@ serializer::~serializer() {
// nop // nop
} }
bool serializer::begin_key_value_pair() {
return begin_tuple(2);
}
bool serializer::end_key_value_pair() {
return end_tuple();
}
bool serializer::begin_associative_array(size_t size) {
return begin_sequence(size);
}
bool serializer::end_associative_array() {
return end_sequence();
}
bool serializer::value(const std::vector<bool>& xs) { bool serializer::value(const std::vector<bool>& xs) {
if (!begin_sequence(xs.size())) if (!begin_sequence(xs.size()))
return false; return false;
......
This diff is collapsed.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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. *
******************************************************************************/
#include "caf/type_id.hpp"
#include "caf/detail/meta_object.hpp"
namespace caf {
string_view query_type_name(type_id_t type) {
if (auto ptr = detail::global_meta_object(type))
return ptr->type_name;
return {};
}
type_id_t query_type_id(string_view name) {
auto objects = detail::global_meta_objects();
for (size_t index = 0; index < objects.size(); ++index)
if (objects[index].type_name == name)
return static_cast<type_id_t>(index);
return invalid_type_id;
}
} // namespace caf
// This header includes various types for testing save and load inspectors.
#pragma once
#include "caf/optional.hpp"
#include "caf/type_id.hpp"
#include "caf/variant.hpp"
#include "nasty.hpp"
namespace {
struct point_3d;
struct line;
struct duration;
struct person;
class foobar;
struct dummy_message;
struct fallback_dummy_message;
struct basics;
} // namespace
#define CAF_TEST_SET_TYPE_NAME(type) \
namespace caf { \
template <> \
struct type_name<type> { \
static constexpr string_view value = #type; \
}; \
}
CAF_TEST_SET_TYPE_NAME(point_3d)
CAF_TEST_SET_TYPE_NAME(line)
CAF_TEST_SET_TYPE_NAME(duration)
CAF_TEST_SET_TYPE_NAME(person)
CAF_TEST_SET_TYPE_NAME(foobar)
CAF_TEST_SET_TYPE_NAME(dummy_message)
CAF_TEST_SET_TYPE_NAME(fallback_dummy_message)
CAF_TEST_SET_TYPE_NAME(basics)
CAF_TEST_SET_TYPE_NAME(nasty)
namespace {
struct point_3d {
int32_t x;
int32_t y;
int32_t z;
};
template <class Inspector>
bool inspect(Inspector& f, point_3d& x) {
return f.object(x).fields(f.field("x", x.x), f.field("y", x.y),
f.field("z", x.z));
}
struct line {
point_3d p1;
point_3d p2;
};
template <class Inspector>
bool inspect(Inspector& f, line& x) {
return f.object(x).fields(f.field("p1", x.p1), f.field("p2", x.p2));
}
struct duration {
std::string unit;
double count;
};
[[maybe_unused]] bool valid_time_unit(const std::string& unit) {
return unit == "seconds" || unit == "minutes";
}
template <class Inspector>
bool inspect(Inspector& f, duration& x) {
return f.object(x).fields(
f.field("unit", x.unit).fallback("seconds").invariant(valid_time_unit),
f.field("count", x.count));
}
struct person {
std::string name;
caf::optional<std::string> phone;
};
template <class Inspector>
bool inspect(Inspector& f, person& x) {
return f.object(x).fields(f.field("name", x.name), f.field("phone", x.phone));
}
class foobar {
public:
foobar() = default;
foobar(const foobar&) = default;
foobar& operator=(const foobar&) = default;
foobar(std::string foo, std::string bar)
: foo_(std::move(foo)), bar_(std::move(bar)) {
// nop
}
const std::string& foo() {
return foo_;
}
void foo(std::string value) {
foo_ = std::move(value);
}
const std::string& bar() {
return bar_;
}
void bar(std::string value) {
bar_ = std::move(value);
}
private:
std::string foo_;
std::string bar_;
};
template <class Inspector>
bool inspect(Inspector& f, foobar& x) {
auto get_foo = [&x]() -> decltype(auto) { return x.foo(); };
auto set_foo = [&x](std::string value) {
x.foo(std::move(value));
return true;
};
auto get_bar = [&x]() -> decltype(auto) { return x.bar(); };
auto set_bar = [&x](std::string value) {
x.bar(std::move(value));
return true;
};
return f.object(x).fields(f.field("foo", get_foo, set_foo),
f.field("bar", get_bar, set_bar));
}
struct dummy_message {
caf::variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, dummy_message& x) {
return f.object(x).fields(f.field("content", x.content));
}
struct fallback_dummy_message {
caf::variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, fallback_dummy_message& x) {
return f.object(x).fields(f.field("content", x.content).fallback(42.0));
}
struct basics {
struct tag {};
tag v1;
int32_t v2;
int32_t v3[4];
dummy_message v4[2];
std::array<int32_t, 2> v5;
std::tuple<int32_t, dummy_message> v6;
std::map<std::string, int32_t> v7;
std::vector<std::list<std::pair<std::string, std::array<int32_t, 3>>>> v8;
};
template <class Inspector>
bool inspect(Inspector& f, basics& x) {
return f.object(x).fields(f.field("v1", x.v1), f.field("v2", x.v2),
f.field("v3", x.v3), f.field("v4", x.v4),
f.field("v5", x.v5), f.field("v6", x.v6),
f.field("v7", x.v7), f.field("v8", x.v8));
}
} // namespace
...@@ -33,153 +33,13 @@ ...@@ -33,153 +33,13 @@
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
#include "caf/variant.hpp" #include "caf/variant.hpp"
#include "nasty.hpp" #include "inspector-tests.hpp"
using namespace caf; using namespace caf;
namespace { namespace {
using string_list = std::vector<std::string>; struct testee : deserializer {
struct point_3d {
static inline string_view tname = "point_3d";
int32_t x;
int32_t y;
int32_t z;
};
template <class Inspector>
bool inspect(Inspector& f, point_3d& x) {
return f.object(x).fields(f.field("x", x.x), f.field("y", x.y),
f.field("z", x.z));
}
struct line {
static inline string_view tname = "line";
point_3d p1;
point_3d p2;
};
template <class Inspector>
bool inspect(Inspector& f, line& x) {
return f.object(x).fields(f.field("p1", x.p1), f.field("p2", x.p2));
}
struct duration {
static inline string_view tname = "duration";
std::string unit;
double count;
};
bool valid_time_unit(const std::string& unit) {
return unit == "seconds" || unit == "minutes";
}
template <class Inspector>
bool inspect(Inspector& f, duration& x) {
return f.object(x).fields(
f.field("unit", x.unit).fallback("seconds").invariant(valid_time_unit),
f.field("count", x.count));
}
struct person {
static inline string_view tname = "person";
std::string name;
optional<std::string> phone;
};
template <class Inspector>
bool inspect(Inspector& f, person& x) {
return f.object(x).fields(f.field("name", x.name), f.field("phone", x.phone));
}
class foobar {
public:
static inline string_view tname = "foobar";
const std::string& foo() {
return foo_;
}
void foo(std::string value) {
foo_ = std::move(value);
}
const std::string& bar() {
return bar_;
}
void bar(std::string value) {
bar_ = std::move(value);
}
private:
std::string foo_;
std::string bar_;
};
template <class Inspector>
bool inspect(Inspector& f, foobar& x) {
auto get_foo = [&x]() -> decltype(auto) { return x.foo(); };
auto set_foo = [&x](std::string value) {
x.foo(std::move(value));
return true;
};
auto get_bar = [&x]() -> decltype(auto) { return x.bar(); };
auto set_bar = [&x](std::string value) {
x.bar(std::move(value));
return true;
};
return f.object(x).fields(f.field("foo", get_foo, set_foo),
f.field("bar", get_bar, set_bar));
}
struct dummy_message {
static inline string_view tname = "dummy_message";
variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, dummy_message& x) {
return f.object(x).fields(f.field("content", x.content));
}
struct fallback_dummy_message {
static inline string_view tname = "fallback_dummy_message";
variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, fallback_dummy_message& x) {
return f.object(x).fields(f.field("content", x.content).fallback(42.0));
}
struct basics {
static inline string_view tname = "basics";
struct tag {
static inline string_view tname = "tag";
};
tag v1;
int32_t v2;
int32_t v3[4];
dummy_message v4[2];
std::array<int32_t, 2> v5;
std::tuple<int32_t, dummy_message> v6;
std::map<std::string, int32_t> v7;
std::vector<std::list<std::pair<std::string, std::array<int32_t, 3>>>> v8;
};
template <class Inspector>
bool inspect(Inspector& f, basics& x) {
return f.object(x).fields(f.field("v1", x.v1), f.field("v2", x.v2),
f.field("v3", x.v3), f.field("v4", x.v4),
f.field("v5", x.v5), f.field("v6", x.v6),
f.field("v7", x.v7), f.field("v8", x.v8));
}
struct testee : load_inspector_base<testee> {
std::string log; std::string log;
bool load_field_failed(string_view, sec code) { bool load_field_failed(string_view, sec code) {
...@@ -194,9 +54,10 @@ struct testee : load_inspector_base<testee> { ...@@ -194,9 +54,10 @@ struct testee : load_inspector_base<testee> {
log.insert(log.end(), indent, ' '); log.insert(log.end(), indent, ' ');
} }
template <class T> using deserializer::object;
auto object(T&) {
return object_t<testee>{T::tname, this}; bool fetch_next_object_type(type_id_t&) override {
return false;
} }
template <class T> template <class T>
...@@ -204,7 +65,12 @@ struct testee : load_inspector_base<testee> { ...@@ -204,7 +65,12 @@ struct testee : load_inspector_base<testee> {
return object_t<testee>{"optional", this}; return object_t<testee>{"optional", this};
} }
bool begin_object(string_view object_name) { template <class... Ts>
auto object(variant<Ts...>&) {
return object_t<testee>{"variant", this};
}
bool begin_object(string_view object_name) override {
new_line(); new_line();
indent += 2; indent += 2;
log += "begin object "; log += "begin object ";
...@@ -212,14 +78,14 @@ struct testee : load_inspector_base<testee> { ...@@ -212,14 +78,14 @@ struct testee : load_inspector_base<testee> {
return ok; return ok;
} }
bool end_object() { bool end_object() override {
indent -= 2; indent -= 2;
new_line(); new_line();
log += "end object"; log += "end object";
return ok; return ok;
} }
bool begin_field(string_view name) { bool begin_field(string_view name) override {
new_line(); new_line();
indent += 2; indent += 2;
log += "begin field "; log += "begin field ";
...@@ -227,7 +93,7 @@ struct testee : load_inspector_base<testee> { ...@@ -227,7 +93,7 @@ struct testee : load_inspector_base<testee> {
return ok; return ok;
} }
bool begin_field(string_view name, bool& is_present) { bool begin_field(string_view name, bool& is_present) override {
new_line(); new_line();
indent += 2; indent += 2;
log += "begin optional field "; log += "begin optional field ";
...@@ -237,7 +103,7 @@ struct testee : load_inspector_base<testee> { ...@@ -237,7 +103,7 @@ struct testee : load_inspector_base<testee> {
} }
bool begin_field(string_view name, span<const type_id_t>, bool begin_field(string_view name, span<const type_id_t>,
size_t& type_index) { size_t& type_index) override {
new_line(); new_line();
indent += 2; indent += 2;
log += "begin variant field "; log += "begin variant field ";
...@@ -247,7 +113,7 @@ struct testee : load_inspector_base<testee> { ...@@ -247,7 +113,7 @@ struct testee : load_inspector_base<testee> {
} }
bool begin_field(string_view name, bool& is_present, span<const type_id_t>, bool begin_field(string_view name, bool& is_present, span<const type_id_t>,
size_t&) { size_t&) override {
new_line(); new_line();
indent += 2; indent += 2;
log += "begin optional variant field "; log += "begin optional variant field ";
...@@ -256,14 +122,14 @@ struct testee : load_inspector_base<testee> { ...@@ -256,14 +122,14 @@ struct testee : load_inspector_base<testee> {
return ok; return ok;
} }
bool end_field() { bool end_field() override {
indent -= 2; indent -= 2;
new_line(); new_line();
log += "end field"; log += "end field";
return ok; return ok;
} }
bool begin_tuple(size_t size) { bool begin_tuple(size_t size) override {
new_line(); new_line();
indent += 2; indent += 2;
log += "begin tuple of size "; log += "begin tuple of size ";
...@@ -271,14 +137,28 @@ struct testee : load_inspector_base<testee> { ...@@ -271,14 +137,28 @@ struct testee : load_inspector_base<testee> {
return ok; return ok;
} }
bool end_tuple() { bool end_tuple() override {
indent -= 2; indent -= 2;
new_line(); new_line();
log += "end tuple"; log += "end tuple";
return ok; return ok;
} }
bool begin_sequence(size_t& size) { bool begin_key_value_pair() override {
new_line();
indent += 2;
log += "begin key-value pair";
return ok;
}
bool end_key_value_pair() override {
indent -= 2;
new_line();
log += "end key-value pair";
return ok;
}
bool begin_sequence(size_t& size) override {
size = 0; size = 0;
new_line(); new_line();
indent += 2; indent += 2;
...@@ -287,15 +167,38 @@ struct testee : load_inspector_base<testee> { ...@@ -287,15 +167,38 @@ struct testee : load_inspector_base<testee> {
return ok; return ok;
} }
bool end_sequence() { bool end_sequence() override {
indent -= 2; indent -= 2;
new_line(); new_line();
log += "end sequence"; log += "end sequence";
return ok; return ok;
} }
bool begin_associative_array(size_t& size) override {
size = 0;
new_line();
indent += 2;
log += "begin associative array of size ";
log += std::to_string(size);
return ok;
}
bool end_associative_array() override {
indent -= 2;
new_line();
log += "end associative array";
return ok;
}
bool value(bool& x) override {
new_line();
log += "bool value";
x = false;
return ok;
}
template <class T> template <class T>
std::enable_if_t<std::is_arithmetic<T>::value, bool> value(T& x) { bool primitive_value(T& x) {
new_line(); new_line();
auto tn = type_name_v<T>; auto tn = type_name_v<T>;
log.insert(log.end(), tn.begin(), tn.end()); log.insert(log.end(), tn.begin(), tn.end());
...@@ -304,10 +207,67 @@ struct testee : load_inspector_base<testee> { ...@@ -304,10 +207,67 @@ struct testee : load_inspector_base<testee> {
return ok; return ok;
} }
bool value(std::string& x) { bool value(int8_t& x) override {
return primitive_value(x);
}
bool value(uint8_t& x) override {
return primitive_value(x);
}
bool value(int16_t& x) override {
return primitive_value(x);
}
bool value(uint16_t& x) override {
return primitive_value(x);
}
bool value(int32_t& x) override {
return primitive_value(x);
}
bool value(uint32_t& x) override {
return primitive_value(x);
}
bool value(int64_t& x) override {
return primitive_value(x);
}
bool value(uint64_t& x) override {
return primitive_value(x);
}
bool value(float& x) override {
return primitive_value(x);
}
bool value(double& x) override {
return primitive_value(x);
}
bool value(long double& x) override {
return primitive_value(x);
}
bool value(std::string& x) override {
return primitive_value(x);
}
bool value(std::u16string& x) override {
return primitive_value(x);
}
bool value(std::u32string& x) override {
return primitive_value(x);
}
bool value(span<byte> xs) override {
new_line(); new_line();
log += "std::string value"; log += "caf::span<caf::byte> value";
x.clear(); for (auto& x : xs)
x = byte{0};
return ok; return ok;
} }
}; };
...@@ -566,7 +526,7 @@ CAF_TEST(load inspectors support all basic STL types) { ...@@ -566,7 +526,7 @@ CAF_TEST(load inspectors support all basic STL types) {
CAF_CHECK_EQUAL(f.log, R"_( CAF_CHECK_EQUAL(f.log, R"_(
begin object basics begin object basics
begin field v1 begin field v1
begin object tag begin object anonymous
end object end object
end field end field
begin field v2 begin field v2
...@@ -611,8 +571,8 @@ begin object basics ...@@ -611,8 +571,8 @@ begin object basics
end tuple end tuple
end field end field
begin field v7 begin field v7
begin sequence of size 0 begin associative array of size 0
end sequence end associative array
end field end field
begin field v8 begin field v8
begin sequence of size 0 begin sequence of size 0
......
...@@ -29,159 +29,12 @@ ...@@ -29,159 +29,12 @@
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
#include "nasty.hpp" #include "inspector-tests.hpp"
namespace {
struct point_3d;
struct line;
struct duration;
struct person;
class foobar;
struct dummy_message;
struct basics;
} // namespace
#define CAF_TYPE_NAME(type) \
namespace caf { \
template <> \
struct type_name<type> { \
static constexpr string_view value = #type; \
}; \
}
CAF_TYPE_NAME(point_3d)
CAF_TYPE_NAME(line)
CAF_TYPE_NAME(duration)
CAF_TYPE_NAME(person)
CAF_TYPE_NAME(foobar)
CAF_TYPE_NAME(dummy_message)
CAF_TYPE_NAME(basics)
CAF_TYPE_NAME(nasty)
using namespace caf; using namespace caf;
namespace { namespace {
using string_list = std::vector<std::string>;
struct point_3d {
int32_t x;
int32_t y;
int32_t z;
};
template <class Inspector>
bool inspect(Inspector& f, point_3d& x) {
return f.object(x).fields(f.field("x", x.x), f.field("y", x.y),
f.field("z", x.z));
}
struct line {
point_3d p1;
point_3d p2;
};
template <class Inspector>
bool inspect(Inspector& f, line& x) {
return f.object(x).fields(f.field("p1", x.p1), f.field("p2", x.p2));
}
struct duration {
std::string unit;
double count;
};
bool valid_time_unit(const std::string& unit) {
return unit == "seconds" || unit == "minutes";
}
template <class Inspector>
bool inspect(Inspector& f, duration& x) {
return f.object(x).fields(
f.field("unit", x.unit).fallback("seconds").invariant(valid_time_unit),
f.field("count", x.count));
}
struct person {
std::string name;
optional<std::string> phone;
};
template <class Inspector>
bool inspect(Inspector& f, person& x) {
return f.object(x).fields(f.field("name", x.name), f.field("phone", x.phone));
}
class foobar {
public:
const std::string& foo() {
return foo_;
}
void foo(std::string value) {
foo_ = std::move(value);
}
const std::string& bar() {
return bar_;
}
void bar(std::string value) {
bar_ = std::move(value);
}
private:
std::string foo_;
std::string bar_;
};
template <class Inspector>
bool inspect(Inspector& f, foobar& x) {
auto get_foo = [&x]() -> decltype(auto) { return x.foo(); };
auto set_foo = [&x](std::string value) {
x.foo(std::move(value));
return true;
};
auto get_bar = [&x]() -> decltype(auto) { return x.bar(); };
auto set_bar = [&x](std::string value) {
x.bar(std::move(value));
return true;
};
return f.object(x).fields(f.field("foo", get_foo, set_foo),
f.field("bar", get_bar, set_bar));
}
struct dummy_message {
variant<std::string, double> content;
};
template <class Inspector>
bool inspect(Inspector& f, dummy_message& x) {
return f.object(x).fields(f.field("content", x.content));
}
struct basics {
struct tag {};
tag v1;
int32_t v2;
int32_t v3[4];
dummy_message v4[2];
std::array<int32_t, 2> v5;
std::tuple<int32_t, dummy_message> v6;
std::map<std::string, int32_t> v7;
std::vector<std::list<std::pair<std::string, std::array<int32_t, 3>>>> v8;
};
template <class Inspector>
bool inspect(Inspector& f, basics& x) {
return f.object(x).fields(f.field("v1", x.v1), f.field("v2", x.v2),
f.field("v3", x.v3), f.field("v4", x.v4),
f.field("v5", x.v5), f.field("v6", x.v6),
f.field("v7", x.v7), f.field("v8", x.v8));
}
struct testee : serializer { struct testee : serializer {
std::string log; std::string log;
...@@ -292,6 +145,22 @@ struct testee : serializer { ...@@ -292,6 +145,22 @@ struct testee : serializer {
return ok; return ok;
} }
bool begin_key_value_pair() override {
new_line();
indent += 2;
log += "begin key-value pair";
return ok;
}
bool end_key_value_pair() override {
if (indent < 2)
CAF_FAIL("begin/end mismatch");
indent -= 2;
new_line();
log += "end key-value pair";
return ok;
}
bool begin_sequence(size_t size) override { bool begin_sequence(size_t size) override {
new_line(); new_line();
indent += 2; indent += 2;
...@@ -309,6 +178,23 @@ struct testee : serializer { ...@@ -309,6 +178,23 @@ struct testee : serializer {
return ok; return ok;
} }
bool begin_associative_array(size_t size) override {
new_line();
indent += 2;
log += "begin associative array of size ";
log += std::to_string(size);
return ok;
}
bool end_associative_array() override {
if (indent < 2)
CAF_FAIL("begin/end mismatch");
indent -= 2;
new_line();
log += "end associative array";
return ok;
}
bool value(bool) override { bool value(bool) override {
new_line(); new_line();
log += "bool value"; log += "bool value";
...@@ -778,20 +664,20 @@ begin object basics ...@@ -778,20 +664,20 @@ begin object basics
end tuple end tuple
end field end field
begin field v7 begin field v7
begin sequence of size 3 begin associative array of size 3
begin tuple of size 2 begin key-value pair
std::string value std::string value
int32_t value int32_t value
end tuple end key-value pair
begin tuple of size 2 begin key-value pair
std::string value std::string value
int32_t value int32_t value
end tuple end key-value pair
begin tuple of size 2 begin key-value pair
std::string value std::string value
int32_t value int32_t value
end tuple end key-value pair
end sequence end associative array
end field end field
begin field v8 begin field v8
begin sequence of size 2 begin sequence of size 2
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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_writer
#include "caf/settings_writer.hpp"
#include "caf/test/dsl.hpp"
#include "inspector-tests.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 set(const T& value) {
settings_writer writer{&xs};
if (!inspect_object(writer, value))
CAF_FAIL("failed two write to settings: " << writer.get_error());
}
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_writer_tests, fixture)
CAF_TEST(structs become dictionaries) {
set(foobar{"hello", "world"});
CAF_CHECK_EQUAL(get<std::string>("foo"), "hello"s);
CAF_CHECK_EQUAL(get<std::string>("bar"), "world"s);
}
CAF_TEST(nested structs become nested dictionaries) {
set(line{{10, 20, 30}, {70, 60, 50}});
CAF_CHECK_EQUAL(get<i64>("p1.x"), 10_i64);
CAF_CHECK_EQUAL(get<i64>("p1.y"), 20_i64);
CAF_CHECK_EQUAL(get<i64>("p1.z"), 30_i64);
CAF_CHECK_EQUAL(get<i64>("p2.x"), 70_i64);
CAF_CHECK_EQUAL(get<i64>("p2.y"), 60_i64);
CAF_CHECK_EQUAL(get<i64>("p2.z"), 50_i64);
}
CAF_TEST(empty types and maps become dictionaries) {
basics tst;
tst.v2 = 42;
for (size_t index = 0; index < 4; ++index)
tst.v3[index] = -static_cast<int32_t>(index + 1);
for (size_t index = 0; index < 2; ++index)
tst.v4[index] = dummy_message{{static_cast<double>(index)}};
for (size_t index = 0; index < 2; ++index)
tst.v5[index] = static_cast<int32_t>(index + 1) * 10;
tst.v6 = std::make_tuple(42, dummy_message{{"foobar"s}});
tst.v7["one"] = 1;
tst.v7["two"] = 2;
tst.v7["three"] = 3;
set(tst);
CAF_MESSAGE(xs);
CAF_CHECK_EQUAL(get<settings>("v1"), settings{});
CAF_CHECK_EQUAL(get<i64>("v2"), 42_i64);
CAF_CHECK_EQUAL(get<i64_list>("v3"), i64_list({-1, -2, -3, -4}));
if (auto v4 = get<config_value::list>("v4");
CAF_CHECK_EQUAL(v4->size(), 2u)) {
if (auto v1 = v4->front(); CAF_CHECK(holds_alternative<settings>(v1))) {
auto& v1_xs = caf::get<settings>(v1);
CAF_CHECK_EQUAL(get<double>(v1_xs, "content"), 0.0);
CAF_CHECK_EQUAL(get<std::string>(v1_xs, "@content-type"),
to_string(type_name_v<double>));
}
if (auto v2 = v4->back(); CAF_CHECK(holds_alternative<settings>(v2))) {
auto& v2_xs = caf::get<settings>(v2);
CAF_CHECK_EQUAL(get<double>(v2_xs, "content"), 1.0);
CAF_CHECK_EQUAL(get<std::string>(v2_xs, "@content-type"),
to_string(type_name_v<double>));
}
}
CAF_CHECK_EQUAL(get<i64_list>("v5"), i64_list({10, 20}));
// TODO: check v6
CAF_CHECK_EQUAL(get<i64>("v7.one"), 1_i64);
CAF_CHECK_EQUAL(get<i64>("v7.two"), 2_i64);
CAF_CHECK_EQUAL(get<i64>("v7.three"), 3_i64);
CAF_CHECK_EQUAL(get<config_value::list>("v8"), config_value::list());
}
CAF_TEST_FIXTURE_SCOPE_END()
...@@ -546,26 +546,29 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture; ...@@ -546,26 +546,29 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture;
} while (false) } while (false)
#define CAF_CHECK(...) \ #define CAF_CHECK(...) \
do { \ ([&] { \
static_cast<void>(::caf::test::detail::check( \ auto caf_check_res \
::caf::test::engine::current_test(), __FILE__, __LINE__, #__VA_ARGS__, \ = ::caf::test::detail::check(::caf::test::engine::current_test(), \
false, static_cast<bool>(__VA_ARGS__))); \ __FILE__, __LINE__, #__VA_ARGS__, false, \
static_cast<bool>(__VA_ARGS__)); \
::caf::test::engine::last_check_file(__FILE__); \ ::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \ ::caf::test::engine::last_check_line(__LINE__); \
} while (false) return caf_check_res; \
})()
#define CAF_CHECK_FUNC(func, x_expr, y_expr) \ #define CAF_CHECK_FUNC(func, x_expr, y_expr) \
do { \ ([&] { \
func comparator; \ func comparator; \
auto&& x_val___ = x_expr; \ auto&& x_val___ = x_expr; \
auto&& y_val___ = y_expr; \ auto&& y_val___ = y_expr; \
static_cast<void>(::caf::test::detail::check( \ auto caf_check_res = ::caf::test::detail::check( \
::caf::test::engine::current_test(), __FILE__, __LINE__, \ ::caf::test::engine::current_test(), __FILE__, __LINE__, \
CAF_FUNC_EXPR(func, x_expr, y_expr), false, \ CAF_FUNC_EXPR(func, x_expr, y_expr), false, \
comparator(x_val___, y_val___), x_val___, y_val___)); \ comparator(x_val___, y_val___), x_val___, y_val___); \
::caf::test::engine::last_check_file(__FILE__); \ ::caf::test::engine::last_check_file(__FILE__); \
::caf::test::engine::last_check_line(__LINE__); \ ::caf::test::engine::last_check_line(__LINE__); \
} while (false) return caf_check_res; \
})()
#define CAF_CHECK_FAIL(...) \ #define CAF_CHECK_FAIL(...) \
do { \ do { \
......
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