Commit e2981877 authored by Dominik Charousset's avatar Dominik Charousset

Add apply functions to inspectors, add docs

parent 5e8bd93a
...@@ -127,6 +127,12 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -127,6 +127,12 @@ is based on [Keep a Changelog](https://keepachangelog.com).
*types*, but did not enforce it because the name was only used for logging. *types*, but did not enforce it because the name was only used for logging.
Since the new metrics use this name for filtering now, we enforce static names Since the new metrics use this name for filtering now, we enforce static names
in order to help avoid hard-to-find issues with the filtering mechanism. in order to help avoid hard-to-find issues with the filtering mechanism.
- The type inspection API received a complete overhaul. The new DSL for writing
`inspect` functions exposes the entire structure of an object to CAF. This
enables inspectors to read and write a wider range of data formats. In
particular human-readable, structured data such as configuration files, JSON,
XML, etc. The inspection API received too many changes to list them here.
Please refer to the manual section on type inspection instead.
### Removed ### Removed
......
...@@ -94,14 +94,14 @@ void caf_main(actor_system& sys) { ...@@ -94,14 +94,14 @@ void caf_main(actor_system& sys) {
binary_serializer::container_type buf; binary_serializer::container_type buf;
// write f1 to buffer // write f1 to buffer
binary_serializer sink{sys, buf}; binary_serializer sink{sys, buf};
if (!inspect_object(sink, f1)) { if (!sink.apply_object(f1)) {
std::cerr << "*** failed to serialize foo2: " << to_string(sink.get_error()) std::cerr << "*** failed to serialize foo2: " << to_string(sink.get_error())
<< '\n'; << '\n';
return; return;
} }
// read f2 back from buffer // read f2 back from buffer
binary_deserializer source{sys, buf}; binary_deserializer source{sys, buf};
if (!inspect_object(source, f2)) { if (!source.apply_object(f2)) {
std::cerr << "*** failed to deserialize foo2: " std::cerr << "*** failed to deserialize foo2: "
<< to_string(source.get_error()) << '\n'; << to_string(source.get_error()) << '\n';
return; return;
......
...@@ -50,29 +50,28 @@ void copy_construct(void* ptr, const void* src) { ...@@ -50,29 +50,28 @@ void copy_construct(void* ptr, const void* src) {
template <class T> template <class T>
bool save_binary(binary_serializer& sink, const void* ptr) { bool save_binary(binary_serializer& sink, const void* ptr) {
return inspect_object(sink, as_mutable_ref(*static_cast<const T*>(ptr))); return sink.apply_object(*static_cast<const T*>(ptr));
} }
template <class T> template <class T>
bool load_binary(binary_deserializer& source, void* ptr) { bool load_binary(binary_deserializer& source, void* ptr) {
return inspect_object(source, *static_cast<T*>(ptr)); return source.apply_object(*static_cast<T*>(ptr));
} }
template <class T> template <class T>
bool save(serializer& sink, const void* ptr) { bool save(serializer& sink, const void* ptr) {
return inspect_object(sink, as_mutable_ref(*static_cast<const T*>(ptr))); return sink.apply_object(*static_cast<const T*>(ptr));
} }
template <class T> template <class T>
bool load(deserializer& source, void* ptr) { bool load(deserializer& source, void* ptr) {
return inspect_object(source, *static_cast<T*>(ptr)); return source.apply_object(*static_cast<T*>(ptr));
} }
template <class T> template <class T>
void stringify(std::string& buf, const void* ptr) { void stringify(std::string& buf, const void* ptr) {
stringification_inspector f{buf}; stringification_inspector f{buf};
auto unused auto unused = f.apply_object(*static_cast<const T*>(ptr));
= inspect_object(f, detail::as_mutable_ref(*static_cast<const T*>(ptr)));
static_cast<void>(unused); static_cast<void>(unused);
} }
......
...@@ -292,6 +292,7 @@ void parse_element(string_parser_state& ps, std::pair<First, Second>& kvp, ...@@ -292,6 +292,7 @@ void parse_element(string_parser_state& ps, std::pair<First, Second>& kvp,
// -- convenience functions ---------------------------------------------------- // -- convenience functions ----------------------------------------------------
CAF_CORE_EXPORT
error parse_result(const string_parser_state& ps, string_view input); error parse_result(const string_parser_state& ps, string_view input);
template <class T> template <class T>
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
namespace caf::detail { namespace caf::detail {
CAF_CORE_EXPORT
size_t print_timestamp(char* buf, size_t buf_size, time_t ts, size_t ms); size_t print_timestamp(char* buf, size_t buf_size, time_t ts, size_t ms);
template <class Buffer> template <class Buffer>
......
...@@ -96,16 +96,16 @@ public: ...@@ -96,16 +96,16 @@ public:
template <class T> template <class T>
size_t serialized_size(const T& x) { size_t serialized_size(const T& x) {
serialized_size_inspector f; serialized_size_inspector f;
auto inspection_res = inspect_object(f, detail::as_mutable_ref(x)); auto unused = f.apply_object(x);
static_cast<void>(inspection_res); // Always true. static_cast<void>(unused); // Always true.
return f.result; return f.result;
} }
template <class T> template <class T>
size_t serialized_size(actor_system& sys, const T& x) { size_t serialized_size(actor_system& sys, const T& x) {
serialized_size_inspector f{sys}; serialized_size_inspector f{sys};
auto inspection_res = inspect_object(f, detail::as_mutable_ref(x)); auto unused = f.apply_object(x);
static_cast<void>(inspection_res); // Always true. static_cast<void>(unused); // Always true.
return f.result; return f.result;
} }
......
...@@ -161,7 +161,13 @@ public: ...@@ -161,7 +161,13 @@ public:
bool> bool>
value(const T& x) { value(const T& x) {
auto str = to_string(x); auto str = to_string(x);
if constexpr (std::is_convertible<decltype(str), const char*>::value) {
const char* cstr = str;
sep();
result_ += cstr;
} else {
append(str); append(str);
}
return true; return true;
} }
......
...@@ -156,9 +156,8 @@ public: ...@@ -156,9 +156,8 @@ public:
static T compute(Ts&&... xs) noexcept { static T compute(Ts&&... xs) noexcept {
using detail::as_mutable_ref; using detail::as_mutable_ref;
fnv f; fnv f;
auto inspect_result = (inspect_object(f, as_mutable_ref(xs)) && ...); auto unused = f.apply_objects(xs...);
// Discard inspection result: always true. static_cast<void>(unused); // Always true.
static_cast<void>(inspect_result);
return f.result; return f.result;
} }
......
...@@ -70,7 +70,7 @@ bool load_value(Inspector& f, T& x, inspector_access_type::specialization) { ...@@ -70,7 +70,7 @@ bool load_value(Inspector& f, T& x, inspector_access_type::specialization) {
} }
template <class Inspector, class T> template <class Inspector, class T>
bool load_object(Inspector& f, T& x, inspector_access_type::inspect_value) { bool load_value(Inspector& f, T& x, inspector_access_type::inspect_value) {
return inspect_value(f, x); return inspect_value(f, x);
} }
...@@ -477,30 +477,6 @@ struct default_inspector_access : inspector_access_base<T> { ...@@ -477,30 +477,6 @@ struct default_inspector_access : inspector_access_base<T> {
template <class T> template <class T>
struct inspector_access; struct inspector_access;
/// Inspects `x` using the inspector `f`.
template <class Inspector, class T>
[[nodiscard]] bool inspect_object(Inspector& f, T& x) {
constexpr auto token = inspect_object_access_type<Inspector, T>();
if constexpr (Inspector::is_loading)
return detail::load_object(f, x, token);
else
return detail::save_object(f, x, token);
}
/// Inspects `x` using the inspector `f`.
template <class Inspector, class T>
[[nodiscard]] bool inspect_object(Inspector& f, const T& x) {
static_assert(!Inspector::is_loading);
constexpr auto token = inspect_object_access_type<Inspector, T>();
return detail::save_object(f, detail::as_mutable_ref(x), token);
}
/// Inspects all `xs` using the inspector `f`.
template <class Inspector, class... Ts>
[[nodiscard]] bool inspect_objects(Inspector& f, Ts&... xs) {
return (inspect_object(f, xs) && ...);
}
// -- inspection support for optional values ----------------------------------- // -- inspection support for optional values -----------------------------------
template <class T> template <class T>
......
...@@ -35,6 +35,10 @@ namespace caf { ...@@ -35,6 +35,10 @@ namespace caf {
/// for the DSL. /// for the DSL.
class CAF_CORE_EXPORT load_inspector { class CAF_CORE_EXPORT load_inspector {
public: public:
// -- member types -----------------------------------------------------------
using result_type = bool;
// -- constants -------------------------------------------------------------- // -- constants --------------------------------------------------------------
/// Convenience constant to indicate success of a processing step. /// Convenience constant to indicate success of a processing step.
...@@ -47,14 +51,6 @@ public: ...@@ -47,14 +51,6 @@ public:
/// Enables dispatching on the inspector type. /// Enables dispatching on the inspector type.
static constexpr bool is_loading = true; static constexpr bool is_loading = true;
// -- legacy API -------------------------------------------------------------
static constexpr bool reads_state = false;
static constexpr bool writes_state = true;
using result_type = bool;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
virtual ~load_inspector(); virtual ~load_inspector();
......
...@@ -39,6 +39,18 @@ public: ...@@ -39,6 +39,18 @@ public:
// -- dispatching to load/load functions ------------------------------------- // -- dispatching to load/load functions -------------------------------------
template <class T>
[[nodiscard]] bool apply_object(T& x) {
static_assert(!std::is_const<T>::value);
constexpr auto token = inspect_object_access_type<Subtype, T>();
return detail::load_object(dref(), x, token);
}
template <class... Ts>
[[nodiscard]] bool apply_objects(Ts&... xs) {
return (apply_object(xs) && ...);
}
template <class T> template <class T>
bool apply_value(T& x) { bool apply_value(T& x) {
return detail::load_value(dref(), x); return detail::load_value(dref(), x);
......
...@@ -35,6 +35,10 @@ namespace caf { ...@@ -35,6 +35,10 @@ namespace caf {
/// for the DSL. /// for the DSL.
class CAF_CORE_EXPORT save_inspector { class CAF_CORE_EXPORT save_inspector {
public: public:
// -- member types -----------------------------------------------------------
using result_type = bool;
// -- constants -------------------------------------------------------------- // -- constants --------------------------------------------------------------
/// Convenience constant to indicate success of a processing step. /// Convenience constant to indicate success of a processing step.
...@@ -47,14 +51,6 @@ public: ...@@ -47,14 +51,6 @@ public:
/// Enables dispatching on the inspector type. /// Enables dispatching on the inspector type.
static constexpr bool is_loading = false; static constexpr bool is_loading = false;
// -- legacy API -------------------------------------------------------------
static constexpr bool reads_state = true;
static constexpr bool writes_state = false;
using result_type = bool;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
virtual ~save_inspector(); virtual ~save_inspector();
......
...@@ -40,12 +40,29 @@ public: ...@@ -40,12 +40,29 @@ public:
// -- dispatching to load/save functions ------------------------------------- // -- dispatching to load/save functions -------------------------------------
template <class T> template <class T>
bool apply_value(T& x) { [[nodiscard]] bool apply_object(T& x) {
constexpr auto token = inspect_object_access_type<Subtype, T>();
return detail::save_object(dref(), x, token);
}
template <class T>
[[nodiscard]] bool apply_object(const T& x) {
constexpr auto token = inspect_object_access_type<Subtype, T>();
return detail::save_object(dref(), detail::as_mutable_ref(x), token);
}
template <class... Ts>
[[nodiscard]] bool apply_objects(Ts&... xs) {
return (apply_object(xs) && ...);
}
template <class T>
[[nodiscard]] bool apply_value(T& x) {
return detail::save_value(dref(), x); return detail::save_value(dref(), x);
} }
template <class Get, class Set> template <class Get, class Set>
bool apply_value(Get&& get, Set&&) { [[nodiscard]] bool apply_value(Get&& get, Set&&) {
auto&& x = get(); auto&& x = get();
return detail::save_value(dref(), x); return detail::save_value(dref(), x);
} }
......
...@@ -231,8 +231,8 @@ CAF_CORE_EXPORT type_id_t query_type_id(string_view name); ...@@ -231,8 +231,8 @@ CAF_CORE_EXPORT type_id_t query_type_id(string_view name);
return atom_text; \ return atom_text; \
} \ } \
template <class Inspector> \ template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \ auto inspect(Inspector& f, atom_name& x) { \
return f(caf::meta::type_name(#atom_namespace "::" #atom_name)); \ return f.object(x).fields(); \
} \ } \
} \ } \
CAF_ADD_TYPE_ID(project_name, (atom_namespace::atom_name)) CAF_ADD_TYPE_ID(project_name, (atom_namespace::atom_name))
......
...@@ -54,12 +54,12 @@ CAF_TEST(serialization roundtrips go through the registry) { ...@@ -54,12 +54,12 @@ CAF_TEST(serialization roundtrips go through the registry) {
CAF_MESSAGE("hdl.id: " << hdl->id()); CAF_MESSAGE("hdl.id: " << hdl->id());
byte_buffer buf; byte_buffer buf;
binary_serializer sink{sys, buf}; binary_serializer sink{sys, buf};
if (!inspect_object(sink, hdl)) if (!sink.apply_object(hdl))
CAF_FAIL("serialization failed: " << sink.get_error()); CAF_FAIL("serialization failed: " << sink.get_error());
CAF_MESSAGE("buf: " << buf); CAF_MESSAGE("buf: " << buf);
actor hdl2; actor hdl2;
binary_deserializer source{sys, buf}; binary_deserializer source{sys, buf};
if (!inspect_object(source, hdl2)) if (!source.apply_object(hdl2))
CAF_FAIL("deserialization failed: " << source.get_error()); CAF_FAIL("deserialization failed: " << source.get_error());
CAF_CHECK_EQUAL(hdl, hdl2); CAF_CHECK_EQUAL(hdl, hdl2);
anon_send_exit(hdl, exit_reason::user_shutdown); anon_send_exit(hdl, exit_reason::user_shutdown);
......
...@@ -59,7 +59,7 @@ struct fixture { ...@@ -59,7 +59,7 @@ struct fixture {
template <class... Ts> template <class... Ts>
void load(const std::vector<byte>& buf, Ts&... xs) { void load(const std::vector<byte>& buf, Ts&... xs) {
binary_deserializer source{nullptr, buf}; binary_deserializer source{nullptr, buf};
if (!inspect_objects(source, xs...)) if (!source.apply_objects(xs...))
CAF_FAIL("binary_deserializer failed to load: " << source.get_error()); CAF_FAIL("binary_deserializer failed to load: " << source.get_error());
} }
......
...@@ -57,7 +57,7 @@ struct fixture { ...@@ -57,7 +57,7 @@ struct fixture {
auto save(const Ts&... xs) { auto save(const Ts&... xs) {
byte_buffer result; byte_buffer result;
binary_serializer sink{nullptr, result}; binary_serializer sink{nullptr, result};
if (!inspect_objects(sink, detail::as_mutable_ref(xs)...)) if (!sink.apply_objects(xs...))
CAF_FAIL("binary_serializer failed to save: " << sink.get_error()); CAF_FAIL("binary_serializer failed to save: " << sink.get_error());
return result; return result;
} }
...@@ -65,7 +65,7 @@ struct fixture { ...@@ -65,7 +65,7 @@ struct fixture {
template <class... Ts> template <class... Ts>
void save_to_buf(byte_buffer& data, const Ts&... xs) { void save_to_buf(byte_buffer& data, const Ts&... xs) {
binary_serializer sink{nullptr, data}; binary_serializer sink{nullptr, data};
if (!inspect_objects(sink, detail::as_mutable_ref(xs)...)) if (!sink.apply_objects(xs...))
CAF_FAIL("binary_serializer failed to save: " << sink.get_error()); CAF_FAIL("binary_serializer failed to save: " << sink.get_error());
} }
}; };
......
...@@ -39,7 +39,7 @@ struct fixture : test_coordinator_fixture<> { ...@@ -39,7 +39,7 @@ struct fixture : test_coordinator_fixture<> {
size_t actual_size(const Ts&... xs) { size_t actual_size(const Ts&... xs) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink{sys, buf}; binary_serializer sink{sys, buf};
if (!inspect_objects(sink, detail::as_mutable_ref(xs)...)) if (!sink.apply_objects(xs...))
CAF_FAIL("failed to serialize data: " << sink.get_error()); CAF_FAIL("failed to serialize data: " << sink.get_error());
return buf.size(); return buf.size();
} }
......
...@@ -54,11 +54,11 @@ struct fixture { ...@@ -54,11 +54,11 @@ struct fixture {
T roundtrip(T x) { T roundtrip(T x) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink(sys, buf); binary_serializer sink(sys, buf);
if (!inspect_object(sink, x)) if (!sink.apply_object(x))
CAF_FAIL("serialization failed: " << sink.get_error()); CAF_FAIL("serialization failed: " << sink.get_error());
binary_deserializer source(sys, make_span(buf)); binary_deserializer source(sys, make_span(buf));
T y; T y;
if (!inspect_object(source, y)) if (!source.apply_object(y))
CAF_FAIL("deserialization failed: " << source.get_error()); CAF_FAIL("deserialization failed: " << source.get_error());
return y; return y;
} }
......
...@@ -54,11 +54,11 @@ struct fixture { ...@@ -54,11 +54,11 @@ struct fixture {
T roundtrip(T x) { T roundtrip(T x) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink(sys, buf); binary_serializer sink(sys, buf);
if (!inspect_object(sink, x)) if (!sink.apply_object(x))
CAF_FAIL("serialization failed: " << sink.get_error()); CAF_FAIL("serialization failed: " << sink.get_error());
binary_deserializer source(sys, make_span(buf)); binary_deserializer source(sys, make_span(buf));
T y; T y;
if (!inspect_object(source, y)) if (!source.apply_object(y))
CAF_FAIL("serialization failed: " << source.get_error()); CAF_FAIL("serialization failed: " << source.get_error());
return y; return y;
} }
......
...@@ -54,22 +54,10 @@ struct testee : deserializer { ...@@ -54,22 +54,10 @@ struct testee : deserializer {
log.insert(log.end(), indent, ' '); log.insert(log.end(), indent, ' ');
} }
using deserializer::object;
bool fetch_next_object_type(type_id_t&) override { bool fetch_next_object_type(type_id_t&) override {
return false; return false;
} }
template <class T>
auto object(optional<T>&) {
return object_t<testee>{"optional", this};
}
template <class... Ts>
auto object(variant<Ts...>&) {
return object_t<testee>{"variant", this};
}
bool begin_object(string_view object_name) override { bool begin_object(string_view object_name) override {
new_line(); new_line();
indent += 2; indent += 2;
...@@ -342,9 +330,9 @@ end object)_"); ...@@ -342,9 +330,9 @@ end object)_");
CAF_TEST(load inspectors support optional) { CAF_TEST(load inspectors support optional) {
optional<int32_t> x; optional<int32_t> x;
CAF_CHECK_EQUAL(inspect_object(f, x), true); CAF_CHECK_EQUAL(f.apply_object(x), true);
CAF_CHECK_EQUAL(f.log, R"_( CAF_CHECK_EQUAL(f.log, R"_(
begin object optional begin object anonymous
begin optional field value begin optional field value
end field end field
end object)_"); end object)_");
......
...@@ -23,36 +23,29 @@ std::string to_string(weekday x); ...@@ -23,36 +23,29 @@ std::string to_string(weekday x);
bool parse(caf::string_view input, weekday& dest); bool parse(caf::string_view input, weekday& dest);
namespace caf { template <class Inspector>
bool inspect(Inspector& f, weekday& x) {
template <>
struct inspector_access<weekday> : inspector_access_base<weekday> {
using default_impl = default_inspector_access<weekday>;
template <class Inspector>
static bool apply_object(Inspector& f, weekday& x) {
if (f.has_human_readable_format()) { if (f.has_human_readable_format()) {
auto get = [&x] { return to_string(x); }; auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) { return parse(str, x); }; auto set = [&x](std::string str) { return parse(str, x); };
f.object(x).fields(f.field("value", get, set)); f.object(x).fields(f.field("value", get, set));
} else { } else {
using default_impl = caf::default_inspector_access<weekday>;
return default_impl::apply_object(f, x); return default_impl::apply_object(f, x);
} }
} }
template <class Inspector> template <class Inspector>
static bool apply_value(Inspector& f, weekday& x) { bool inspect_value(Inspector& f, weekday& x) {
if (f.has_human_readable_format()) { if (f.has_human_readable_format()) {
auto get = [&x] { return to_string(x); }; auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) { return parse(str, x); }; auto set = [&x](std::string str) { return parse(str, x); };
return f.apply_value(get, set); return f.apply_value(get, set);
} else { } else {
using default_impl = caf::default_inspector_access<weekday>;
return default_impl::apply_value(f, x); return default_impl::apply_value(f, x);
} }
} }
};
} // namespace caf
#define ADD_GET_SET_FIELD(type, name) \ #define ADD_GET_SET_FIELD(type, name) \
private: \ private: \
......
...@@ -33,7 +33,7 @@ node_id roundtrip(node_id nid) { ...@@ -33,7 +33,7 @@ node_id roundtrip(node_id nid) {
byte_buffer buf; byte_buffer buf;
{ {
binary_serializer sink{nullptr, buf}; binary_serializer sink{nullptr, buf};
if (!inspect_object(sink, nid)) if (!sink.apply_object(nid))
CAF_FAIL("serialization failed: " << sink.get_error()); CAF_FAIL("serialization failed: " << sink.get_error());
} }
if (buf.empty()) if (buf.empty())
...@@ -41,7 +41,7 @@ node_id roundtrip(node_id nid) { ...@@ -41,7 +41,7 @@ node_id roundtrip(node_id nid) {
node_id result; node_id result;
{ {
binary_deserializer source{nullptr, buf}; binary_deserializer source{nullptr, buf};
if (!inspect_object(source, result)) if (!source.apply_object(result))
CAF_FAIL("deserialization failed: " << source.get_error()); CAF_FAIL("deserialization failed: " << source.get_error());
if (source.remaining() > 0) if (source.remaining() > 0)
CAF_FAIL("binary_serializer ignored part of its input"); CAF_FAIL("binary_serializer ignored part of its input");
......
...@@ -49,18 +49,6 @@ struct testee : serializer { ...@@ -49,18 +49,6 @@ struct testee : serializer {
log.insert(log.end(), indent, ' '); log.insert(log.end(), indent, ' ');
} }
using serializer::object;
template <class T>
auto object(optional<T>&) {
return object_t<testee>{"optional", this};
}
template <class... Ts>
auto object(variant<Ts...>&) {
return object_t<testee>{"variant", this};
}
bool inject_next_object_type(type_id_t type) override { bool inject_next_object_type(type_id_t type) override {
new_line(); new_line();
log += "next object type: "; log += "next object type: ";
...@@ -448,9 +436,9 @@ end object)_"); ...@@ -448,9 +436,9 @@ end object)_");
CAF_TEST(save inspectors support optional) { CAF_TEST(save inspectors support optional) {
optional<int32_t> x; optional<int32_t> x;
CAF_CHECK_EQUAL(inspect_object(f, x), true); CAF_CHECK_EQUAL(f.apply_object(x), true);
CAF_CHECK_EQUAL(f.log, R"_( CAF_CHECK_EQUAL(f.log, R"_(
begin object optional begin object anonymous
begin optional field value begin optional field value
end field end field
end object)_"); end object)_");
......
...@@ -111,7 +111,7 @@ struct fixture : test_coordinator_fixture<> { ...@@ -111,7 +111,7 @@ struct fixture : test_coordinator_fixture<> {
byte_buffer serialize(const Ts&... xs) { byte_buffer serialize(const Ts&... xs) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink{sys, buf}; binary_serializer sink{sys, buf};
if (!inspect_objects(sink, xs...)) if (!sink.apply_objects(xs...))
CAF_FAIL("serialization failed: " CAF_FAIL("serialization failed: "
<< sink.get_error() << sink.get_error()
<< ", data: " << deep_to_string(std::forward_as_tuple(xs...))); << ", data: " << deep_to_string(std::forward_as_tuple(xs...)));
...@@ -121,7 +121,7 @@ struct fixture : test_coordinator_fixture<> { ...@@ -121,7 +121,7 @@ struct fixture : test_coordinator_fixture<> {
template <class... Ts> template <class... Ts>
void deserialize(const byte_buffer& buf, Ts&... xs) { void deserialize(const byte_buffer& buf, Ts&... xs) {
binary_deserializer source{sys, buf}; binary_deserializer source{sys, buf};
if (!inspect_objects(source, xs...)) if (!source.apply_objects(xs...))
CAF_FAIL("deserialization failed: " << source.get_error()); CAF_FAIL("deserialization failed: " << source.get_error());
} }
......
...@@ -44,7 +44,7 @@ struct fixture { ...@@ -44,7 +44,7 @@ struct fixture {
template <class T> template <class T>
void set(const T& value) { void set(const T& value) {
settings_writer writer{&xs}; settings_writer writer{&xs};
if (!inspect_object(writer, value)) if (!writer.apply_object(value))
CAF_FAIL("failed two write to settings: " << writer.get_error()); CAF_FAIL("failed two write to settings: " << writer.get_error());
} }
......
...@@ -47,11 +47,11 @@ public: ...@@ -47,11 +47,11 @@ public:
} }
bool serialize(serializer& sink) const override { bool serialize(serializer& sink) const override {
return inspect_object(sink, value); return sink.apply_object(value);
} }
bool serialize(binary_serializer& sink) const override { bool serialize(binary_serializer& sink) const override {
return inspect_object(sink, value); return sink.apply_object(value);
} }
}; };
...@@ -72,7 +72,7 @@ private: ...@@ -72,7 +72,7 @@ private:
bool deserialize_impl(Deserializer& source, bool deserialize_impl(Deserializer& source,
std::unique_ptr<tracing_data>& dst) const { std::unique_ptr<tracing_data>& dst) const {
string value; string value;
if (!inspect_object(source, value)) if (!source.apply_object(value))
return false; return false;
dst.reset(new dummy_tracing_data(std::move(value))); dst.reset(new dummy_tracing_data(std::move(value)));
return true; return true;
...@@ -193,10 +193,10 @@ CAF_TEST(tracing data is serializable) { ...@@ -193,10 +193,10 @@ CAF_TEST(tracing data is serializable) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink{sys, buf}; binary_serializer sink{sys, buf};
tracing_data_ptr data{new dummy_tracing_data("iTrace")}; tracing_data_ptr data{new dummy_tracing_data("iTrace")};
CAF_CHECK(inspect_object(sink, data)); CAF_CHECK(sink.apply_object(data));
binary_deserializer source{sys, buf}; binary_deserializer source{sys, buf};
tracing_data_ptr copy; tracing_data_ptr copy;
CAF_CHECK(inspect_object(source, copy)); CAF_CHECK(source.apply_object(copy));
CAF_REQUIRE_NOT_EQUAL(copy.get(), nullptr); CAF_REQUIRE_NOT_EQUAL(copy.get(), nullptr);
CAF_CHECK_EQUAL(dynamic_cast<dummy_tracing_data&>(*copy).value, "iTrace"); CAF_CHECK_EQUAL(dynamic_cast<dummy_tracing_data&>(*copy).value, "iTrace");
} }
......
...@@ -133,7 +133,7 @@ struct fixture { ...@@ -133,7 +133,7 @@ struct fixture {
byte_buffer serialize(uri x) { byte_buffer serialize(uri x) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink{nullptr, buf}; binary_serializer sink{nullptr, buf};
if (!inspect_objects(sink, x)) if (!sink.apply_objects(x))
CAF_FAIL("unable to serialize " << x << ": " << sink.get_error()); CAF_FAIL("unable to serialize " << x << ": " << sink.get_error());
return buf; return buf;
} }
...@@ -141,7 +141,7 @@ struct fixture { ...@@ -141,7 +141,7 @@ struct fixture {
uri deserialize(byte_buffer buf) { uri deserialize(byte_buffer buf) {
uri result; uri result;
binary_deserializer source{nullptr, buf}; binary_deserializer source{nullptr, buf};
if (!inspect_objects(source, result)) if (!source.apply_objects(result))
CAF_FAIL("unable to deserialize from buffer: " << source.get_error()); CAF_FAIL("unable to deserialize from buffer: " << source.get_error());
return result; return result;
} }
......
...@@ -75,12 +75,12 @@ public: ...@@ -75,12 +75,12 @@ public:
if (dref.hdr_.operation == basp::message_type::routed_message) { if (dref.hdr_.operation == basp::message_type::routed_message) {
node_id src_node; node_id src_node;
node_id dst_node; node_id dst_node;
if (!inspect_object(source, src_node)) { if (!source.apply_object(src_node)) {
CAF_LOG_ERROR( CAF_LOG_ERROR(
"failed to read source of routed message:" << source.get_error()); "failed to read source of routed message:" << source.get_error());
return; return;
} }
if (!inspect_object(source, dst_node)) { if (!source.apply_object(dst_node)) {
CAF_LOG_ERROR("failed to read destination of routed message:" CAF_LOG_ERROR("failed to read destination of routed message:"
<< source.get_error()); << source.get_error());
return; return;
...@@ -104,11 +104,11 @@ public: ...@@ -104,11 +104,11 @@ public:
return; return;
} }
// Get the remainder of the message. // Get the remainder of the message.
if (!inspect_object(source, stages)) { if (!source.apply_object(stages)) {
CAF_LOG_ERROR("failed to read stages:" << source.get_error()); CAF_LOG_ERROR("failed to read stages:" << source.get_error());
return; return;
} }
if (!inspect_objects(source, msg)) { if (!source.apply_objects(msg)) {
CAF_LOG_ERROR("failed to read message content:" << source.get_error()); CAF_LOG_ERROR("failed to read message content:" << source.get_error());
return; return;
} }
......
...@@ -71,7 +71,7 @@ connection_state instance::handle(execution_unit* ctx, new_data_msg& dm, ...@@ -71,7 +71,7 @@ connection_state instance::handle(execution_unit* ctx, new_data_msg& dm,
} }
} else { } else {
binary_deserializer source{ctx, dm.buf}; binary_deserializer source{ctx, dm.buf};
if (!inspect_object(source, hdr)) { if (!source.apply_object(hdr)) {
CAF_LOG_WARNING("failed to receive header:" << source.get_error()); CAF_LOG_WARNING("failed to receive header:" << source.get_error());
return err(malformed_basp_message); return err(malformed_basp_message);
} }
...@@ -183,7 +183,7 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender, ...@@ -183,7 +183,7 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
sender ? sender->id() : invalid_actor_id, sender ? sender->id() : invalid_actor_id,
dest_actor}; dest_actor};
auto writer = make_callback([&](binary_serializer& sink) { // auto writer = make_callback([&](binary_serializer& sink) { //
return inspect_objects(sink, forwarding_stack, msg); return sink.apply_objects(forwarding_stack, msg);
}); });
write(ctx, callee_.get_buffer(path->hdl), hdr, &writer); write(ctx, callee_.get_buffer(path->hdl), hdr, &writer);
} else { } else {
...@@ -197,8 +197,7 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender, ...@@ -197,8 +197,7 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
CAF_LOG_DEBUG("send routed message: " CAF_LOG_DEBUG("send routed message: "
<< CAF_ARG(source_node) << CAF_ARG(dest_node) << CAF_ARG(source_node) << CAF_ARG(dest_node)
<< CAF_ARG(forwarding_stack) << CAF_ARG(msg)); << CAF_ARG(forwarding_stack) << CAF_ARG(msg));
return inspect_objects(sink, source_node, dest_node, forwarding_stack, return sink.apply_objects(source_node, dest_node, forwarding_stack, msg);
msg);
}); });
write(ctx, callee_.get_buffer(path->hdl), hdr, &writer); write(ctx, callee_.get_buffer(path->hdl), hdr, &writer);
} }
...@@ -222,7 +221,7 @@ void instance::write(execution_unit* ctx, byte_buffer& buf, header& hdr, ...@@ -222,7 +221,7 @@ void instance::write(execution_unit* ctx, byte_buffer& buf, header& hdr,
auto payload_len = buf.size() - (header_offset + basp::header_size); auto payload_len = buf.size() - (header_offset + basp::header_size);
hdr.payload_len = static_cast<uint32_t>(payload_len); hdr.payload_len = static_cast<uint32_t>(payload_len);
} }
if (!inspect_objects(sink, hdr)) if (!sink.apply_objects(hdr))
CAF_LOG_ERROR(sink.get_error()); CAF_LOG_ERROR(sink.get_error());
} }
...@@ -251,7 +250,7 @@ void instance::write_server_handshake(execution_unit* ctx, byte_buffer& out_buf, ...@@ -251,7 +250,7 @@ void instance::write_server_handshake(execution_unit* ctx, byte_buffer& out_buf,
aid = pa->first->id(); aid = pa->first->id();
iface = pa->second; iface = pa->second;
} }
return inspect_objects(sink, this_node_, app_ids, aid, iface); return sink.apply_objects(this_node_, app_ids, aid, iface);
}); });
header hdr{message_type::server_handshake, header hdr{message_type::server_handshake,
0, 0,
...@@ -264,7 +263,7 @@ void instance::write_server_handshake(execution_unit* ctx, byte_buffer& out_buf, ...@@ -264,7 +263,7 @@ void instance::write_server_handshake(execution_unit* ctx, byte_buffer& out_buf,
void instance::write_client_handshake(execution_unit* ctx, byte_buffer& buf) { void instance::write_client_handshake(execution_unit* ctx, byte_buffer& buf) {
auto writer = make_callback([&](binary_serializer& sink) { // auto writer = make_callback([&](binary_serializer& sink) { //
return inspect_objects(sink, this_node_); return sink.apply_objects(this_node_);
}); });
header hdr{message_type::client_handshake, header hdr{message_type::client_handshake,
0, 0,
...@@ -279,7 +278,7 @@ void instance::write_monitor_message(execution_unit* ctx, byte_buffer& buf, ...@@ -279,7 +278,7 @@ void instance::write_monitor_message(execution_unit* ctx, byte_buffer& buf,
const node_id& dest_node, actor_id aid) { const node_id& dest_node, actor_id aid) {
CAF_LOG_TRACE(CAF_ARG(dest_node) << CAF_ARG(aid)); CAF_LOG_TRACE(CAF_ARG(dest_node) << CAF_ARG(aid));
auto writer = make_callback([&](binary_serializer& sink) { // auto writer = make_callback([&](binary_serializer& sink) { //
return inspect_objects(sink, this_node_, dest_node); return sink.apply_objects(this_node_, dest_node);
}); });
header hdr{message_type::monitor_message, 0, 0, 0, invalid_actor_id, aid}; header hdr{message_type::monitor_message, 0, 0, 0, invalid_actor_id, aid};
write(ctx, buf, hdr, &writer); write(ctx, buf, hdr, &writer);
...@@ -290,7 +289,7 @@ void instance::write_down_message(execution_unit* ctx, byte_buffer& buf, ...@@ -290,7 +289,7 @@ void instance::write_down_message(execution_unit* ctx, byte_buffer& buf,
const error& rsn) { const error& rsn) {
CAF_LOG_TRACE(CAF_ARG(dest_node) << CAF_ARG(aid) << CAF_ARG(rsn)); CAF_LOG_TRACE(CAF_ARG(dest_node) << CAF_ARG(aid) << CAF_ARG(rsn));
auto writer = make_callback([&](binary_serializer& sink) { // auto writer = make_callback([&](binary_serializer& sink) { //
return inspect_objects(sink, this_node_, dest_node, rsn); return sink.apply_objects(this_node_, dest_node, rsn);
}); });
header hdr{message_type::down_message, 0, 0, 0, aid, invalid_actor_id}; header hdr{message_type::down_message, 0, 0, 0, aid, invalid_actor_id};
write(ctx, buf, hdr, &writer); write(ctx, buf, hdr, &writer);
...@@ -326,7 +325,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl, ...@@ -326,7 +325,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
string_list app_ids; string_list app_ids;
actor_id aid = invalid_actor_id; actor_id aid = invalid_actor_id;
std::set<std::string> sigs; std::set<std::string> sigs;
if (!inspect_objects(source, source_node, app_ids, aid, sigs)) { if (!source.apply_objects(source_node, app_ids, aid, sigs)) {
CAF_LOG_WARNING("unable to deserialize payload of server handshake:" CAF_LOG_WARNING("unable to deserialize payload of server handshake:"
<< source.get_error()); << source.get_error());
return serializing_basp_payload_failed; return serializing_basp_payload_failed;
...@@ -376,7 +375,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl, ...@@ -376,7 +375,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
// Deserialize payload. // Deserialize payload.
binary_deserializer source{ctx, *payload}; binary_deserializer source{ctx, *payload};
node_id source_node; node_id source_node;
if (!inspect_objects(source, source_node)) { if (!source.apply_objects(source_node)) {
CAF_LOG_WARNING("unable to deserialize payload of client handshake:" CAF_LOG_WARNING("unable to deserialize payload of client handshake:"
<< source.get_error()); << source.get_error());
return serializing_basp_payload_failed; return serializing_basp_payload_failed;
...@@ -399,7 +398,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl, ...@@ -399,7 +398,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
binary_deserializer source{ctx, *payload}; binary_deserializer source{ctx, *payload};
node_id source_node; node_id source_node;
node_id dest_node; node_id dest_node;
if (!inspect_objects(source, source_node, dest_node)) { if (!source.apply_objects(source_node, dest_node)) {
CAF_LOG_WARNING( CAF_LOG_WARNING(
"unable to deserialize source and destination for routed message:" "unable to deserialize source and destination for routed message:"
<< source.get_error()); << source.get_error());
...@@ -458,7 +457,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl, ...@@ -458,7 +457,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
binary_deserializer source{ctx, *payload}; binary_deserializer source{ctx, *payload};
node_id source_node; node_id source_node;
node_id dest_node; node_id dest_node;
if (!inspect_objects(source, source_node, dest_node)) { if (!source.apply_objects(source_node, dest_node)) {
CAF_LOG_WARNING("unable to deserialize payload of monitor message:" CAF_LOG_WARNING("unable to deserialize payload of monitor message:"
<< source.get_error()); << source.get_error());
return serializing_basp_payload_failed; return serializing_basp_payload_failed;
...@@ -475,7 +474,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl, ...@@ -475,7 +474,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
node_id source_node; node_id source_node;
node_id dest_node; node_id dest_node;
error fail_state; error fail_state;
if (!inspect_objects(source, source_node, dest_node, fail_state)) { if (!source.apply_objects(source_node, dest_node, fail_state)) {
CAF_LOG_WARNING("unable to deserialize payload of down message:" CAF_LOG_WARNING("unable to deserialize payload of down message:"
<< source.get_error()); << source.get_error());
return serializing_basp_payload_failed; return serializing_basp_payload_failed;
...@@ -512,12 +511,12 @@ void instance::forward(execution_unit* ctx, const node_id& dest_node, ...@@ -512,12 +511,12 @@ void instance::forward(execution_unit* ctx, const node_id& dest_node,
CAF_LOG_TRACE(CAF_ARG(dest_node) << CAF_ARG(hdr) << CAF_ARG(payload)); CAF_LOG_TRACE(CAF_ARG(dest_node) << CAF_ARG(hdr) << CAF_ARG(payload));
auto path = lookup(dest_node); auto path = lookup(dest_node);
if (path) { if (path) {
binary_serializer bs{ctx, callee_.get_buffer(path->hdl)}; binary_serializer sink{ctx, callee_.get_buffer(path->hdl)};
if (!inspect_objects(bs, hdr)) { if (!sink.apply_object(hdr)) {
CAF_LOG_ERROR("unable to serialize BASP header:" << bs.get_error()); CAF_LOG_ERROR("unable to serialize BASP header:" << sink.get_error());
return; return;
} }
bs.value(span<const byte>{payload.data(), payload.size()}); sink.value(span<const byte>{payload.data(), payload.size()});
flush(*path); flush(*path);
} else { } else {
CAF_LOG_WARNING("cannot forward message, no route to destination"); CAF_LOG_WARNING("cannot forward message, no route to destination");
......
...@@ -163,7 +163,7 @@ public: ...@@ -163,7 +163,7 @@ public:
uint32_t serialized_size(const message& msg) { uint32_t serialized_size(const message& msg) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink{mpx_, buf}; binary_serializer sink{mpx_, buf};
if (!inspect_objects(sink, msg)) if (!sink.apply_object(msg))
CAF_FAIL("failed to serialize message: " << sink.get_error()); CAF_FAIL("failed to serialize message: " << sink.get_error());
return static_cast<uint32_t>(buf.size()); return static_cast<uint32_t>(buf.size());
} }
...@@ -221,7 +221,7 @@ public: ...@@ -221,7 +221,7 @@ public:
template <class... Ts> template <class... Ts>
void to_payload(byte_buffer& buf, const Ts&... xs) { void to_payload(byte_buffer& buf, const Ts&... xs) {
binary_serializer sink{mpx_, buf}; binary_serializer sink{mpx_, buf};
if (!inspect_objects(sink, xs...)) if (!sink.apply_objects(xs...))
CAF_FAIL("failed to serialize payload: " << sink.get_error()); CAF_FAIL("failed to serialize payload: " << sink.get_error());
} }
...@@ -235,7 +235,7 @@ public: ...@@ -235,7 +235,7 @@ public:
auto pw = make_callback([&](binary_serializer& sink) { auto pw = make_callback([&](binary_serializer& sink) {
if (writer != nullptr && !(*writer)(sink)) if (writer != nullptr && !(*writer)(sink))
return false; return false;
return inspect_objects(sink, x, xs...); return sink.apply_objects(x, xs...);
}); });
to_buf(buf, hdr, &pw); to_buf(buf, hdr, &pw);
} }
...@@ -243,7 +243,7 @@ public: ...@@ -243,7 +243,7 @@ public:
std::pair<basp::header, byte_buffer> from_buf(const byte_buffer& buf) { std::pair<basp::header, byte_buffer> from_buf(const byte_buffer& buf) {
basp::header hdr; basp::header hdr;
binary_deserializer source{mpx_, buf}; binary_deserializer source{mpx_, buf};
if (!inspect_object(source, hdr)) if (!source.apply_object(hdr))
CAF_FAIL("failed to deserialize header: " << source.get_error()); CAF_FAIL("failed to deserialize header: " << source.get_error());
byte_buffer payload; byte_buffer payload;
if (hdr.payload_len > 0) { if (hdr.payload_len > 0) {
...@@ -307,7 +307,7 @@ public: ...@@ -307,7 +307,7 @@ public:
binary_deserializer source{mpx_, buf}; binary_deserializer source{mpx_, buf};
std::vector<strong_actor_ptr> stages; std::vector<strong_actor_ptr> stages;
message msg; message msg;
if (!inspect_objects(source, stages, msg)) if (!source.apply_objects(stages, msg))
CAF_FAIL("deserialization failed: " << source.get_error()); CAF_FAIL("deserialization failed: " << source.get_error());
auto src = actor_cast<strong_actor_ptr>(registry_->get(hdr.source_actor)); auto src = actor_cast<strong_actor_ptr>(registry_->get(hdr.source_actor));
auto dest = registry_->get(hdr.dest_actor); auto dest = registry_->get(hdr.dest_actor);
...@@ -348,7 +348,7 @@ public: ...@@ -348,7 +348,7 @@ public:
basp::header hdr; basp::header hdr;
{ // lifetime scope of source { // lifetime scope of source
binary_deserializer source{this_->mpx(), ob}; binary_deserializer source{this_->mpx(), ob};
if (!inspect_objects(source, hdr)) if (!source.apply_objects(hdr))
CAF_FAIL("failed to deserialize header: " << source.get_error()); CAF_FAIL("failed to deserialize header: " << source.get_error());
} }
byte_buffer payload; byte_buffer payload;
...@@ -486,7 +486,7 @@ CAF_TEST(non_empty_server_handshake) { ...@@ -486,7 +486,7 @@ CAF_TEST(non_empty_server_handshake) {
std::set<std::string> ifs{"caf::replies_to<@u16>::with<@u16>"}; std::set<std::string> ifs{"caf::replies_to<@u16>::with<@u16>"};
binary_serializer sink{nullptr, expected_payload}; binary_serializer sink{nullptr, expected_payload};
auto id = self()->id(); auto id = self()->id();
if (!inspect_objects(sink, instance().this_node(), app_ids, id, ifs)) if (!sink.apply_objects(instance().this_node(), app_ids, id, ifs))
CAF_FAIL("serializing handshake failed: " << sink.get_error()); CAF_FAIL("serializing handshake failed: " << sink.get_error());
CAF_CHECK_EQUAL(hexstr(payload), hexstr(expected_payload)); CAF_CHECK_EQUAL(hexstr(payload), hexstr(expected_payload));
} }
......
...@@ -49,7 +49,7 @@ struct fixture : test_coordinator_fixture<> { ...@@ -49,7 +49,7 @@ struct fixture : test_coordinator_fixture<> {
auto serialize(T& x, Ts&... xs) { auto serialize(T& x, Ts&... xs) {
byte_buffer buf; byte_buffer buf;
binary_serializer sink{sys, buf}; binary_serializer sink{sys, buf};
if (!inspect_objects(sink, x, xs...)) if (!sink.apply_objects(x, xs...))
CAF_FAIL("serialization failed: " << sink.get_error()); CAF_FAIL("serialization failed: " << sink.get_error());
return buf; return buf;
} }
...@@ -57,7 +57,7 @@ struct fixture : test_coordinator_fixture<> { ...@@ -57,7 +57,7 @@ struct fixture : test_coordinator_fixture<> {
template <class Buffer, class T, class... Ts> template <class Buffer, class T, class... Ts>
void deserialize(const Buffer& buf, T& x, Ts&... xs) { void deserialize(const Buffer& buf, T& x, Ts&... xs) {
binary_deserializer source{sys, buf}; binary_deserializer source{sys, buf};
if (!inspect_objects(source, x, xs...)) if (!source.apply_objects(x, xs...))
CAF_FAIL("serialization failed: " << source.get_error()); CAF_FAIL("serialization failed: " << source.get_error());
} }
}; };
......
...@@ -109,7 +109,7 @@ CAF_TEST(deliver serialized message) { ...@@ -109,7 +109,7 @@ CAF_TEST(deliver serialized message) {
std::vector<strong_actor_ptr> stages; std::vector<strong_actor_ptr> stages;
binary_serializer sink{sys, payload}; binary_serializer sink{sys, payload};
auto msg = make_message(ok_atom_v); auto msg = make_message(ok_atom_v);
if (!inspect_objects(sink, stages, msg)) if (!sink.apply_objects(stages, msg))
CAF_FAIL("unable to serialize message: " << sink.get_error()); CAF_FAIL("unable to serialize message: " << sink.get_error());
io::basp::header hdr{io::basp::message_type::direct_message, io::basp::header hdr{io::basp::message_type::direct_message,
0, 0,
......
...@@ -843,7 +843,7 @@ public: ...@@ -843,7 +843,7 @@ public:
caf::byte_buffer serialize(const Ts&... xs) { caf::byte_buffer serialize(const Ts&... xs) {
caf::byte_buffer buf; caf::byte_buffer buf;
caf::binary_serializer sink{sys, buf}; caf::binary_serializer sink{sys, buf};
if (!inspect_objects(sink, xs...)) if (!sink.apply_objects(xs...))
CAF_FAIL("serialization failed: " << sink.get_error()); CAF_FAIL("serialization failed: " << sink.get_error());
return buf; return buf;
} }
...@@ -851,7 +851,7 @@ public: ...@@ -851,7 +851,7 @@ public:
template <class... Ts> template <class... Ts>
void deserialize(const caf::byte_buffer& buf, Ts&... xs) { void deserialize(const caf::byte_buffer& buf, Ts&... xs) {
caf::binary_deserializer source{sys, buf}; caf::binary_deserializer source{sys, buf};
if (!inspect_objects(source, xs...)) if (!source.apply_objects(xs...))
CAF_FAIL("deserialization failed: " << source.get_error()); CAF_FAIL("deserialization failed: " << source.get_error());
} }
......
...@@ -8,6 +8,8 @@ be serializable. Using a message type that is not serializable causes a compiler ...@@ -8,6 +8,8 @@ be serializable. Using a message type that is not serializable causes a compiler
error unless explicitly listed as unsafe message type by the user (see error unless explicitly listed as unsafe message type by the user (see
:ref:`unsafe-message-type`). :ref:`unsafe-message-type`).
.. _type-inspection-data-model:
Data Model Data Model
---------- ----------
...@@ -90,6 +92,92 @@ the inspector: ...@@ -90,6 +92,92 @@ the inspector:
f.field("z", x.z)); f.field("z", x.z));
} }
Writing ``inspect_value`` Overloads
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The free function ``inspect`` models the object-level type inspection. As
mentioned in the section on the :ref:`data model <type-inspection-data-model>`,
objects are containers for fields that in turn contain a value. When providing
an ``inspect`` overload, CAF recursively visits a value as an object.
For example, consider the following ID type that simply wraps a string:
.. code-block:: C++
struct id { std::string value; };
template <class Inspector>
bool inspect(Inspector& f, id& x) {
return f.object(x).fields(f.field("value", x.value));
}
The type ``id`` is basically a *strong typedef* to improve type safety. To a
type inspector, ID objects look as follows:
.. code-block:: none
object(type: "id") {
field(name: "value") {
value(type: "string")
}
}
Now, this type has little use on its own. Usually, we would use such a type to
compose other types such as the following type ``person``:
.. code-block:: C++
struct person { std::string name; id key; };
template <class Inspector>
bool inspect(Inspector& f, person& x) {
return f.object(x).fields(f.field("name", x.name), f.field("key", x.key));
}
By providing the ``inspect`` overload for ID, inspectors can recursively visit
an ``id`` as an object. Hence, the above implementations work as expected. When
using ``person`` in human-readable data formats such as CAF configurations,
however, allowing CAF to look "inside" a strong typedef can simplify working
with types.
With the current implementation, we could read the key ``manager.ceo`` from a
configuration file with this content:
.. code-block:: none
manager {
ceo {
name = "Bob"
key = {
value = "TWFuIGlz"
}
}
}
This clearly is more verbose than it needs to be. By also providing an overload
for ``inspect_value``, we can teach CAF how to inspect an ID directly as a
*value* without having to recursively visit it as an object:
.. code-block:: C++
template <class Inspector>
bool inspect_value(Inspector& f, id& x) {
return f.apply_value(x.value);
}
With this overload in place, inspectors can now remove one level of indirection
and read or write strings whenever they encounter an ``id`` as value. This
allows us to simply our config file from before:
.. code-block:: none
manager {
ceo {
name = "Bob"
key = "TWFuIGlz"
}
}
Specializing ``inspector_access`` Specializing ``inspector_access``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -128,9 +216,13 @@ The full interface of ``inspector_access`` looks as follows: ...@@ -128,9 +216,13 @@ The full interface of ``inspector_access`` looks as follows:
SetFallback& set_fallback); SetFallback& set_fallback);
}; };
For most types, we can implement ``apply_object`` and use default implementation The static member function ``apply_object`` has the same role as the free
for the other member functions. For example, specializing ``inspector_access`` ``inspect`` function. Likewise, ``apply_value`` corresponds to the free
for our ``point_3d`` would look as follows: ``inspect_value`` function.
For most types, we can implement only ``apply_object`` and use default
implementation for the other member functions. For example, specializing
``inspector_access`` for our ``point_3d`` would look as follows:
.. code-block:: C++ .. code-block:: C++
...@@ -170,9 +262,6 @@ from ``apply_value``. The latter customizes how CAF inspects a value inside a ...@@ -170,9 +262,6 @@ from ``apply_value``. The latter customizes how CAF inspects a value inside a
field. By calling ``apply_object``, we simply recursively visit ``x`` as an field. By calling ``apply_object``, we simply recursively visit ``x`` as an
object again. object again.
For a non-trivial use case of ``apply_value``, see
:ref:`has-human-readable-format`.
Types with Getter and Setter Access Types with Getter and Setter Access
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -364,36 +453,29 @@ an ``enum class`` otherwise. ...@@ -364,36 +453,29 @@ an ``enum class`` otherwise.
bool parse(std::string_view input, weekday& dest); bool parse(std::string_view input, weekday& dest);
namespace caf {
template <>
struct inspector_access<weekday> : inspector_access_base<weekday> {
using default_impl = default_inspector_access<weekday>;
template <class Inspector> template <class Inspector>
static bool apply_object(Inspector& f, weekday& x) { bool inspect(Inspector& f, weekday& x) {
if (f.has_human_readable_format()) { if (f.has_human_readable_format()) {
auto get = [&x] { return to_string(x); }; auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) { return parse(str, x); }; auto set = [&x](std::string str) { return parse(str, x); };
f.object(x).fields(f.field("value", get, set)); f.object(x).fields(f.field("value", get, set));
} else { } else {
using default_impl = caf::default_inspector_access<weekday>;
return default_impl::apply_object(f, x); return default_impl::apply_object(f, x);
} }
} }
template <class Inspector> template <class Inspector>
static bool apply_value(Inspector& f, weekday& x) { bool inspect_value(Inspector& f, weekday& x) {
if (f.has_human_readable_format()) { if (f.has_human_readable_format()) {
auto get = [&x] { return to_string(x); }; auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) { return parse(str, x); }; auto set = [&x](std::string str) { return parse(str, x); };
return f.apply_value(get, set); return f.apply_value(get, set);
} else { } else {
using default_impl = caf::default_inspector_access<weekday>;
return default_impl::apply_value(f, x); return default_impl::apply_value(f, x);
} }
} }
};
} // namespace caf
When inspecting an object of type ``weekday``, we treat it as if we were When inspecting an object of type ``weekday``, we treat it as if we were
inspecting an object with a single field named ``value``. However, usually we inspecting an object with a single field named ``value``. However, usually we
......
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