Unverified Commit 3f59e8d4 authored by Noir's avatar Noir Committed by GitHub

Merge pull request #1192

Add new get_as and get_or utility functions
parents f5c450a6 3e1ae2ba
......@@ -35,7 +35,8 @@
namespace caf {
/// Deserializes objects from sequence of bytes.
/// Deserializes C++ objects from sequence of bytes. Does not perform run-time
/// type checks.
class CAF_CORE_EXPORT binary_deserializer
: public load_inspector_base<binary_deserializer> {
public:
......@@ -112,7 +113,7 @@ public:
bool fetch_next_object_type(type_id_t& type) noexcept;
constexpr bool begin_object(string_view) noexcept {
constexpr bool begin_object(type_id_t, string_view) noexcept {
return true;
}
......
......@@ -33,7 +33,10 @@
namespace caf {
/// Serializes objects into a sequence of bytes.
/// Serializes C++ objects into a sequence of bytes.
/// @note The binary data format may change between CAF versions and does not
/// perform any type checking at run-time. Thus the output of this
/// serializer is unsuitable for persistence layers.
class CAF_CORE_EXPORT binary_serializer
: public save_inspector_base<binary_serializer> {
public:
......@@ -95,9 +98,7 @@ public:
// -- interface functions ----------------------------------------------------
bool inject_next_object_type(type_id_t type);
constexpr bool begin_object(string_view) {
constexpr bool begin_object(type_id_t, string_view) noexcept {
return true;
}
......
This diff is collapsed.
......@@ -23,6 +23,7 @@
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include <memory>
#include <stack>
#include <vector>
......@@ -85,6 +86,10 @@ public:
~config_value_reader() override;
config_value_reader(const config_value_reader&) = delete;
config_value_reader& operator=(const config_value_reader&) = delete;
// -- stack access -----------------------------------------------------------
value_type& top() {
......@@ -99,7 +104,7 @@ public:
bool fetch_next_object_type(type_id_t& type) override;
bool begin_object(string_view name) override;
bool begin_object(type_id_t type, string_view name) override;
bool end_object() override;
......@@ -166,9 +171,14 @@ public:
bool value(span<byte> x) override;
private:
// Sets `type` according to the `@type` field in `obj` or to the type ID of
// `settings` as fallback if no such field exists.
bool fetch_object_type(const settings* obj, type_id_t& type);
stack_type st_;
// Stores on-the-fly converted values.
std::vector<std::unique_ptr<config_value>> scratch_space_;
};
} // namespace caf
......@@ -68,9 +68,7 @@ public:
// -- interface functions ----------------------------------------------------
bool inject_next_object_type(type_id_t type) override;
bool begin_object(string_view name) override;
bool begin_object(type_id_t type, string_view name) override;
bool end_object() override;
......@@ -140,7 +138,6 @@ private:
bool push(config_value&& x);
stack_type st_;
string_view type_hint_;
};
} // namespace caf
......@@ -62,13 +62,15 @@ public:
// -- interface functions ----------------------------------------------------
/// Reads run-time-type information for the next object. Requires that the
/// @ref serializer provided this information via
/// @ref serializer::inject_next_object_type.
/// Reads run-time-type information for the next object if available.
virtual bool fetch_next_object_type(type_id_t& type) = 0;
/// Begins processing of an object.
virtual bool begin_object(string_view type) = 0;
/// Begins processing of an object, may perform a type check depending on the
/// data format.
/// @param type 16-bit ID for known types, @ref invalid_type_id otherwise.
/// @param pretty_class_name Either the output of @ref type_name_or_anonymous
/// or the optionally defined pretty name.
virtual bool begin_object(type_id_t type, string_view pretty_class_name) = 0;
/// Ends processing of an object.
virtual bool end_object() = 0;
......
......@@ -33,6 +33,13 @@ struct bounds_checker {
}
};
template <>
struct bounds_checker<int64_t, false> {
static constexpr bool check(int64_t) noexcept {
return true;
}
};
template <class To>
struct bounds_checker<To, true> {
static constexpr bool check(int64_t x) noexcept {
......
......@@ -222,8 +222,15 @@ template <class First, class Second, size_t N>
void parse_element(string_parser_state& ps, std::pair<First, Second>& kvp,
const char (&char_blacklist)[N]);
template <class T>
enable_if_tt<is_iterable<T>> parse(string_parser_state& ps, T& xs) {
struct require_opening_char_t {};
constexpr auto require_opening_char = require_opening_char_t{};
struct allow_omitting_opening_char_t {};
constexpr auto allow_omitting_opening_char = allow_omitting_opening_char_t{};
template <class T, class Policy = allow_omitting_opening_char_t>
enable_if_tt<is_iterable<T>>
parse(string_parser_state& ps, T& xs, Policy = {}) {
using value_type = deconst_kvp_t<typename T::value_type>;
static constexpr auto is_map_type = is_pair<value_type>::value;
static constexpr auto opening_char = is_map_type ? '{' : '[';
......@@ -252,19 +259,23 @@ enable_if_tt<is_iterable<T>> parse(string_parser_state& ps, T& xs) {
}
return;
}
// An empty string simply results in an empty list/map.
if (ps.at_end())
return;
// List/map without [] or {}.
do {
char char_blacklist[] = {',', '\0'};
value_type tmp;
parse_element(ps, tmp, char_blacklist);
if (ps.code > pec::trailing_character)
if constexpr (std::is_same<Policy, require_opening_char_t>::value) {
ps.code = pec::unexpected_character;
} else {
// An empty string simply results in an empty list/map.
if (ps.at_end())
return;
*out++ = std::move(tmp);
} while (ps.consume(','));
ps.code = ps.at_end() ? pec::success : pec::trailing_character;
// List/map without [] or {}.
do {
char char_blacklist[] = {',', '\0'};
value_type tmp;
parse_element(ps, tmp, char_blacklist);
if (ps.code > pec::trailing_character)
return;
*out++ = std::move(tmp);
} while (ps.consume(','));
ps.code = ps.at_end() ? pec::success : pec::trailing_character;
}
}
template <class T>
......@@ -306,4 +317,11 @@ auto parse(string_view str, T& x) {
return parse_result(ps, str);
}
template <class T, class Policy>
auto parse(string_view str, T& x, Policy policy) {
string_parser_state ps{str.begin(), str.end()};
parse(ps, x, policy);
return parse_result(ps, str);
}
} // namespace caf::detail
......@@ -18,6 +18,7 @@
#pragma once
#include "caf/none.hpp"
#include "caf/string_view.hpp"
#include <chrono>
......@@ -60,6 +61,13 @@ void print_escaped(Buffer& buf, string_view str) {
buf.push_back('"');
}
template <class Buffer>
void print(Buffer& buf, none_t) {
using namespace caf::literals;
auto str = "null"_sv;
buf.insert(buf.end(), str.begin(), str.end());
}
template <class Buffer>
void print(Buffer& buf, bool x) {
using namespace caf::literals;
......
......@@ -32,9 +32,7 @@ public:
size_t result = 0;
bool inject_next_object_type(type_id_t type) override;
bool begin_object(string_view) override;
bool begin_object(type_id_t, string_view) override;
bool end_object() override;
......
......@@ -58,7 +58,7 @@ public:
// -- serializer interface ---------------------------------------------------
bool begin_object(string_view name);
bool begin_object(type_id_t, string_view name);
bool end_object();
......
......@@ -330,14 +330,6 @@ private:
map_type xs_;
};
// -- free functions -----------------------------------------------------------
// @relates dictionary
template <class T>
std::string to_string(const dictionary<T>& xs) {
return deep_to_string(xs.container());
}
// -- operators ----------------------------------------------------------------
// @relates dictionary
......@@ -376,10 +368,4 @@ bool operator>=(const dictionary<T>& xs, const dictionary<T>& ys) {
return xs.container() >= ys.container();
}
// @relates dictionary
template <class T>
std::ostream& operator<<(std::ostream& out, const dictionary<T>& xs) {
return out << to_string(xs);
}
} // namespace caf
......@@ -53,7 +53,7 @@ public:
return false;
}
constexpr bool begin_object(string_view) {
constexpr bool begin_object(type_id_t, string_view) {
return true;
}
......
......@@ -49,7 +49,7 @@ public:
return false;
}
constexpr bool begin_object(string_view) {
constexpr bool begin_object(type_id_t, string_view) {
return true;
}
......
......@@ -275,6 +275,7 @@ public:
template <class Inspector, class LoadCallback>
struct object_with_load_callback_t {
type_id_t object_type;
string_view object_name;
Inspector* f;
LoadCallback load_callback;
......@@ -282,7 +283,7 @@ public:
template <class... Fields>
bool fields(Fields&&... fs) {
using load_callback_result = decltype(load_callback());
if (!(f->begin_object(object_name) && (fs(*f) && ...)))
if (!(f->begin_object(object_type, object_name) && (fs(*f) && ...)))
return false;
if constexpr (std::is_same<load_callback_result, bool>::value) {
if (!load_callback()) {
......@@ -299,7 +300,7 @@ public:
}
auto pretty_name(string_view name) && {
return object_t{name, f};
return object_t{object_type, name, f};
}
template <class F>
......@@ -310,16 +311,19 @@ public:
template <class Inspector>
struct object_t {
type_id_t object_type;
string_view object_name;
Inspector* f;
template <class... Fields>
bool fields(Fields&&... fs) {
return f->begin_object(object_name) && (fs(*f) && ...) && f->end_object();
return f->begin_object(object_type, object_name) //
&& (fs(*f) && ...) //
&& f->end_object();
}
auto pretty_name(string_view name) && {
return object_t{name, f};
return object_t{object_type, name, f};
}
template <class F>
......@@ -330,6 +334,7 @@ public:
template <class F>
auto on_load(F fun) && {
return object_with_load_callback_t<Inspector, F>{
object_type,
object_name,
f,
std::move(fun),
......
......@@ -38,7 +38,8 @@ public:
template <class T>
constexpr auto object(T&) noexcept {
return super::object_t<Subtype>{type_name_or_anonymous<T>(), dptr()};
return super::object_t<Subtype>{type_id_or_invalid<T>(),
type_name_or_anonymous<T>(), dptr()};
}
template <class T>
......
......@@ -171,6 +171,7 @@ public:
template <class Inspector, class SaveCallback>
struct object_with_save_callback_t {
type_id_t object_type;
string_view object_name;
Inspector* f;
SaveCallback save_callback;
......@@ -178,7 +179,7 @@ public:
template <class... Fields>
bool fields(Fields&&... fs) {
using save_callback_result = decltype(save_callback());
if (!(f->begin_object(object_name) && (fs(*f) && ...)))
if (!(f->begin_object(object_type, object_name) && (fs(*f) && ...)))
return false;
if constexpr (std::is_same<save_callback_result, bool>::value) {
if (!save_callback()) {
......@@ -206,16 +207,19 @@ public:
template <class Inspector>
struct object_t {
type_id_t object_type;
string_view object_name;
Inspector* f;
template <class... Fields>
bool fields(Fields&&... fs) {
return f->begin_object(object_name) && (fs(*f) && ...) && f->end_object();
return f->begin_object(object_type, object_name) //
&& (fs(*f) && ...) //
&& f->end_object();
}
auto pretty_name(string_view name) && {
return object_t{name, f};
return object_t{object_type, name, f};
}
template <class F>
......@@ -226,6 +230,7 @@ public:
template <class F>
auto on_save(F fun) && {
return object_with_save_callback_t<Inspector, F>{
object_type,
object_name,
f,
std::move(fun),
......
......@@ -34,7 +34,8 @@ public:
template <class T>
constexpr auto object(T&) noexcept {
return super::object_t<Subtype>{type_name_or_anonymous<T>(), dptr()};
return super::object_t<Subtype>{type_id_or_invalid<T>(),
type_name_or_anonymous<T>(), dptr()};
}
template <class T>
......
......@@ -164,6 +164,12 @@ enum class sec : uint8_t {
conversion_failed,
/// A network connection was closed by the remote side.
connection_closed,
/// An operation failed because run-time type information diverged from the
/// expected type.
type_clash,
/// An operation failed because the callee does not implement this
/// functionality.
unsupported_operation,
};
/// @relates sec
......
......@@ -66,15 +66,10 @@ public:
// -- interface functions ----------------------------------------------------
/// Injects run-time-type information for the *next* object, i.e., causes the
/// next call to `begin_object` to write additional meta information. Allows a
/// @ref deserializer to retrieve the type for the next object via
/// @ref deserializer::fetch_next_object_type.
virtual bool inject_next_object_type(type_id_t type) = 0;
/// Begins processing of an object. Saves the type information
/// to the underlying storage.
virtual bool begin_object(string_view name) = 0;
/// Begins processing of an object. May save the type information to the
/// underlying storage to allow a @ref deserializer to retrieve and check the
/// type information for data formats that provide deserialization.
virtual bool begin_object(type_id_t type, string_view name) = 0;
/// Ends processing of an object.
virtual bool end_object() = 0;
......
......@@ -33,6 +33,9 @@ namespace caf {
/// @relates config_value
using settings = dictionary<config_value>;
/// @relates config_value
CAF_CORE_EXPORT std::string to_string(const settings& xs);
/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
CAF_CORE_EXPORT const config_value*
......
......@@ -108,6 +108,15 @@ string_view type_name_or_anonymous() {
return "anonymous";
}
/// Returns `type_id_v<T>` if available, `invalid_type_id` otherwise.
template <class T>
type_id_t type_id_or_invalid() {
if constexpr (detail::is_complete<type_id<T>>)
return type_id<T>::value;
else
return invalid_type_id;
}
/// Returns the type name of given `type` or an empty string if `type` is an
/// invalid ID.
CAF_CORE_EXPORT string_view query_type_name(type_id_t type);
......
......@@ -88,6 +88,10 @@ public:
return begin() + size();
}
/// Returns the number of bytes that a buffer needs to allocate for storing a
/// type-erased tuple for the element types stored in this list.
size_t data_size() const noexcept;
private:
pointer data_;
};
......@@ -110,3 +114,22 @@ constexpr type_id_list make_type_id_list() {
CAF_CORE_EXPORT std::string to_string(type_id_list xs);
} // namespace caf
namespace caf::detail {
template <class F>
struct argument_type_id_list_factory;
template <class R, class... Ts>
struct argument_type_id_list_factory<R(Ts...)> {
static type_id_list make() {
return make_type_id_list<Ts...>();
}
};
template <class F>
type_id_list make_argument_type_id_list() {
return argument_type_id_list_factory<F>::make();
}
} // namespace caf::detail
......@@ -31,6 +31,7 @@
#include "caf/make_actor.hpp"
#include "caf/replies_to.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/type_id_list.hpp"
#include "caf/typed_actor_view_base.hpp"
#include "caf/typed_behavior.hpp"
#include "caf/typed_response_promise.hpp"
......@@ -246,6 +247,10 @@ public:
x.ptr_.reset();
}
static std::array<type_id_list, sizeof...(Sigs)> allowed_inputs() {
return {{detail::make_argument_type_id_list<Sigs>()...}};
}
/// @endcond
private:
......
......@@ -35,19 +35,23 @@ namespace {
template <class T>
bool int_value(binary_deserializer& source, T& x) {
auto tmp = std::make_unsigned_t<T>{};
if (!source.value(as_writable_bytes(make_span(&tmp, 1))))
if (source.value(as_writable_bytes(make_span(&tmp, 1)))) {
x = static_cast<T>(detail::from_network_order(tmp));
return true;
} else {
return false;
x = static_cast<T>(detail::from_network_order(tmp));
return true;
}
}
template <class T>
bool float_value(binary_deserializer& source, T& x) {
auto tmp = typename detail::ieee_754_trait<T>::packed_type{};
if (!int_value(source, tmp))
if (int_value(source, tmp)) {
x = detail::unpack754(tmp);
return true;
} else {
return false;
x = detail::unpack754(tmp);
return true;
}
}
// Does not perform any range checks.
......@@ -67,7 +71,10 @@ binary_deserializer::binary_deserializer(actor_system& sys) noexcept
}
bool binary_deserializer::fetch_next_object_type(type_id_t& type) noexcept {
return value(type);
type = invalid_type_id;
emplace_error(sec::unsupported_operation,
"the default binary format does not embed type information");
return false;
}
bool binary_deserializer::begin_sequence(size_t& list_size) noexcept {
......
......@@ -51,10 +51,6 @@ void binary_serializer::skip(size_t num_bytes) {
write_pos_ += num_bytes;
}
bool binary_serializer::inject_next_object_type(type_id_t type) {
return value(type);
}
bool binary_serializer::begin_sequence(size_t list_size) {
// Use varbyte encoding to compress sequence size on the wire.
// For 64-bit values, the encoded representation cannot get larger than 10
......
This diff is collapsed.
......@@ -122,11 +122,12 @@ bool config_value_reader::fetch_next_object_type(type_id_t& type) {
return false;
},
[this, &type](const config_value* val) {
if (auto obj = get_if<settings>(val); obj == nullptr) {
emplace_error(sec::conversion_failed, "cannot read input as object");
return false;
auto tid = val->type_id();
if (tid != type_id_v<config_value::dictionary>) {
type = tid;
return true;
} else {
return fetch_object_type(obj, type);
return fetch_object_type(get_if<settings>(val), type);
}
},
[this](key_ptr) {
......@@ -146,11 +147,13 @@ bool config_value_reader::fetch_next_object_type(type_id_t& type) {
emplace_error(sec::runtime_error, "list index out of bounds");
return false;
}
if (auto obj = get_if<settings>(std::addressof(seq.current())); !obj) {
emplace_error(sec::conversion_failed, "cannot read input as object");
return false;
auto& val = seq.current();
auto tid = val.type_id();
if (tid != type_id_v<config_value::dictionary>) {
type = tid;
return true;
} else {
return fetch_object_type(obj, type);
return fetch_object_type(get_if<settings>(&val), type);
}
},
[this](associative_array&) {
......@@ -162,7 +165,7 @@ bool config_value_reader::fetch_next_object_type(type_id_t& type) {
}
}
bool config_value_reader::begin_object(string_view) {
bool config_value_reader::begin_object(type_id_t type, string_view) {
if (st_.empty()) {
emplace_error(sec::runtime_error,
"tried to read multiple objects from the root object");
......@@ -176,10 +179,17 @@ bool config_value_reader::begin_object(string_view) {
},
[this](const config_value* val) {
if (auto obj = get_if<settings>(val)) {
// Morph into an object. This value gets "consumed" by
// begin_object/end_object.
// Unbox the dictionary.
st_.top() = obj;
return true;
} else if (auto dict = val->to_dictionary()) {
// Replace the actual config value on the stack with the on-the-fly
// converted dictionary.
auto ptr = std::make_unique<config_value>(std::move(*dict));
const settings* unboxed = std::addressof(get<settings>(*ptr));
st_.top() = unboxed;
scratch_space_.emplace_back(std::move(ptr));
return true;
} else {
emplace_error(sec::conversion_failed, "cannot read input as object");
return false;
......@@ -216,7 +226,27 @@ bool config_value_reader::begin_object(string_view) {
"fetch_next_object_type called inside associative array");
return false;
});
return visit(f, st_.top());
if (visit(f, st_.top())) {
// Perform a type check if type is a valid ID and the object contains an
// "@type" field.
if (type != invalid_type_id) {
CAF_ASSERT(holds_alternative<const settings*>(st_.top()));
auto obj = get<const settings*>(st_.top());
auto want = query_type_name(type);
if (auto i = obj->find("@type"); i != obj->end()) {
if (auto got = get_if<std::string>(std::addressof(i->second))) {
if (want != *got) {
emplace_error(sec::type_clash, "expected type: " + to_string(want),
"found type: " + *got);
return false;
}
}
}
}
return true;
} else {
return false;
}
}
bool config_value_reader::end_object() {
......@@ -563,15 +593,15 @@ bool config_value_reader::value(span<byte> bytes) {
bool config_value_reader::fetch_object_type(const settings* obj,
type_id_t& type) {
if (auto str = get_if<std::string>(obj, "@type"); str == nullptr) {
emplace_error(sec::runtime_error,
"cannot fetch object type: no '@type' entry found");
return false;
} else if (auto id = query_type_id(*str); id == invalid_type_id) {
emplace_error(sec::runtime_error, "no such type: " + *str);
return false;
} else {
// fetch_next_object_type only calls this function
type = type_id_v<config_value::dictionary>;
return true;
} else if (auto id = query_type_id(*str); id != invalid_type_id) {
type = id;
return true;
} else {
emplace_error(sec::runtime_error, "unknown type: " + *str);
return false;
}
}
......
......@@ -66,18 +66,7 @@ config_value_writer::~config_value_writer() {
// -- interface functions ------------------------------------------------------
bool config_value_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 config_value_writer::begin_object(string_view) {
bool config_value_writer::begin_object(type_id_t type, string_view) {
CHECK_NOT_EMPTY();
auto f = detail::make_overload(
[this](config_value* x) {
......@@ -118,10 +107,8 @@ bool config_value_writer::begin_object(string_view) {
});
if (!visit(f, st_.top()))
return false;
if (!type_hint_.empty()) {
put(*get<settings*>(st_.top()), "@type", type_hint_);
type_hint_ = string_view{};
}
if (type != invalid_type_id)
put(*get<settings*>(st_.top()), "@type", query_type_name(type));
return true;
}
......
......@@ -26,11 +26,7 @@
namespace caf::detail {
bool serialized_size_inspector::inject_next_object_type(type_id_t type) {
return value(type);
}
bool serialized_size_inspector::begin_object(string_view) {
bool serialized_size_inspector::begin_object(type_id_t, string_view) {
return true;
}
......
......@@ -49,7 +49,7 @@ void escape(std::string& result, char c) {
namespace caf::detail {
bool stringification_inspector::begin_object(string_view name) {
bool stringification_inspector::begin_object(type_id_t, string_view name) {
sep();
if (name != "std::string") {
result_.insert(result_.end(), name.begin(), name.end());
......@@ -130,15 +130,13 @@ bool stringification_inspector::value(float x) {
bool stringification_inspector::value(double x) {
sep();
auto str = std::to_string(x);
result_ += str;
detail::print(result_, x);
return true;
}
bool stringification_inspector::value(long double x) {
sep();
auto str = std::to_string(x);
result_ += str;
detail::print(result_, x);
return true;
}
......
......@@ -59,7 +59,7 @@ template <class Deserializer>
bool load_data(Deserializer& source, message::data_ptr& data) {
// For machine-to-machine data formats, we prefix the type information.
if (!source.has_human_readable_format()) {
GUARDED(source.begin_object("message"));
GUARDED(source.begin_object(type_id_v<message>, "message"));
GUARDED(source.begin_field("types"));
size_t msg_size = 0;
GUARDED(source.begin_sequence(msg_size));
......@@ -159,8 +159,6 @@ bool load_data(Deserializer& source, message::data_ptr& data) {
using unique_void_ptr = std::unique_ptr<void, free_t>;
auto msg_size = size_t{0};
std::vector<object_ptr> objects;
GUARDED(source.begin_object("message"));
GUARDED(source.begin_field("values"));
GUARDED(source.begin_sequence(msg_size));
if (msg_size > 0) {
// Deserialize message elements individually.
......@@ -185,7 +183,7 @@ bool load_data(Deserializer& source, message::data_ptr& data) {
STOP(sec::unknown_type);
}
}
GUARDED(source.end_field() && source.end_sequence());
GUARDED(source.end_sequence());
// Merge elements into a single message data object.
intrusive_ptr<detail::message_data> ptr;
if (auto vptr = malloc(sizeof(detail::message_data) + data_size)) {
......@@ -203,13 +201,11 @@ bool load_data(Deserializer& source, message::data_ptr& data) {
pos += x.meta->padded_size;
}
data.reset(ptr.release(), false);
return source.end_object();
return true;
} else {
data.reset();
return source.end_sequence();
}
return source.end_sequence() //
&& source.end_field() //
&& source.end_object();
}
} // namespace
......@@ -242,18 +238,18 @@ save_data(Serializer& sink, const message::data_ptr& data) {
if (!sink.has_human_readable_format()) {
if (data == nullptr) {
// Short-circuit empty tuples.
return sink.begin_object("message") //
&& sink.begin_field("types") //
&& sink.begin_sequence(0) //
&& sink.end_sequence() //
&& sink.end_field() //
&& sink.begin_field("values") //
&& sink.begin_tuple(0) //
&& sink.end_tuple() //
&& sink.end_field() //
return sink.begin_object(type_id_v<message>, "message") //
&& sink.begin_field("types") //
&& sink.begin_sequence(0) //
&& sink.end_sequence() //
&& sink.end_field() //
&& sink.begin_field("values") //
&& sink.begin_tuple(0) //
&& sink.end_tuple() //
&& sink.end_field() //
&& sink.end_object();
}
GUARDED(sink.begin_object("message"));
GUARDED(sink.begin_object(type_id_v<message>, "message"));
auto type_ids = data->types();
// Write type information.
GUARDED(sink.begin_field("types") && sink.begin_sequence(type_ids.size()));
......@@ -274,25 +270,17 @@ save_data(Serializer& sink, const message::data_ptr& data) {
// dynamically-typed objects.
if (data == nullptr) {
// Short-circuit empty tuples.
return sink.begin_object("message") //
&& sink.begin_field("values") //
&& sink.begin_sequence(0) //
&& sink.end_sequence() //
&& sink.end_field() //
&& sink.end_object();
return sink.begin_sequence(0) && sink.end_sequence();
}
auto type_ids = data->types();
GUARDED(sink.begin_object("message") //
&& sink.begin_field("values") //
&& sink.begin_sequence(type_ids.size()));
GUARDED(sink.begin_sequence(type_ids.size()));
auto storage = data->storage();
for (auto id : type_ids) {
auto& meta = gmos[id];
GUARDED(sink.inject_next_object_type(id) //
&& save(meta, sink, storage));
GUARDED(save(meta, sink, storage));
storage += meta.padded_size;
}
return sink.end_sequence() && sink.end_field() && sink.end_object();
return sink.end_sequence();
}
} // namespace
......
......@@ -142,6 +142,10 @@ std::string to_string(sec x) {
return "conversion_failed";
case sec::connection_closed:
return "connection_closed";
case sec::type_clash:
return "type_clash";
case sec::unsupported_operation:
return "unsupported_operation";
};
}
......@@ -335,6 +339,12 @@ bool from_string(string_view in, sec& out) {
} else if (in == "connection_closed") {
out = sec::connection_closed;
return true;
} else if (in == "type_clash") {
out = sec::type_clash;
return true;
} else if (in == "unsupported_operation") {
out = sec::unsupported_operation;
return true;
} else {
return false;
}
......@@ -409,6 +419,8 @@ bool from_integer(std::underlying_type_t<sec> in,
case sec::load_callback_failed:
case sec::conversion_failed:
case sec::connection_closed:
case sec::type_clash:
case sec::unsupported_operation:
out = result;
return true;
};
......
......@@ -22,6 +22,8 @@
namespace caf {
// note: to_string is implemented in config_value.cpp
const config_value* get_if(const settings* xs, string_view name) {
// Access the key directly unless the user specified a dot-separated path.
auto pos = name.find('.');
......
......@@ -41,22 +41,22 @@ namespace {
template <class Serializer>
bool serialize_impl(Serializer& sink, const tracing_data_ptr& x) {
if (!x) {
return sink.begin_object("tracing_data") //
&& sink.begin_field("value", false) //
&& sink.end_field() //
return sink.begin_object(invalid_type_id, "tracing_data") //
&& sink.begin_field("value", false) //
&& sink.end_field() //
&& sink.end_object();
}
return sink.begin_object("tracing_data") //
&& sink.begin_field("value", true) //
&& x->serialize(sink) //
&& sink.end_field() //
return sink.begin_object(invalid_type_id, "tracing_data") //
&& sink.begin_field("value", true) //
&& x->serialize(sink) //
&& sink.end_field() //
&& sink.end_object();
}
template <class Deserializer>
bool deserialize_impl(Deserializer& source, tracing_data_ptr& x) {
bool is_present = false;
if (!source.begin_object("tracing_data")
if (!source.begin_object(invalid_type_id, "tracing_data")
|| !source.begin_field("value", is_present))
return false;
if (!is_present)
......
......@@ -22,6 +22,15 @@
namespace caf {
size_t type_id_list::data_size() const noexcept {
auto result = size_t{0};
for (auto type : *this) {
auto meta_obj = detail::global_meta_object(type);
result += meta_obj->padded_size;
}
return result;
}
std::string to_string(type_id_list xs) {
if (!xs || xs.size() == 0)
return "[]";
......
This diff is collapsed.
......@@ -83,7 +83,7 @@ struct i32_wrapper {
template <class Inspector>
friend bool inspect(Inspector& f, i32_wrapper& x) {
return f.object(x).fields(f.field("value", x.value));
return f.apply(x.value);
}
};
......@@ -97,19 +97,27 @@ struct i64_wrapper {
++instances;
}
explicit i64_wrapper(int64_t val) : value(val) {
++instances;
}
~i64_wrapper() {
--instances;
}
template <class Inspector>
friend bool inspect(Inspector& f, i64_wrapper& x) {
return f.object(x).fields(f.field("value", x.value));
return f.apply(x.value);
}
};
struct my_request {
int32_t a;
int32_t b;
int32_t a = 0;
int32_t b = 0;
my_request() = default;
my_request(int a, int b) : a(a), b(b) {
// nop
}
};
[[maybe_unused]] inline bool operator==(const my_request& x,
......
......@@ -145,7 +145,7 @@ const auto conf0_log = make_log(
"key: foo=bar",
"{",
"key: foo",
"value (string): \"bar\"",
"value (string): bar",
"}",
"key: 1group",
"{",
......@@ -162,7 +162,7 @@ const auto conf0_log = make_log(
"key: padding",
"value (integer): 10",
"key: file-name",
"value (string): \"foobar.ini\"",
"value (string): foobar.ini",
"}",
"key: scheduler",
"{",
......@@ -184,7 +184,7 @@ const auto conf0_log = make_log(
"value (integer): 23",
"value (integer): 2",
"value (integer): 4",
"value (string): \"abc\"",
"value (string): abc",
"]",
"key: some-map",
"{",
......@@ -193,7 +193,7 @@ const auto conf0_log = make_log(
"key: entry2",
"value (integer): 23",
"key: entry3",
"value (string): \"abc\"",
"value (string): abc",
"}",
"key: middleman",
"{",
......
......@@ -58,7 +58,7 @@ struct testee : deserializer {
return false;
}
bool begin_object(string_view object_name) override {
bool begin_object(type_id_t, string_view object_name) override {
new_line();
indent += 2;
log += "begin object ";
......
......@@ -49,15 +49,7 @@ struct testee : serializer {
log.insert(log.end(), indent, ' ');
}
bool inject_next_object_type(type_id_t type) override {
new_line();
log += "next object type: ";
auto tn = detail::global_meta_object(type)->type_name;
log.insert(log.end(), tn.begin(), tn.end());
return true;
}
bool begin_object(string_view object_name) override {
bool begin_object(type_id_t, string_view object_name) override {
new_line();
indent += 2;
log += "begin object ";
......@@ -734,18 +726,11 @@ end object)_");
f.set_has_human_readable_format(true);
CAF_CHECK(inspect(f, x));
CAF_CHECK_EQUAL(f.log, R"_(
begin object message
begin field values
begin sequence of size 3
next object type: int32_t
int32_t value
next object type: std::string
std::string value
next object type: double
double value
end sequence
end field
end object)_");
begin sequence of size 3
int32_t value
std::string value
double value
end sequence)_");
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment