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;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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/settings_writer.hpp"
#include "caf/detail/append_hex.hpp"
#include "caf/detail/overload.hpp"
#define CHECK_NOT_EMPTY() \
do { \
if (st_.empty()) { \
emplace_error(sec::runtime_error, "mismatching calls to begin/end"); \
return false; \
} \
} while (false)
#define CHECK_VALID() \
do { \
CHECK_NOT_EMPTY(); \
if (holds_alternative<none_t>(st_.top())) { \
emplace_error(sec::runtime_error, \
"attempted to write to a non-existent optional field"); \
return false; \
} \
} while (false)
#define SCOPE(top_type) \
CHECK_VALID(); \
if (!holds_alternative<top_type>(st_.top())) { \
if constexpr (std::is_same<top_type, settings>::value) { \
emplace_error(sec::runtime_error, \
"attempted to add list items before calling " \
"begin_sequence or begin_tuple"); \
} else { \
emplace_error(sec::runtime_error, \
"attempted to add fields to a list item"); \
} \
return false; \
} \
[[maybe_unused]] auto& top = get<top_type>(st_.top());
namespace caf {
// -- constructors, destructors, and assignment operators ----------------------
settings_writer::~settings_writer() {
// nop
}
// -- interface functions ------------------------------------------------------
bool settings_writer::inject_next_object_type(type_id_t type) {
CHECK_NOT_EMPTY();
type_hint_ = query_type_name(type);
if (type_hint_.empty()) {
emplace_error(sec::runtime_error,
"query_type_name returned an empty string for type ID");
return false;
}
return true;
}
bool settings_writer::begin_object(string_view) {
if (st_.empty()) {
if (root_ == nullptr) {
emplace_error(sec::runtime_error,
"tried to serialize multiple objects into the root object");
return false;
}
st_.push(root_);
root_ = nullptr;
} else {
auto f = detail::make_overload(
[this](settings*) {
emplace_error(sec::runtime_error,
"begin_object called inside another object");
return false;
},
[this](absent_field) {
emplace_error(sec::runtime_error,
"begin_object called inside non-existent optional field");
return false;
},
[this](present_field fld) {
auto [iter, added] = fld.parent->emplace(fld.name, settings{});
if (!added) {
emplace_error(sec::runtime_error,
"field already defined: " + to_string(fld.name));
return false;
}
auto obj = std::addressof(get<settings>(iter->second));
if (!fld.type.empty())
put(*obj, "@type", fld.type);
st_.push(obj);
return true;
},
[this](config_value::list* ls) {
ls->emplace_back(settings{});
st_.push(std::addressof(get<settings>(ls->back())));
return true;
});
if (!visit(f, st_.top()))
return false;
}
if (!type_hint_.empty()) {
put(*get<settings*>(st_.top()), "@type", type_hint_);
type_hint_ = string_view{};
}
return true;
}
bool settings_writer::end_object() {
SCOPE(settings*);
st_.pop();
return true;
}
bool settings_writer::begin_field(string_view name) {
SCOPE(settings*);
st_.push(present_field{top, name, string_view{}});
return true;
}
bool settings_writer::begin_field(string_view name, bool is_present) {
SCOPE(settings*);
if (is_present)
st_.push(present_field{top, name, string_view{}});
else
st_.push(absent_field{});
return true;
}
bool settings_writer::begin_field(string_view name, span<const type_id_t> types,
size_t index) {
SCOPE(settings*);
if (index >= types.size()) {
emplace_error(sec::invalid_argument,
"index out of range in optional variant field "
+ to_string(name));
return false;
}
auto tn = query_type_name(types[index]);
if (tn.empty()) {
emplace_error(sec::runtime_error,
"query_type_name returned an empty string for type ID");
return false;
}
st_.push(present_field{top, name, tn});
return true;
}
bool settings_writer::begin_field(string_view name, bool is_present,
span<const type_id_t> types, size_t index) {
if (is_present)
return begin_field(name, types, index);
else
return begin_field(name, false);
}
bool settings_writer::end_field() {
CHECK_NOT_EMPTY();
if (!holds_alternative<present_field>(st_.top())
&& !holds_alternative<absent_field>(st_.top())) {
emplace_error(sec::runtime_error, "end_field called outside of a field");
return false;
}
st_.pop();
return true;
}
bool settings_writer::begin_tuple(size_t size) {
return begin_sequence(size);
}
bool settings_writer::end_tuple() {
return end_sequence();
}
bool settings_writer::begin_key_value_pair() {
SCOPE(settings*);
auto [iter, added] = top->emplace("@tmp", config_value::list{});
if (!added) {
emplace_error(sec::runtime_error, "temporary entry @tmp already exists");
return false;
}
st_.push(std::addressof(get<config_value::list>(iter->second)));
return true;
}
bool settings_writer::end_key_value_pair() {
config_value::list tmp;
/* lifetime scope of the list */ {
SCOPE(config_value::list*);
if (top->size() != 2) {
emplace_error(sec::runtime_error,
"a key-value pair must have exactly two elements");
return false;
}
tmp = std::move(*top);
st_.pop();
}
SCOPE(settings*);
// Get key and value from the temporary list.
top->container().erase("@tmp");
std::string key;
if (auto str = get_if<std::string>(std::addressof(tmp[0])))
key = std::move(*str);
else
key = to_string(tmp[0]);
if (!top->emplace(std::move(key), std::move(tmp[1])).second) {
emplace_error(sec::runtime_error, "multiple definitions for key");
return false;
}
return true;
}
bool settings_writer::begin_sequence(size_t) {
CHECK_NOT_EMPTY();
auto f = detail::make_overload(
[this](settings*) {
emplace_error(sec::runtime_error,
"cannot start sequence/tuple inside an object");
return false;
},
[this](absent_field) {
emplace_error(
sec::runtime_error,
"cannot start sequence/tuple inside non-existent optional field");
return false;
},
[this](present_field fld) {
auto [iter, added] = fld.parent->emplace(fld.name, config_value::list{});
if (!added) {
emplace_error(sec::runtime_error,
"field already defined: " + to_string(fld.name));
return false;
}
st_.push(std::addressof(get<config_value::list>(iter->second)));
return true;
},
[this](config_value::list* ls) {
ls->emplace_back(config_value::list{});
st_.push(std::addressof(get<config_value::list>(ls->back())));
return true;
});
return visit(f, st_.top());
}
bool settings_writer::end_sequence() {
SCOPE(config_value::list*);
st_.pop();
return true;
}
bool settings_writer::begin_associative_array(size_t) {
CHECK_NOT_EMPTY();
settings* inner = nullptr;
auto f = detail::make_overload(
[this](settings*) {
emplace_error(sec::runtime_error, "cannot write values outside fields");
return false;
},
[this](absent_field) {
emplace_error(sec::runtime_error,
"cannot add values to non-existent optional field");
return false;
},
[this, &inner](present_field fld) {
auto [iter, added] = fld.parent->emplace(fld.name,
config_value{settings{}});
if (!added) {
emplace_error(sec::runtime_error,
"field already defined: " + to_string(fld.name));
return false;
}
if (!fld.type.empty()) {
std::string key;
key += '@';
key.insert(key.end(), fld.name.begin(), fld.name.end());
key += "-type";
if (fld.parent->contains(key)) {
emplace_error(sec::runtime_error,
"type of variant field already defined.");
return false;
}
put(*fld.parent, key, fld.type);
}
inner = std::addressof(get<settings>(iter->second));
return true;
},
[&inner](config_value::list* ls) {
ls->emplace_back(config_value{settings{}});
inner = std::addressof(get<settings>(ls->back()));
return true;
});
if (visit(f, st_.top())) {
CAF_ASSERT(inner != nullptr);
st_.push(inner);
return true;
}
return false;
}
bool settings_writer::end_associative_array() {
SCOPE(settings*);
st_.pop();
return true;
}
bool settings_writer::value(bool x) {
return push(config_value{x});
}
bool settings_writer::value(int8_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(uint8_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(int16_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(uint16_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(int32_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(uint32_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(int64_t x) {
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(uint64_t x) {
auto max_val = std::numeric_limits<config_value::integer>::max();
if (x > static_cast<uint64_t>(max_val)) {
emplace_error(sec::runtime_error, "integer overflow");
return false;
}
return push(config_value{static_cast<config_value::integer>(x)});
}
bool settings_writer::value(float x) {
return push(config_value{double{x}});
}
bool settings_writer::value(double x) {
return push(config_value{x});
}
bool settings_writer::value(long double x) {
return push(config_value{std::to_string(x)});
}
bool settings_writer::value(string_view x) {
return push(config_value{to_string(x)});
}
bool settings_writer::value(const std::u16string&) {
emplace_error(sec::runtime_error, "u16string support not implemented yet");
return false;
}
bool settings_writer::value(const std::u32string&) {
emplace_error(sec::runtime_error, "u32string support not implemented yet");
return false;
}
bool settings_writer::value(span<const byte> x) {
std::string str;
detail::append_hex(str, x.data(), x.size());
return push(config_value{std::move(str)});
}
bool settings_writer::push(config_value&& x) {
CHECK_NOT_EMPTY();
auto f = detail::make_overload(
[this](settings*) {
emplace_error(sec::runtime_error, "cannot write values outside fields");
return false;
},
[this](absent_field) {
emplace_error(sec::runtime_error,
"cannot add values to non-existent optional field");
return false;
},
[this, &x](present_field fld) {
auto [iter, added] = fld.parent->emplace(fld.name, std::move(x));
if (!added) {
emplace_error(sec::runtime_error,
"field already defined: " + to_string(fld.name));
return false;
}
if (!fld.type.empty()) {
std::string key;
key += '@';
key.insert(key.end(), fld.name.begin(), fld.name.end());
key += "-type";
if (fld.parent->contains(key)) {
emplace_error(sec::runtime_error,
"type of variant field already defined.");
return false;
}
put(*fld.parent, key, fld.type);
}
return true;
},
[&x](config_value::list* ls) {
ls->emplace_back(std::move(x));
return true;
});
return visit(f, st_.top());
}
} // 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. *
******************************************************************************/
#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