Commit 34237d75 authored by Dominik Charousset's avatar Dominik Charousset

Port CAF to the new inspector API

parent 7933819d
...@@ -38,8 +38,8 @@ struct foo { ...@@ -38,8 +38,8 @@ struct foo {
}; };
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) { bool inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a, x.b); return f.object(x).fields(f.field("a", x.a), f.field("b", x.b));
} }
// --(rst-foo-end)-- // --(rst-foo-end)--
...@@ -57,8 +57,8 @@ struct foo2 { ...@@ -57,8 +57,8 @@ struct foo2 {
// foo2 also needs to be serializable // foo2 also needs to be serializable
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo2& x) { bool inspect(Inspector& f, foo2& x) {
return f(meta::type_name("foo2"), x.a, x.b); return f.objects(x).fields(f.field("a", x.a), f.field("b", x.b));
} }
// receives our custom message types // receives our custom message types
......
...@@ -47,8 +47,8 @@ public: ...@@ -47,8 +47,8 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, foo& x) { friend bool inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a_, x.b_); return f.object(x).fields(f.field("a", x.a_), f.field("b", x.b_));
} }
private: private:
......
...@@ -83,19 +83,19 @@ scope_guard<Fun> make_scope_guard(Fun f) { ...@@ -83,19 +83,19 @@ scope_guard<Fun> make_scope_guard(Fun f) {
// --(rst-inspect-begin)-- // --(rst-inspect-begin)--
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) { bool inspect(Inspector& f, foo& x) {
if constexpr (Inspector::reads_state) { auto get_a = [&x] { return x.a(); };
return f(meta::type_name("foo"), x.a(), x.b()); auto set_a = [&x](int val) {
} else { x.a(val);
int a; return true;
int b; };
// write back to x at scope exit auto get_b = [&x] { return x.b(); };
auto g = make_scope_guard([&] { auto set_b = [&x](int val) {
x.set_a(a); x.b(val);
x.set_b(b); return true;
}); };
return f(meta::type_name("foo"), a, b); return f.object(x).fields(f.field("a", get_a, set_a),
} f.field("b", get_b, set_b));
} }
// --(rst-inspect-end)-- // --(rst-inspect-end)--
......
...@@ -103,7 +103,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -103,7 +103,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/thread_safe_actor_clock.cpp src/detail/thread_safe_actor_clock.cpp
src/detail/tick_emitter.cpp src/detail/tick_emitter.cpp
src/detail/type_id_list_builder.cpp src/detail/type_id_list_builder.cpp
src/detail/uri_impl.cpp
src/downstream_manager.cpp src/downstream_manager.cpp
src/downstream_manager_base.cpp src/downstream_manager_base.cpp
src/error.cpp src/error.cpp
...@@ -125,6 +124,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -125,6 +124,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/ipv6_address.cpp src/ipv6_address.cpp
src/ipv6_endpoint.cpp src/ipv6_endpoint.cpp
src/ipv6_subnet.cpp src/ipv6_subnet.cpp
src/load_inspector.cpp
src/local_actor.cpp src/local_actor.cpp
src/logger.cpp src/logger.cpp
src/mailbox_element.cpp src/mailbox_element.cpp
...@@ -148,6 +148,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS} ...@@ -148,6 +148,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/replies_to.cpp src/replies_to.cpp
src/response_promise.cpp src/response_promise.cpp
src/resumable.cpp src/resumable.cpp
src/save_inspector.cpp
src/scheduled_actor.cpp src/scheduled_actor.cpp
src/scheduler/abstract_coordinator.cpp src/scheduler/abstract_coordinator.cpp
src/scheduler/test_coordinator.cpp src/scheduler/test_coordinator.cpp
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <string> #include <string>
#include "caf/abstract_channel.hpp" #include "caf/abstract_channel.hpp"
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
#include "caf/attachable.hpp" #include "caf/attachable.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
...@@ -46,12 +47,6 @@ public: ...@@ -46,12 +47,6 @@ public:
// -- pure virtual member functions ------------------------------------------ // -- pure virtual member functions ------------------------------------------
/// Serialize this group to `sink`.
virtual error save(serializer& sink) const = 0;
/// Serialize this group to `sink`.
virtual error_code<sec> save(binary_serializer& sink) const = 0;
/// Subscribes `who` to this group and returns `true` on success /// Subscribes `who` to this group and returns `true` on success
/// or `false` if `who` is already subscribed. /// or `false` if `who` is already subscribed.
virtual bool subscribe(strong_actor_ptr who) = 0; virtual bool subscribe(strong_actor_ptr who) = 0;
...@@ -64,22 +59,28 @@ public: ...@@ -64,22 +59,28 @@ public:
// -- observers -------------------------------------------------------------- // -- observers --------------------------------------------------------------
/// Returns the parent module.
group_module& module() const {
return parent_;
}
/// Returns the hosting system. /// Returns the hosting system.
actor_system& system() const { actor_system& system() const {
return system_; return system_;
} }
/// Returns the parent module.
group_module& module() const {
return parent_;
}
/// Returns a string representation of the group identifier, e.g., /// Returns a string representation of the group identifier, e.g.,
/// "224.0.0.1" for IPv4 multicast or a user-defined string for local groups. /// "224.0.0.1" for IPv4 multicast or a user-defined string for local groups.
const std::string& identifier() const { const std::string& identifier() const {
return identifier_; return identifier_;
} }
/// @private
const actor& dispatcher() {
return dispatcher_;
}
protected: protected:
abstract_group(group_module& mod, std::string id, node_id nid); abstract_group(group_module& mod, std::string id, node_id nid);
...@@ -87,6 +88,7 @@ protected: ...@@ -87,6 +88,7 @@ protected:
group_module& parent_; group_module& parent_;
std::string identifier_; std::string identifier_;
node_id origin_; node_id origin_;
actor dispatcher_;
}; };
/// A smart pointer type that manages instances of {@link group}. /// A smart pointer type that manages instances of {@link group}.
......
...@@ -147,7 +147,7 @@ public: ...@@ -147,7 +147,7 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, actor& x) { friend bool inspect(Inspector& f, actor& x) {
return inspect(f, x.ptr_); return inspect(f, x.ptr_);
} }
......
...@@ -110,7 +110,7 @@ public: ...@@ -110,7 +110,7 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, actor_addr& x) { friend bool inspect(Inspector& f, actor_addr& x) {
return inspect(f, x.ptr_); return inspect(f, x.ptr_);
} }
......
...@@ -25,10 +25,6 @@ ...@@ -25,10 +25,6 @@
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/meta/omittable_if_none.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/weak_intrusive_ptr.hpp" #include "caf/weak_intrusive_ptr.hpp"
...@@ -97,7 +93,7 @@ public: ...@@ -97,7 +93,7 @@ public:
static_assert(sizeof(std::atomic<size_t>) == sizeof(void*), static_assert(sizeof(std::atomic<size_t>) == sizeof(void*),
"std::atomic not lockfree on this platform"); "std::atomic not lockfree on this platform");
static_assert(sizeof(intrusive_ptr<node_id::data>) == sizeof(void*), static_assert(sizeof(intrusive_ptr<int>) == sizeof(int*),
"intrusive_ptr<T> and T* have different size"); "intrusive_ptr<T> and T* have different size");
static_assert(sizeof(node_id) == sizeof(void*), static_assert(sizeof(node_id) == sizeof(void*),
...@@ -205,25 +201,34 @@ CAF_CORE_EXPORT std::string to_string(const weak_actor_ptr& x); ...@@ -205,25 +201,34 @@ CAF_CORE_EXPORT std::string to_string(const weak_actor_ptr& x);
CAF_CORE_EXPORT void append_to_string(std::string& x, const weak_actor_ptr& y); CAF_CORE_EXPORT void append_to_string(std::string& x, const weak_actor_ptr& y);
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, strong_actor_ptr& x) { bool inspect(Inspector& f, strong_actor_ptr& x) {
actor_id aid = 0; actor_id aid = 0;
node_id nid; node_id nid;
if (x) { if constexpr (!Inspector::is_loading) {
aid = x->aid; if (x) {
nid = x->nid; aid = x->aid;
nid = x->nid;
}
} }
auto load = [&] { return load_actor(x, context_of(&f), aid, nid); }; auto load_cb = [&] { return load_actor(x, context_of(&f), aid, nid); };
auto save = [&] { return save_actor(x, context_of(&f), aid, nid); }; auto save_cb = [&] { return save_actor(x, context_of(&f), aid, nid); };
return f(meta::type_name("actor"), aid, meta::omittable_if_none(), nid, return f.object(x)
meta::load_callback(load), meta::save_callback(save)); .pretty_name("actor")
.on_load(load_cb)
.on_save(save_cb)
.fields(f.field("id", aid), f.field("node", nid));
} }
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, weak_actor_ptr& x) { bool inspect(Inspector& f, weak_actor_ptr& x) {
// inspect as strong pointer, then write back to weak pointer on save // Inspect as strong pointer, then write back to weak pointer on save.
auto tmp = x.lock(); auto tmp = x.lock();
auto load = [&] { x.reset(tmp.get()); }; auto result = inspect(f, tmp);
return f(tmp, meta::load_callback(load)); if constexpr (!Inspector::is_loading) {
if (result)
x.reset(tmp.get());
}
return result;
} }
} // namespace caf } // namespace caf
......
...@@ -75,8 +75,8 @@ struct typed_mpi_access<result<Out...>(In...)> { ...@@ -75,8 +75,8 @@ struct typed_mpi_access<result<Out...>(In...)> {
std::string operator()() const { std::string operator()() const {
static_assert(sizeof...(In) > 0, "typed MPI without inputs"); static_assert(sizeof...(In) > 0, "typed MPI without inputs");
static_assert(sizeof...(Out) > 0, "typed MPI without outputs"); static_assert(sizeof...(Out) > 0, "typed MPI without outputs");
std::vector<std::string> inputs{type_name_v<In>...}; std::vector<std::string> inputs{to_string(type_name_v<In>)...};
std::vector<std::string> outputs1{type_name_v<Out>...}; std::vector<std::string> outputs1{to_string(type_name_v<Out>)...};
std::string result = "("; std::string result = "(";
result += join(inputs, ","); result += join(inputs, ",");
result += ") -> ("; result += ") -> (";
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include "caf/dictionary.hpp" #include "caf/dictionary.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/is_typed_actor.hpp" #include "caf/is_typed_actor.hpp"
#include "caf/named_actor_config.hpp"
#include "caf/settings.hpp" #include "caf/settings.hpp"
#include "caf/stream.hpp" #include "caf/stream.hpp"
#include "caf/thread_hook.hpp" #include "caf/thread_hook.hpp"
...@@ -75,8 +74,6 @@ public: ...@@ -75,8 +74,6 @@ public:
using string_list = std::vector<std::string>; using string_list = std::vector<std::string>;
using named_actor_config_map = hash_map<std::string, named_actor_config>;
using opt_group = config_option_adder; using opt_group = config_option_adder;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -253,9 +250,6 @@ public: ...@@ -253,9 +250,6 @@ public:
// -- utility for caf-run ---------------------------------------------------- // -- utility for caf-run ----------------------------------------------------
// Config parameter for individual actor types.
named_actor_config_map named_actor_configs;
int (*slave_mode_fun)(actor_system&, const actor_system_config&); int (*slave_mode_fun)(actor_system&, const actor_system_config&);
// -- default error rendering functions -------------------------------------- // -- default error rendering functions --------------------------------------
......
...@@ -70,7 +70,6 @@ ...@@ -70,7 +70,6 @@
#include "caf/fused_downstream_manager.hpp" #include "caf/fused_downstream_manager.hpp"
#include "caf/group.hpp" #include "caf/group.hpp"
#include "caf/hash/fnv.hpp" #include "caf/hash/fnv.hpp"
#include "caf/index_mapping.hpp"
#include "caf/init_global_meta_objects.hpp" #include "caf/init_global_meta_objects.hpp"
#include "caf/local_actor.hpp" #include "caf/local_actor.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
...@@ -106,7 +105,6 @@ ...@@ -106,7 +105,6 @@
#include "caf/term.hpp" #include "caf/term.hpp"
#include "caf/thread_hook.hpp" #include "caf/thread_hook.hpp"
#include "caf/timeout_definition.hpp" #include "caf/timeout_definition.hpp"
#include "caf/to_string.hpp"
#include "caf/tracing_data.hpp" #include "caf/tracing_data.hpp"
#include "caf/tracing_data_factory.hpp" #include "caf/tracing_data_factory.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
......
...@@ -26,21 +26,16 @@ ...@@ -26,21 +26,16 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error_code.hpp" #include "caf/error_code.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/load_inspector.hpp"
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/write_inspector.hpp"
namespace caf { namespace caf {
/// Deserializes objects from sequence of bytes. /// Deserializes objects from sequence of bytes.
class CAF_CORE_EXPORT binary_deserializer class CAF_CORE_EXPORT binary_deserializer : public load_inspector {
: public write_inspector<binary_deserializer> {
public: public:
// -- member types -----------------------------------------------------------
using result_type = error_code<sec>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
template <class Container> template <class Container>
...@@ -87,7 +82,7 @@ public: ...@@ -87,7 +82,7 @@ public:
/// Jumps `num_bytes` forward. /// Jumps `num_bytes` forward.
/// @pre `num_bytes <= remaining()` /// @pre `num_bytes <= remaining()`
void skip(size_t num_bytes) noexcept; void skip(size_t num_bytes);
/// Assigns a new input. /// Assigns a new input.
void reset(span<const byte> bytes) noexcept; void reset(span<const byte> bytes) noexcept;
...@@ -102,56 +97,92 @@ public: ...@@ -102,56 +97,92 @@ public:
return end_; return end_;
} }
static constexpr bool has_human_readable_format() noexcept {
return false;
}
// -- overridden member functions -------------------------------------------- // -- overridden member functions --------------------------------------------
result_type begin_object(type_id_t& type); constexpr bool begin_object(string_view) noexcept {
return ok;
}
result_type end_object() noexcept; constexpr bool end_object() noexcept {
return ok;
}
result_type begin_sequence(size_t& list_size) noexcept; constexpr bool begin_field(string_view) noexcept {
return true;
}
result_type end_sequence() noexcept; bool begin_field(string_view name, bool& is_present) noexcept;
result_type apply(bool&) noexcept; bool begin_field(string_view name, span<const type_id_t> types,
size_t& index) noexcept;
result_type apply(byte&) noexcept; bool begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index) noexcept;
result_type apply(int8_t&) noexcept; constexpr bool end_field() {
return ok;
}
result_type apply(uint8_t&) noexcept; constexpr bool begin_tuple(size_t) noexcept {
return ok;
}
result_type apply(int16_t&) noexcept; constexpr bool end_tuple() noexcept {
return ok;
}
result_type apply(uint16_t&) noexcept; bool begin_sequence(size_t& list_size) noexcept;
result_type apply(int32_t&) noexcept; constexpr bool end_sequence() noexcept {
return ok;
}
result_type apply(uint32_t&) noexcept; bool value(bool& x) noexcept;
result_type apply(int64_t&) noexcept; bool value(byte& x) noexcept;
result_type apply(uint64_t&) noexcept; bool value(uint8_t& x) noexcept;
result_type apply(float&) noexcept; bool value(int8_t& x) noexcept;
result_type apply(double&) noexcept; bool value(int16_t& x) noexcept;
result_type apply(long double&); bool value(uint16_t& x) noexcept;
result_type apply(span<byte>) noexcept; bool value(int32_t& x) noexcept;
result_type apply(std::string&); bool value(uint32_t& x) noexcept;
result_type apply(std::u16string&); bool value(int64_t& x) noexcept;
result_type apply(std::u32string&); bool value(uint64_t& x) noexcept;
template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>> bool value(float& x) noexcept;
auto apply(Enum& x) noexcept {
return apply(reinterpret_cast<std::underlying_type_t<Enum>&>(x)); bool value(double& x) noexcept;
}
bool value(long double& x);
bool value(std::string& x);
bool value(std::u16string& x);
result_type apply(std::vector<bool>& xs); bool value(std::u32string& x);
bool value(span<byte> x) noexcept;
bool value(std::vector<bool>& x);
// -- DSL entry point --------------------------------------------------------
template <class T>
constexpr auto object(T&) noexcept {
return object_t<binary_deserializer>{type_name_or_anonymous<T>(), this};
}
private: private:
explicit binary_deserializer(actor_system& sys) noexcept; explicit binary_deserializer(actor_system& sys) noexcept;
......
...@@ -31,20 +31,17 @@ ...@@ -31,20 +31,17 @@
#include "caf/detail/squashed_int.hpp" #include "caf/detail/squashed_int.hpp"
#include "caf/error_code.hpp" #include "caf/error_code.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/read_inspector.hpp" #include "caf/save_inspector.hpp"
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
namespace caf { namespace caf {
/// Serializes objects into a sequence of bytes. /// Serializes objects into a sequence of bytes.
class CAF_CORE_EXPORT binary_serializer class CAF_CORE_EXPORT binary_serializer : public save_inspector {
: public read_inspector<binary_serializer> {
public: public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
using result_type = error_code<sec>;
using container_type = byte_buffer; using container_type = byte_buffer;
using value_type = byte; using value_type = byte;
...@@ -81,6 +78,10 @@ public: ...@@ -81,6 +78,10 @@ public:
return write_pos_; return write_pos_;
} }
static constexpr bool has_human_readable_format() noexcept {
return false;
}
// -- position management ---------------------------------------------------- // -- position management ----------------------------------------------------
/// Sets the write position to `offset`. /// Sets the write position to `offset`.
...@@ -95,52 +96,83 @@ public: ...@@ -95,52 +96,83 @@ public:
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
error_code<sec> begin_object(type_id_t type); constexpr bool begin_object(string_view) {
return ok;
}
error_code<sec> end_object(); constexpr bool end_object() {
return ok;
}
error_code<sec> begin_sequence(size_t list_size); constexpr bool begin_field(string_view) noexcept {
return ok;
}
error_code<sec> end_sequence(); bool begin_field(string_view, bool is_present);
void apply(byte x); bool begin_field(string_view, span<const type_id_t> types, size_t index);
void apply(uint8_t x); bool begin_field(string_view, bool is_present, span<const type_id_t> types,
size_t index);
void apply(uint16_t x); constexpr bool end_field() {
return ok;
}
void apply(uint32_t x); constexpr bool begin_tuple(size_t) {
return ok;
}
void apply(uint64_t x); constexpr bool end_tuple() {
return ok;
}
void apply(float x); bool begin_sequence(size_t list_size);
void apply(double x); constexpr bool end_sequence() {
return ok;
}
void apply(long double x); bool value(byte x);
void apply(string_view x); bool value(int8_t x);
void apply(const std::u16string& x); bool value(uint8_t x);
void apply(const std::u32string& x); bool value(int16_t x);
void apply(span<const byte> x); bool value(uint16_t x);
template <class T> bool value(int32_t x);
std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value>
apply(T x) {
using unsigned_type = std::make_unsigned_t<T>;
using squashed_unsigned_type = detail::squashed_int_t<unsigned_type>;
return apply(static_cast<squashed_unsigned_type>(x));
}
template <class Enum> bool value(uint32_t x);
std::enable_if_t<std::is_enum<Enum>::value> apply(Enum x) {
return apply(static_cast<std::underlying_type_t<Enum>>(x));
}
void apply(const std::vector<bool>& x); bool value(int64_t x);
bool value(uint64_t x);
bool value(float x);
bool value(double x);
bool value(long double x);
bool value(string_view x);
bool value(const std::u16string& x);
bool value(const std::u32string& x);
bool value(span<const byte> x);
bool value(const std::vector<bool>& x);
// -- DSL entry point --------------------------------------------------------
template <class T>
constexpr auto object(T&) noexcept {
return object_t<binary_serializer>{type_name_or_anonymous<T>(), this};
}
private: private:
/// Stores the serialized output. /// Stores the serialized output.
......
...@@ -850,8 +850,51 @@ config_value make_config_value_list(Ts&&... xs) { ...@@ -850,8 +850,51 @@ config_value make_config_value_list(Ts&&... xs) {
/// @relates config_value /// @relates config_value
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, config_value& x) { bool inspect(Inspector& f, config_value& x) {
return f(meta::type_name("config_value"), x.get_data()); return f.object(x).fields(f.field("value", x.get_data()));
} }
template <>
struct inspector_access<config_value> {
using wrapped = inspector_access<config_value::variant_type>;
template <class Inspector>
static bool apply_object(Inspector& f, config_value& x) {
return wrapped::apply_object(f, x.get_data());
}
template <class Inspector>
static bool apply_value(Inspector& f, config_value& x) {
return wrapped::apply_value(f, x.get_data());
}
template <class Inspector>
static bool
save_field(Inspector& f, string_view field_name, config_value& x) {
return wrapped::save_field(f, field_name, x.get_data());
}
template <class Inspector, class IsPresent, class Get>
static bool save_field(Inspector& f, string_view field_name,
IsPresent& is_present, Get& get) {
auto get_data = [&get]() -> decltype(auto) { return get().get_data(); };
return wrapped::save_field(f, field_name, is_present, get_data);
}
template <class Inspector, class IsValid, class SyncValue>
static bool load_field(Inspector& f, string_view field_name, config_value& x,
IsValid& is_valid, SyncValue& sync_value) {
return wrapped::load_field(f, field_name, x.get_data(), is_valid,
sync_value);
}
template <class Inspector, class IsValid, class SyncValue, class SetFallback>
static bool load_field(Inspector& f, string_view field_name, config_value& x,
IsValid& is_valid, SyncValue& sync_value,
SetFallback& set_fallback) {
return wrapped::load_field(f, field_name, x.get_data(), is_valid,
sync_value, set_fallback);
}
};
} // namespace caf } // namespace caf
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <tuple> #include <tuple>
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/inspector_access.hpp"
#include "caf/make_copy_on_write.hpp" #include "caf/make_copy_on_write.hpp"
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
...@@ -114,22 +115,6 @@ private: ...@@ -114,22 +115,6 @@ private:
intrusive_cow_ptr<impl> ptr_; intrusive_cow_ptr<impl> ptr_;
}; };
/// @relates cow_tuple
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type
inspect(Inspector& f, const cow_tuple<Ts...>& x) {
return f(x.data());
}
/// @relates cow_tuple
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
inspect(Inspector& f, cow_tuple<Ts...>& x) {
return f(x.unshared());
}
/// Creates a new copy-on-write tuple from given arguments. /// Creates a new copy-on-write tuple from given arguments.
/// @relates cow_tuple /// @relates cow_tuple
template <class... Ts> template <class... Ts>
...@@ -144,4 +129,66 @@ auto get(const cow_tuple<Ts...>& xs) -> decltype(std::get<N>(xs.data())) { ...@@ -144,4 +129,66 @@ auto get(const cow_tuple<Ts...>& xs) -> decltype(std::get<N>(xs.data())) {
return std::get<N>(xs.data()); return std::get<N>(xs.data());
} }
// -- inspection ---------------------------------------------------------------
template <class... Ts>
struct inspector_access<cow_tuple<Ts...>> {
using value_type = cow_tuple<Ts...>;
using wrapped = inspector_access<std::tuple<Ts...>>;
template <class Inspector>
static bool apply_object(Inspector& f, value_type& x) {
if constexpr (Inspector::is_loading)
return wrapped::apply_object(f, x.unshared());
else
return wrapped::apply_object(f, detail::as_mutable_ref(x.data()));
}
template <class Inspector>
static bool apply_value(Inspector& f, value_type& x) {
if constexpr (Inspector::is_loading)
return wrapped::apply_value(f, x.unshared());
else
return wrapped::apply_value(f, detail::as_mutable_ref(x.data()));
}
template <class Inspector>
static bool save_field(Inspector& f, string_view field_name, value_type& x) {
return wrapped::save_field(f, field_name, detail::as_mutable_ref(x.data()));
}
template <class Inspector, class IsPresent, class Get>
static bool save_field(Inspector& f, string_view field_name,
IsPresent& is_present, Get& get) {
if constexpr (std::is_lvalue_reference<decltype(get())>::value){
auto get_data = [&get]() -> decltype(auto) {
return detail::as_mutable_ref(get().data());
};
return wrapped::save_field(f, field_name, is_present, get_data);
} else {
auto get_data = [&get] {
auto tmp = get();
return std::move(tmp.unshared());
};
return wrapped::save_field(f, field_name, is_present, get_data);
}
}
template <class Inspector, class IsValid, class SyncValue>
static bool load_field(Inspector& f, string_view field_name, value_type& x,
IsValid& is_valid, SyncValue& sync_value) {
return wrapped::load_field(f, field_name, x.unshared(), is_valid,
sync_value);
}
template <class Inspector, class IsValid, class SyncValue, class SetFallback>
static bool load_field(Inspector& f, string_view field_name, value_type& x,
IsValid& is_valid, SyncValue& sync_value,
SetFallback& set_fallback) {
return wrapped::load_field(f, field_name, x.unshared(), is_valid,
sync_value, set_fallback);
}
};
} // namespace caf } // namespace caf
...@@ -34,28 +34,23 @@ template <class... Ts> ...@@ -34,28 +34,23 @@ template <class... Ts>
std::string deep_to_string(const Ts&... xs) { std::string deep_to_string(const Ts&... xs) {
std::string result; std::string result;
detail::stringification_inspector f{result}; detail::stringification_inspector f{result};
f(xs...); auto inspect_result = (inspect_object(f, xs) && ...);
static_cast<void>(inspect_result); // Always true.
return result; return result;
} }
/// Wrapper to `deep_to_string` for using the function as an inspector.
struct deep_to_string_t {
using result_type = std::string;
static constexpr bool reads_state = true;
static constexpr bool writes_state = false;
template <class... Ts>
result_type operator()(const Ts&... xs) const {
return deep_to_string(xs...);
}
};
/// Convenience function for `deep_to_string(std::forward_as_tuple(xs...))`. /// Convenience function for `deep_to_string(std::forward_as_tuple(xs...))`.
template <class... Ts> template <class... Ts>
std::string deep_to_string_as_tuple(const Ts&... xs) { std::string deep_to_string_as_tuple(const Ts&... xs) {
return deep_to_string(std::forward_as_tuple(xs...)); return deep_to_string(std::forward_as_tuple(xs...));
} }
/// Wraps `deep_to_string` into a function object.
struct deep_to_string_t {
template <class... Ts>
std::string operator()(const Ts&... xs) const {
return deep_to_string(xs...);
}
};
} // namespace caf } // namespace caf
...@@ -27,19 +27,16 @@ ...@@ -27,19 +27,16 @@
#include "caf/byte.hpp" #include "caf/byte.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/load_inspector.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/write_inspector.hpp" #include "caf/type_id.hpp"
namespace caf { namespace caf {
/// @ingroup TypeSystem /// @ingroup TypeSystem
/// Technology-independent deserialization interface. /// Technology-independent deserialization interface.
class CAF_CORE_EXPORT deserializer : public write_inspector<deserializer> { class CAF_CORE_EXPORT deserializer : public load_inspector {
public: public:
// -- member types -----------------------------------------------------------
using result_type = error;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
explicit deserializer(actor_system& sys) noexcept; explicit deserializer(actor_system& sys) noexcept;
...@@ -54,86 +51,114 @@ public: ...@@ -54,86 +51,114 @@ public:
return context_; return context_;
} }
bool has_human_readable_format() const noexcept {
return has_human_readable_format_;
}
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
/// Begins processing of an object. /// Begins processing of an object.
virtual result_type begin_object(type_id_t& type) = 0; virtual bool begin_object(string_view type) = 0;
/// Ends processing of an object. /// Ends processing of an object.
virtual result_type end_object() = 0; virtual bool end_object() = 0;
virtual bool begin_field(string_view name) = 0;
virtual bool begin_field(string_view, bool& is_present) = 0;
virtual bool
begin_field(string_view name, span<const type_id_t> types, size_t& index)
= 0;
virtual bool begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index)
= 0;
virtual bool end_field() = 0;
/// Begins processing of a fixed-size sequence.
virtual bool begin_tuple(size_t size) = 0;
/// Ends processing of a sequence.
virtual bool end_tuple() = 0;
/// Begins processing of a sequence. /// Begins processing of a sequence.
virtual result_type 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 result_type end_sequence() = 0; virtual bool end_sequence() = 0;
/// 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.
virtual result_type apply(bool& x) = 0; virtual bool value(bool& x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int8_t&) = 0; virtual bool value(int8_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint8_t&) = 0; virtual bool value(uint8_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int16_t&) = 0; virtual bool value(int16_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint16_t&) = 0; virtual bool value(uint16_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int32_t&) = 0; virtual bool value(int32_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint32_t&) = 0; virtual bool value(uint32_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int64_t&) = 0; virtual bool value(int64_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint64_t&) = 0; virtual bool value(uint64_t&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(float&) = 0; virtual bool value(float&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(double&) = 0; virtual bool value(double&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(long double&) = 0; virtual bool value(long double&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(std::string&) = 0; virtual bool value(std::string&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(std::u16string&) = 0; virtual bool value(std::u16string&) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(std::u32string&) = 0; virtual bool value(std::u32string&) = 0;
/// @copydoc apply
template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>>
auto apply(Enum& x) {
return apply(reinterpret_cast<std::underlying_type_t<Enum>&>(x));
}
/// Reads a byte sequence from the input. /// Reads a byte sequence from the input.
/// @param x The byte sequence. /// @param x The byte sequence.
/// @returns A non-zero error code on failure, `sec::success` otherwise. /// @returns A non-zero error code on failure, `sec::success` otherwise.
virtual result_type apply(span<byte> x) = 0; virtual bool value(span<byte> x) = 0;
/// Adds each boolean in `xs` to the output. Derived classes can override this /// Adds each boolean in `xs` to the output. Derived classes can override this
/// member function to pack the booleans, for example to avoid using one byte /// member function to pack the booleans, for example to avoid using one byte
/// for each value in a binary output format. /// for each value in a binary output format.
virtual result_type apply(std::vector<bool>& xs) noexcept; virtual bool value(std::vector<bool>& xs);
// -- DSL entry point --------------------------------------------------------
template <class T>
constexpr auto object(T&) noexcept {
return object_t<deserializer>{type_name_or_anonymous<T>(), this};
}
protected: protected:
/// Provides access to the ::proxy_registry and to the ::actor_system. /// Provides access to the ::proxy_registry and to the ::actor_system.
execution_unit* context_; execution_unit* context_;
/// Configures whether client code should assume human-readable output.
bool has_human_readable_format_ = false;
}; };
} // namespace caf } // namespace caf
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "caf/config_value_adaptor_field.hpp" #include "caf/config_value_adaptor_field.hpp"
#include "caf/config_value_field.hpp" #include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp" #include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
namespace caf::detail { namespace caf::detail {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 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 <chrono>
#include "caf/meta/load_callback.hpp"
namespace caf::detail {
// -- inject `inspect` overloads for some STL types ----------------------------
template <class Inspector, class Rep, class Period>
auto inspect(Inspector& f, std::chrono::duration<Rep, Period>& x) {
if constexpr (Inspector::reads_state) {
return f(x.count());
} else {
auto tmp = Rep{};
auto cb = [&] { x = std::chrono::duration<Rep, Period>{tmp}; };
return f(tmp, meta::load_callback(cb));
}
}
template <class Inspector, class Clock, class Duration>
auto inspect(Inspector& f, std::chrono::time_point<Clock, Duration>& x) {
if constexpr (Inspector::reads_state) {
return f(x.time_since_epoch());
} else {
auto tmp = Duration{};
auto cb = [&] { x = std::chrono::time_point<Clock, Duration>{tmp}; };
return f(tmp, meta::load_callback(cb));
}
}
// -- provide `is_inspectable` trait for metaprogramming -----------------------
/// Checks whether `T` is inspectable by `Inspector`.
template <class Inspector, class T>
class is_inspectable {
private:
template <class U>
static auto sfinae(Inspector& x, U& y) -> decltype(inspect(x, y));
static std::false_type sfinae(Inspector&, ...);
using result_type
= decltype(sfinae(std::declval<Inspector&>(), std::declval<T&>()));
public:
static constexpr bool value
= !std::is_same<result_type, std::false_type>::value;
};
// Pointers are never inspectable.
template <class Inspector, class T>
struct is_inspectable<Inspector, T*> : std::false_type {};
} // namespace caf::detail
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/detail/padded_size.hpp" #include "caf/detail/padded_size.hpp"
#include "caf/detail/stringification_inspector.hpp" #include "caf/detail/stringification_inspector.hpp"
#include "caf/error.hpp" #include "caf/inspector_access.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
namespace caf::detail::default_function { namespace caf::detail::default_function {
...@@ -45,33 +45,34 @@ void default_construct(void* ptr) { ...@@ -45,33 +45,34 @@ void default_construct(void* ptr) {
template <class T> template <class T>
void copy_construct(void* ptr, const void* src) { void copy_construct(void* ptr, const void* src) {
new (ptr) T(*reinterpret_cast<const T*>(src)); new (ptr) T(*static_cast<const T*>(src));
} }
template <class T> template <class T>
error_code<sec> save_binary(caf::binary_serializer& sink, const void* ptr) { bool save_binary(binary_serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr)); return inspect_object(sink, as_mutable_ref(*static_cast<const T*>(ptr)));
} }
template <class T> template <class T>
error_code<sec> load_binary(caf::binary_deserializer& source, void* ptr) { bool load_binary(binary_deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr)); return inspect_object(source, *static_cast<T*>(ptr));
} }
template <class T> template <class T>
caf::error save(caf::serializer& sink, const void* ptr) { bool save(serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr)); return inspect_object(sink, as_mutable_ref(*static_cast<const T*>(ptr)));
} }
template <class T> template <class T>
caf::error load(caf::deserializer& source, void* ptr) { bool load(deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr)); return inspect_object(source, *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};
f(*reinterpret_cast<const T*>(ptr)); auto unused = inspect_object(f, *static_cast<const T*>(ptr));
static_cast<void>(unused);
} }
} // namespace caf::detail::default_function } // namespace caf::detail::default_function
...@@ -79,7 +80,7 @@ void stringify(std::string& buf, const void* ptr) { ...@@ -79,7 +80,7 @@ void stringify(std::string& buf, const void* ptr) {
namespace caf::detail { namespace caf::detail {
template <class T> template <class T>
meta_object make_meta_object(const char* type_name) { meta_object make_meta_object(string_view type_name) {
return { return {
type_name, type_name,
padded_size_v<T>, padded_size_v<T>,
......
...@@ -115,13 +115,13 @@ public: ...@@ -115,13 +115,13 @@ public:
/// @copydoc at /// @copydoc at
const byte* at(size_t index) const noexcept; const byte* at(size_t index) const noexcept;
caf::error save(caf::serializer& sink) const; bool save(caf::serializer& sink) const;
caf::error save(caf::binary_serializer& sink) const; bool save(caf::binary_serializer& sink) const;
caf::error load(caf::deserializer& source); bool load(caf::deserializer& source);
caf::error load(caf::binary_deserializer& source); bool load(caf::binary_deserializer& source);
private: private:
mutable std::atomic<size_t> rc_; mutable std::atomic<size_t> rc_;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/string_view.hpp"
namespace caf::detail { namespace caf::detail {
...@@ -31,7 +32,7 @@ namespace caf::detail { ...@@ -31,7 +32,7 @@ namespace caf::detail {
/// pointers. /// pointers.
struct meta_object { struct meta_object {
/// Stores a human-readable representation of the type's name. /// Stores a human-readable representation of the type's name.
const char* type_name = nullptr; string_view type_name;
/// Stores how many Bytes objects of this type require, including padding for /// Stores how many Bytes objects of this type require, including padding for
/// aligning to `max_align_t`. /// aligning to `max_align_t`.
...@@ -49,36 +50,44 @@ struct meta_object { ...@@ -49,36 +50,44 @@ struct meta_object {
void (*copy_construct)(void*, const void*); void (*copy_construct)(void*, const void*);
/// Applies an object to a binary serializer. /// Applies an object to a binary serializer.
error_code<sec> (*save_binary)(caf::binary_serializer&, const void*); bool (*save_binary)(caf::binary_serializer&, const void*);
/// Applies an object to a binary deserializer. /// Applies an object to a binary deserializer.
error_code<sec> (*load_binary)(caf::binary_deserializer&, void*); bool (*load_binary)(caf::binary_deserializer&, void*);
/// Applies an object to a generic serializer. /// Applies an object to a generic serializer.
caf::error (*save)(caf::serializer&, const void*); bool (*save)(caf::serializer&, const void*);
/// Applies an object to a generic deserializer. /// Applies an object to a generic deserializer.
caf::error (*load)(caf::deserializer&, void*); bool (*load)(caf::deserializer&, void*);
/// Appends a string representation of an object to a buffer. /// Appends a string representation of an object to a buffer.
void (*stringify)(std::string&, const void*); void (*stringify)(std::string&, const void*);
}; };
/// Convenience function for calling `meta.save(sink, obj)`. /// Convenience function for calling `meta.save(sink, obj)`.
CAF_CORE_EXPORT caf::error save(const meta_object& meta, caf::serializer& sink, inline bool save(const meta_object& meta, caf::serializer& sink,
const void* obj); const void* obj) {
return meta.save(sink, obj);
}
/// Convenience function for calling `meta.save_binary(sink, obj)`. /// Convenience function for calling `meta.save_binary(sink, obj)`.
CAF_CORE_EXPORT caf::error_code<sec> inline bool save(const meta_object& meta, caf::binary_serializer& sink,
save(const meta_object& meta, caf::binary_serializer& sink, const void* obj); const void* obj) {
return meta.save_binary(sink, obj);
}
/// Convenience function for calling `meta.load(source, obj)`. /// Convenience function for calling `meta.load(source, obj)`.
CAF_CORE_EXPORT caf::error load(const meta_object& meta, inline bool load(const meta_object& meta, caf::deserializer& source,
caf::deserializer& source, void* obj); void* obj) {
return meta.load(source, obj);
}
/// Convenience function for calling `meta.load_binary(source, obj)`. /// Convenience function for calling `meta.load_binary(source, obj)`.
CAF_CORE_EXPORT caf::error_code<sec> inline bool load(const meta_object& meta, caf::binary_deserializer& source,
load(const meta_object& meta, caf::binary_deserializer& source, void* obj); void* obj) {
return meta.load_binary(source, obj);
}
/// Returns the global storage for all meta objects. The ::type_id of an object /// Returns the global storage for all meta objects. The ::type_id of an object
/// is the index for accessing the corresonding meta object. /// is the index for accessing the corresonding meta object.
......
...@@ -34,65 +34,81 @@ public: ...@@ -34,65 +34,81 @@ public:
return result_; return result_;
} }
result_type begin_object(type_id_t) override; bool begin_object(string_view) override;
result_type end_object() override; bool end_object() override;
result_type begin_sequence(size_t num) override; bool begin_field(string_view) override;
result_type end_sequence() override; bool begin_field(string_view, bool is_present) override;
result_type apply(bool x) override; bool begin_field(string_view, span<const type_id_t> types,
size_t index) override;
result_type apply(int8_t x) override; bool begin_field(string_view, bool is_present, span<const type_id_t> types,
size_t index) override;
result_type apply(uint8_t x) override; bool end_field() override;
result_type apply(int16_t x) override; bool begin_tuple(size_t size) override;
result_type apply(uint16_t x) override; bool end_tuple() override;
result_type apply(int32_t x) override; bool begin_sequence(size_t size) override;
result_type apply(uint32_t x) override; bool end_sequence() override;
result_type apply(int64_t x) override; bool value(bool x) override;
result_type apply(uint64_t x) override; bool value(int8_t x) override;
result_type apply(float x) override; bool value(uint8_t x) override;
result_type apply(double x) override; bool value(int16_t x) override;
result_type apply(long double x) override; bool value(uint16_t x) override;
result_type apply(string_view x) override; bool value(int32_t x) override;
result_type apply(const std::u16string& x) override; bool value(uint32_t x) override;
result_type apply(const std::u32string& x) override; bool value(int64_t x) override;
result_type apply(span<const byte> x) override; bool value(uint64_t x) override;
result_type apply(const std::vector<bool>& xs) 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;
bool value(const std::vector<bool>& xs) override;
private: private:
size_t result_ = 0; size_t result_ = 0;
}; };
template <class T> template <class T>
size_t serialized_size(actor_system& sys, const T& x) { size_t serialized_size(const T& x) {
serialized_size_inspector f{sys}; serialized_size_inspector f;
auto err = f(x); auto inspection_res = inspect_object(f, x);
static_cast<void>(err); static_cast<void>(inspection_res); // Always true.
return f.result(); return f.result();
} }
template <class T> template <class T>
size_t serialized_size(const T& x) { size_t serialized_size(actor_system& sys, const T& x) {
serialized_size_inspector f{nullptr}; serialized_size_inspector f{sys};
auto err = f(x); auto inspection_res = inspect_object(f, x);
static_cast<void>(err); static_cast<void>(inspection_res); // Always true.
return f.result(); return f.result();
} }
......
...@@ -19,38 +19,24 @@ ...@@ -19,38 +19,24 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#include <functional>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <vector>
#include "caf/detail/append_hex.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/inspect.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/annotation.hpp" #include "caf/inspector_access.hpp"
#include "caf/meta/hex_formatted.hpp" #include "caf/save_inspector.hpp"
#include "caf/meta/omittable.hpp"
#include "caf/meta/omittable_if_empty.hpp"
#include "caf/meta/omittable_if_none.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/none.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/timespan.hpp" #include "caf/timespan.hpp"
#include "caf/timestamp.hpp" #include "caf/timestamp.hpp"
namespace caf::detail { namespace caf::detail {
class CAF_CORE_EXPORT stringification_inspector { class CAF_CORE_EXPORT stringification_inspector : public save_inspector {
public: public:
// -- member types required by Inspector concept ----------------------------- // -- member types -----------------------------------------------------------
using result_type = void; using super = save_inspector;
static constexpr bool reads_state = true;
static constexpr bool writes_state = false;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
...@@ -58,216 +44,92 @@ public: ...@@ -58,216 +44,92 @@ public:
// nop // nop
} }
// -- serializer interface --------------------------------------------------- // -- properties -------------------------------------------------------------
void begin_object(type_id_t) { constexpr bool has_human_readable_format() const noexcept {
// nop return true;
} }
void end_object() { // -- serializer interface ---------------------------------------------------
// nop
}
void begin_sequence(size_t) { bool begin_object(string_view name);
// nop
}
void end_sequence() { bool end_object();
// nop
}
// -- operator() ------------------------------------------------------------- bool begin_field(string_view);
template <class... Ts> bool begin_field(string_view name, bool is_present);
void operator()(Ts&&... xs) {
traverse(xs...);
}
/// Prints a separator to the result string. bool begin_field(string_view name, span<const type_id_t>, size_t);
void sep();
void consume(const timespan& x); bool begin_field(string_view name, bool, span<const type_id_t>, size_t);
void consume(const timestamp& x); bool end_field();
void consume(const bool& x); bool begin_sequence(size_t size);
void consume(const std::vector<bool>& xs); bool end_sequence();
template <class T, size_t N> bool begin_tuple(size_t size);
void consume(const T (&xs)[N]) {
consume_range(xs, xs + N);
}
template <class T> bool end_tuple();
void consume(const T& x) {
if constexpr (std::is_pointer<T>::value) {
consume_ptr(x);
} else if constexpr (std::is_convertible<T, string_view>::value) {
consume_str(string_view{x});
} else if constexpr (std::is_integral<T>::value) {
if constexpr (std::is_signed<T>::value)
consume_int(static_cast<int64_t>(x));
else
consume_int(static_cast<uint64_t>(x));
} else if constexpr (std::is_floating_point<T>::value) {
result_ += std::to_string(x);
} else if constexpr (has_to_string<T>::value) {
result_ += to_string(x);
} else if constexpr (is_inspectable<stringification_inspector, T>::value) {
inspect(*this, const_cast<T&>(x));
} else if constexpr (is_map_like<T>::value) {
result_ += '{';
for (const auto& kvp : x) {
sep();
consume(kvp.first);
result_ += " = ";
consume(kvp.second);
}
result_ += '}';
} else if constexpr (is_iterable<T>::value) {
consume_range(x.begin(), x.end());
} else if constexpr (has_peek_all<T>::value) {
result_ += '[';
x.peek_all(*this);
result_ += ']';
} else {
result_ += "<unprintable>";
}
}
template <class Clock, class Duration> bool value(bool x);
void consume(const std::chrono::time_point<Clock, Duration>& x) {
timestamp tmp{std::chrono::duration_cast<timespan>(x.time_since_epoch())};
consume(tmp);
}
template <class Rep, class Period> template <class Integral>
void consume(const std::chrono::duration<Rep, Period>& x) { std::enable_if_t<std::is_integral<Integral>::value, bool> value(Integral x) {
auto tmp = std::chrono::duration_cast<timespan>(x); if constexpr (std::is_signed<Integral>::value)
consume(tmp); return int_value(static_cast<int64_t>(x));
else
return int_value(static_cast<uint64_t>(x));
} }
// Unwrap std::ref. bool value(float x);
template <class T>
void consume(const std::reference_wrapper<T>& x) {
return consume(x.get());
}
template <class F, class S> bool value(double x);
void consume(const std::pair<F, S>& x) {
result_ += '(';
traverse(x.first, x.second);
result_ += ')';
}
template <class... Ts> bool value(long double x);
void consume(const std::tuple<Ts...>& x) {
result_ += '(';
apply_args(*this, get_indices(x), x);
result_ += ')';
}
void traverse() { bool value(string_view x);
// end of recursion
}
template <class T, class... Ts> bool value(const std::u16string& x);
void traverse(const meta::hex_formatted_t&, const T& x, const Ts&... xs) {
sep();
if constexpr (std::is_integral<T>::value) {
append_hex(result_, x);
} else {
static_assert(sizeof(typename T::value_type) == 1);
append_hex(result_, x.data(), x.size());
}
traverse(xs...);
}
template <class T, class... Ts> bool value(const std::u32string& x);
void traverse(const meta::omittable_if_none_t&, const T& x, const Ts&... xs) {
if (x != none) {
sep();
consume(x);
}
traverse(xs...);
}
template <class T, class... Ts>
void
traverse(const meta::omittable_if_empty_t&, const T& x, const Ts&... xs) {
if (!x.empty()) {
sep();
consume(x);
}
traverse(xs...);
}
template <class T, class... Ts> template <class T>
void traverse(const meta::omittable_t&, const T&, const Ts&... xs) { std::enable_if_t<has_to_string<T>::value, bool> value(const T& x) {
traverse(xs...); auto str = to_string(x);
append(str);
return true;
} }
template <class... Ts> template <class T>
void traverse(const meta::type_name_t& x, const Ts&... xs) { void append(T&& str) {
sep(); sep();
result_ += x.value; result_.insert(result_.end(), str.begin(), str.end());
result_ += '(';
traverse(xs...);
result_ += ')';
} }
template <class... Ts> template <class T>
void traverse(const meta::annotation&, const Ts&... xs) { bool opaque_value(const T&) {
traverse(xs...); result_ += "<unprintable>";
} return true;
template <class T, class... Ts>
enable_if_t<!meta::is_annotation<T>::value && !is_callable<T>::value>
traverse(const T& x, const Ts&... xs) {
sep();
consume(x);
traverse(xs...);
} }
template <class T, class... Ts>
enable_if_t<!meta::is_annotation<T>::value && is_callable<T>::value>
traverse(const T&, const Ts&... xs) {
sep();
result_ += "<fun>";
traverse(xs...);
}
private: // -- DSL entry point --------------------------------------------------------
template <class Iterator>
void consume_range(Iterator first, Iterator last) {
result_ += '[';
while (first != last) {
sep();
consume(*first++);
}
result_ += ']';
}
template <class T> template <class Object>
void consume_ptr(const T* ptr) { constexpr auto object(Object&) noexcept {
if (ptr) { using wrapper_type = object_t<stringification_inspector>;
result_ += '*'; return wrapper_type{type_name_or_anonymous<Object>(), this};
consume(*ptr);
} else {
result_ += "nullptr";
}
} }
void consume_str(string_view str); private:
bool int_value(int64_t x);
void consume_ptr(const void* ptr);
void consume_ptr(const char* cstr);
void consume_int(int64_t x); bool int_value(uint64_t x);
void consume_int(uint64_t x); void sep();
std::string& result_; std::string& result_;
}; };
......
...@@ -67,6 +67,9 @@ ...@@ -67,6 +67,9 @@
namespace caf::detail { namespace caf::detail {
template <class T>
constexpr T* null_v = nullptr;
// -- backport of C++14 additions ---------------------------------------------- // -- backport of C++14 additions ----------------------------------------------
template <class T> template <class T>
...@@ -651,12 +654,44 @@ struct is_map_like { ...@@ -651,12 +654,44 @@ struct is_map_like {
template <class T> template <class T>
constexpr bool is_map_like_v = is_map_like<T>::value; constexpr bool is_map_like_v = is_map_like<T>::value;
template <class T>
struct has_insert {
private:
template <class List>
static auto sfinae(List* l, typename List::value_type* x = nullptr)
-> decltype(l->insert(l->end(), *x), std::true_type());
template <class U>
static auto sfinae(...) -> std::false_type;
using sfinae_type = decltype(sfinae<T>(nullptr));
public:
static constexpr bool value = sfinae_type::value;
};
template <class T>
struct has_size {
private:
template <class List>
static auto sfinae(List* l) -> decltype(l->size(), std::true_type());
template <class U>
static auto sfinae(...) -> std::false_type;
using sfinae_type = decltype(sfinae<T>(nullptr));
public:
static constexpr bool value = sfinae_type::value;
};
/// Checks whether T behaves like `std::vector`, `std::list`, or `std::set`. /// Checks whether T behaves like `std::vector`, `std::list`, or `std::set`.
template <class T> template <class T>
struct is_list_like { struct is_list_like {
static constexpr bool value = is_iterable<T>::value static constexpr bool value = is_iterable<T>::value
&& has_value_type_alias<T>::value && has_value_type_alias<T>::value
&& !has_mapped_type_alias<T>::value; && !has_mapped_type_alias<T>::value
&& has_insert<T>::value && has_size<T>::value;
}; };
template <class T> template <class T>
...@@ -747,6 +782,71 @@ struct is_stl_tuple_type { ...@@ -747,6 +782,71 @@ struct is_stl_tuple_type {
template <class T> template <class T>
constexpr bool is_stl_tuple_type_v = is_stl_tuple_type<T>::value; constexpr bool is_stl_tuple_type_v = is_stl_tuple_type<T>::value;
template <class Inspector>
class has_context {
private:
template <class F>
static auto sfinae(F& f) -> decltype(f.context());
static void sfinae(...);
using result_type = decltype(sfinae(std::declval<Inspector&>()));
public:
static constexpr bool value
= std::is_same<result_type, execution_unit*>::value;
};
/// Checks whether `T` provides an `inspector` overload for `Inspector`.
template <class Inspector, class T>
class is_inspectable {
private:
template <class U>
static auto sfinae(Inspector& x, U& y)
-> decltype(inspect(x, y), std::true_type{});
static std::false_type sfinae(Inspector&, ...);
using result_type
= decltype(sfinae(std::declval<Inspector&>(), std::declval<T&>()));
public:
static constexpr bool value = result_type::value;
};
/// Checks whether the inspector has a `value` overload for `T`.
template <class Inspector, class T>
class is_trivially_inspectable {
private:
template <class U>
static auto sfinae(Inspector& f, U& x)
-> decltype(f.value(x), std::true_type{});
static std::false_type sfinae(Inspector&, ...);
using sfinae_result
= decltype(sfinae(std::declval<Inspector&>(), std::declval<T&>()));
public:
static constexpr bool value = sfinae_result::value;
};
/// Checks whether the inspector has an `opaque_value` overload for `T`.
template <class Inspector, class T>
class accepts_opaque_value {
private:
template <class F, class U>
static auto sfinae(F* f, U* x)
-> decltype(f->opaque_value(*x), std::true_type{});
static std::false_type sfinae(...);
using sfinae_result = decltype(sfinae(null_v<Inspector>, null_v<T>));
public:
static constexpr bool value = sfinae_result::value;
};
} // namespace caf::detail } // namespace caf::detail
#undef CAF_HAS_MEMBER_TRAIT #undef CAF_HAS_MEMBER_TRAIT
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 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 <atomic>
#include <cstdint>
#include <string>
#include <utility>
#include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/ref_counted.hpp"
#include "caf/string_view.hpp"
#include "caf/uri.hpp"
namespace caf::detail {
class CAF_CORE_EXPORT uri_impl {
public:
// -- constructors, destructors, and assignment operators --------------------
uri_impl();
uri_impl(const uri_impl&) = delete;
uri_impl& operator=(const uri_impl&) = delete;
// -- member variables -------------------------------------------------------
static uri_impl default_instance;
/// Null-terminated buffer for holding the string-representation of the URI.
std::string str;
/// Scheme component.
std::string scheme;
/// Assembled authority component.
uri::authority_type authority;
/// Path component.
std::string path;
/// Query component as key-value pairs.
uri::query_map query;
/// The fragment component.
std::string fragment;
// -- properties -------------------------------------------------------------
bool valid() const noexcept {
return !scheme.empty() && (!authority.empty() || !path.empty());
}
// -- modifiers --------------------------------------------------------------
/// Assembles the human-readable string representation for this URI.
void assemble_str();
// -- friend functions -------------------------------------------------------
friend CAF_CORE_EXPORT void intrusive_ptr_add_ref(const uri_impl* p);
friend CAF_CORE_EXPORT void intrusive_ptr_release(const uri_impl* p);
private:
// -- member variables -------------------------------------------------------
mutable std::atomic<size_t> rc_;
};
// -- related free functions -------------------------------------------------
/// @relates uri_impl
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri_impl& x) {
auto load = [&] {
x.str.clear();
if (x.valid())
x.assemble_str();
};
return f(x.scheme, x.authority, x.path, x.query, x.fragment,
meta::load_callback(load));
}
} // namespace caf::detail
...@@ -35,39 +35,45 @@ ...@@ -35,39 +35,45 @@
namespace caf { namespace caf {
/// Stream messages that travel downstream, i.e., batches and close messages. /// Transmits stream data.
struct CAF_CORE_EXPORT downstream_msg : tag::boxing_type { struct downstream_msg_batch {
// -- nested types ----------------------------------------------------------- /// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
/// Size of the type-erased vector<T> (used credit).
int32_t xs_size;
/// A type-erased vector<T> containing the elements of the batch.
message xs;
/// ID of this batch (ascending numbering).
int64_t id;
};
/// Transmits stream data. /// Orderly shuts down a stream after receiving an ACK for the last batch.
struct batch { struct downstream_msg_close {
/// Allows the testing DSL to unbox this type automagically. /// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg; using outer_type = downstream_msg;
};
/// Size of the type-erased vector<T> (used credit). /// Propagates a fatal error from sources to sinks.
int32_t xs_size; struct downstream_msg_forced_close {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
/// A type-erased vector<T> containing the elements of the batch. /// Reason for shutting down the stream.
message xs; error reason;
};
/// ID of this batch (ascending numbering). /// Stream messages that travel downstream, i.e., batches and close messages.
int64_t id; struct CAF_CORE_EXPORT downstream_msg : tag::boxing_type {
}; // -- nested types -----------------------------------------------------------
/// Orderly shuts down a stream after receiving an ACK for the last batch. using batch = downstream_msg_batch;
struct close {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
};
/// Propagates a fatal error from sources to sinks. using close = downstream_msg_close;
struct forced_close {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
/// Reason for shutting down the stream. using forced_close = downstream_msg_forced_close;
error reason;
};
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
...@@ -129,28 +135,33 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) { ...@@ -129,28 +135,33 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) {
/// @relates downstream_msg::batch /// @relates downstream_msg::batch
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, downstream_msg::batch& x) {
inspect(Inspector& f, downstream_msg::batch& x) { return f.object(x).pretty_name("batch").fields(f.field("size", x.xs_size),
return f(meta::type_name("batch"), meta::omittable(), x.xs_size, x.xs, x.id); f.field("xs", x.xs),
f.field("id", x.id));
} }
/// @relates downstream_msg::close /// @relates downstream_msg::close
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, downstream_msg::close&) { bool inspect(Inspector& f, downstream_msg::close& x) {
return f(meta::type_name("close")); return f.object(x).pretty_name("close").fields();
} }
/// @relates downstream_msg::forced_close /// @relates downstream_msg::forced_close
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, downstream_msg::forced_close& x) {
inspect(Inspector& f, downstream_msg::forced_close& x) { return f.object(x)
return f(meta::type_name("forced_close"), x.reason); .pretty_name("forced_close")
.fields(f.field("reason", x.reason));
} }
/// @relates downstream_msg /// @relates downstream_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, downstream_msg& x) { bool inspect(Inspector& f, downstream_msg& x) {
return f(meta::type_name("downstream_msg"), x.slots, x.sender, x.content); return f.object(x)
.pretty_name("downstream_msg")
.fields(f.field("slots", x.slots), f.field("sender", x.sender),
f.field("content", x.content));
} }
} // namespace caf } // namespace caf
...@@ -26,12 +26,9 @@ ...@@ -26,12 +26,9 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/error_code.hpp" #include "caf/error_code.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/inspector_access.hpp"
#include "caf/is_error_code_enum.hpp" #include "caf/is_error_code_enum.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/meta/omittable_if_empty.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
...@@ -67,6 +64,21 @@ namespace caf { ...@@ -67,6 +64,21 @@ namespace caf {
/// instead. /// instead.
class CAF_CORE_EXPORT error : detail::comparable<error> { class CAF_CORE_EXPORT error : detail::comparable<error> {
public: public:
// -- nested classes ---------------------------------------------------------
struct data {
uint8_t code;
type_id_t category;
message context;
template <class Inspector>
friend bool inspect(Inspector& f, data& x) {
return f.object(x).fields(f.field("code", x.code),
f.field("category", x.category),
f.field("context", x.context));
}
};
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
error() noexcept = default; error() noexcept = default;
...@@ -139,6 +151,11 @@ public: ...@@ -139,6 +151,11 @@ public:
return data_ == nullptr; return data_ == nullptr;
} }
/// Returns whether this error was default-constructed.
bool empty() const noexcept {
return data_ == nullptr;
}
int compare(const error&) const noexcept; int compare(const error&) const noexcept;
int compare(uint8_t code, type_id_t category) const noexcept; int compare(uint8_t code, type_id_t category) const noexcept;
...@@ -162,31 +179,8 @@ public: ...@@ -162,31 +179,8 @@ public:
// -- friend functions ------------------------------------------------------- // -- friend functions -------------------------------------------------------
template <class Inspector> template <class Inspector>
friend auto inspect(Inspector& f, error& x) { friend bool inspect(Inspector& f, error& x) {
using result_type = typename Inspector::result_type; return f.object(x).fields(f.field("data", x.data_));
if constexpr (Inspector::reads_state) {
if (!x) {
uint8_t code = 0;
return f(code);
}
return f(x.code(), x.category(), x.context());
} else {
uint8_t code = 0;
auto cb = meta::load_callback([&] {
if (code == 0) {
x.data_.reset();
if constexpr (std::is_same<result_type, void>::value)
return;
else
return result_type{};
}
if (!x.data_)
x.data_.reset(new data);
x.data_->code = code;
return f(x.data_->category, x.data_->context);
});
return f(code, cb);
}
} }
private: private:
...@@ -196,19 +190,17 @@ private: ...@@ -196,19 +190,17 @@ private:
error(uint8_t code, type_id_t category, message context); error(uint8_t code, type_id_t category, message context);
// -- nested classes ---------------------------------------------------------
struct data {
uint8_t code;
type_id_t category;
message context;
};
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
std::unique_ptr<data> data_; std::unique_ptr<data> data_;
}; };
template <>
struct inspector_access<std::unique_ptr<error::data>>
: optional_inspector_access<std::unique_ptr<error::data>> {
// nop
};
/// @relates error /// @relates error
CAF_CORE_EXPORT std::string to_string(const error& x); CAF_CORE_EXPORT std::string to_string(const error& x);
......
...@@ -46,7 +46,6 @@ template <class> class stream_source; ...@@ -46,7 +46,6 @@ template <class> class stream_source;
template <class> class weak_intrusive_ptr; template <class> class weak_intrusive_ptr;
template <class> struct inspector_access; template <class> struct inspector_access;
template <class> struct inspector_access_traits;
template <class> struct timeout_definition; template <class> struct timeout_definition;
template <class> struct type_id; template <class> struct type_id;
...@@ -83,6 +82,7 @@ template <class...> class variant; ...@@ -83,6 +82,7 @@ template <class...> class variant;
// -- classes ------------------------------------------------------------------ // -- classes ------------------------------------------------------------------
class [[nodiscard]] error;
class abstract_actor; class abstract_actor;
class abstract_group; class abstract_group;
class actor; class actor;
...@@ -108,12 +108,12 @@ class config_value; ...@@ -108,12 +108,12 @@ class config_value;
class deserializer; class deserializer;
class downstream_manager; class downstream_manager;
class downstream_manager_base; class downstream_manager_base;
class [[nodiscard]] error;
class event_based_actor; class event_based_actor;
class execution_unit; class execution_unit;
class forwarding_actor_proxy; class forwarding_actor_proxy;
class group; class group;
class group_module; class group_module;
class hashed_node_id;
class inbound_path; class inbound_path;
class ipv4_address; class ipv4_address;
class ipv4_endpoint; class ipv4_endpoint;
...@@ -128,6 +128,7 @@ class message_builder; ...@@ -128,6 +128,7 @@ class message_builder;
class message_handler; class message_handler;
class message_id; class message_id;
class node_id; class node_id;
class node_id_data;
class outbound_path; class outbound_path;
class proxy_registry; class proxy_registry;
class ref_counted; class ref_counted;
...@@ -156,18 +157,26 @@ class stateful_actor; ...@@ -156,18 +157,26 @@ class stateful_actor;
struct down_msg; struct down_msg;
struct downstream_msg; struct downstream_msg;
struct downstream_msg_batch;
struct downstream_msg_close;
struct downstream_msg_forced_close;
struct exit_msg; struct exit_msg;
struct group_down_msg; struct group_down_msg;
struct illegal_message_element; struct illegal_message_element;
struct invalid_actor_addr_t; struct invalid_actor_addr_t;
struct invalid_actor_t; struct invalid_actor_t;
struct node_down_msg; struct node_down_msg;
struct none_t;
struct open_stream_msg; struct open_stream_msg;
struct prohibit_top_level_spawn_marker; struct prohibit_top_level_spawn_marker;
struct stream_slots; struct stream_slots;
struct timeout_msg; struct timeout_msg;
struct unit_t; struct unit_t;
struct upstream_msg; struct upstream_msg;
struct upstream_msg_ack_batch;
struct upstream_msg_ack_open;
struct upstream_msg_drop;
struct upstream_msg_forced_drop;
// -- free template functions -------------------------------------------------- // -- free template functions --------------------------------------------------
...@@ -352,14 +361,9 @@ class dynamic_message_data; ...@@ -352,14 +361,9 @@ class dynamic_message_data;
class group_manager; class group_manager;
class message_data; class message_data;
class private_thread; class private_thread;
class uri_impl;
struct meta_object; struct meta_object;
// enable intrusive_ptr<uri_impl> with forward declaration only
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const uri_impl*);
CAF_CORE_EXPORT void intrusive_ptr_release(const uri_impl*);
// enable intrusive_cow_ptr<dynamic_message_data> with forward declaration only // enable intrusive_cow_ptr<dynamic_message_data> with forward declaration only
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*); CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*);
CAF_CORE_EXPORT void intrusive_ptr_release(const dynamic_message_data*); CAF_CORE_EXPORT void intrusive_ptr_release(const dynamic_message_data*);
......
...@@ -80,14 +80,6 @@ public: ...@@ -80,14 +80,6 @@ public:
return ptr_ ? 1 : 0; return ptr_ ? 1 : 0;
} }
friend CAF_CORE_EXPORT error inspect(serializer&, group&);
friend CAF_CORE_EXPORT error_code<sec> inspect(binary_serializer&, group&);
friend CAF_CORE_EXPORT error inspect(deserializer&, group&);
friend CAF_CORE_EXPORT error_code<sec> inspect(binary_deserializer&, group&);
abstract_group* get() const noexcept { abstract_group* get() const noexcept {
return ptr_.get(); return ptr_.get();
} }
...@@ -122,6 +114,42 @@ public: ...@@ -122,6 +114,42 @@ public:
return this; return this;
} }
template <class Inspector>
friend bool inspect(Inspector& f, group& x) {
std::string module_name;
std::string group_name;
actor dispatcher;
if constexpr (!Inspector::is_loading) {
if (x) {
module_name = x.get()->module().name();
group_name = x.get()->identifier();
dispatcher = x.get()->dispatcher();
}
}
auto load_cb = [&] {
if constexpr (detail::has_context<Inspector>::value) {
auto ctx = f.context();
if (ctx != nullptr) {
if (auto grp = ctx->system().groups().get(module_name, group_name,
dispatcher)) {
x = std::move(*grp);
return true;
} else {
f.set_error(std::move(grp.error()));
return false;
}
}
}
f.emplace_error(sec::no_context);
return false;
};
return f.object(x)
.on_load(load_cb) //
.fields(f.field("module_name", module_name),
f.field("group_name", group_name),
f.field("dispatcher", dispatcher));
}
/// @endcond /// @endcond
private: private:
...@@ -140,11 +168,14 @@ CAF_CORE_EXPORT std::string to_string(const group& x); ...@@ -140,11 +168,14 @@ CAF_CORE_EXPORT std::string to_string(const group& x);
} // namespace caf } // namespace caf
namespace std { namespace std {
template <> template <>
struct hash<caf::group> { struct hash<caf::group> {
size_t operator()(const caf::group& x) const { size_t operator()(const caf::group& x) const {
// groups are singleton objects, the address is thus the best possible hash // Groups are singleton objects. Hence, we can simply use the address as
// hash value.
return !x ? 0 : reinterpret_cast<size_t>(x.get()); return !x ? 0 : reinterpret_cast<size_t>(x.get());
} }
}; };
} // namespace std } // namespace std
...@@ -79,6 +79,11 @@ public: ...@@ -79,6 +79,11 @@ public:
/// Returns the module named `name` if it exists, otherwise `none`. /// Returns the module named `name` if it exists, otherwise `none`.
optional<group_module&> get_module(const std::string& x) const; optional<group_module&> get_module(const std::string& x) const;
/// @private
expected<group> get(const std::string& module_name,
const std::string& group_identifier,
const caf::actor& dispatcher) const;
private: private:
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
......
...@@ -52,11 +52,10 @@ public: ...@@ -52,11 +52,10 @@ public:
/// @threadsafe /// @threadsafe
virtual expected<group> get(const std::string& group_name) = 0; virtual expected<group> get(const std::string& group_name) = 0;
/// Loads a group of this module from `source` and stores it in `storage`. /// Returns a pointer to the group associated with the name `group_name`.
virtual error load(deserializer& source, group& storage) = 0; /// @threadsafe
virtual expected<group>
/// Loads a group of this module from `source` and stores it in `storage`. get(const std::string& group_name, const caf::actor& dispatcher) = 0;
virtual error_code<sec> load(binary_deserializer& source, group& storage) = 0;
// -- observers -------------------------------------------------------------- // -- observers --------------------------------------------------------------
......
...@@ -22,9 +22,11 @@ ...@@ -22,9 +22,11 @@
#include <type_traits> #include <type_traits>
#include "caf/detail/ieee_754.hpp" #include "caf/detail/ieee_754.hpp"
#include "caf/read_inspector.hpp" #include "caf/inspector_access.hpp"
#include "caf/save_inspector.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/type_id.hpp"
namespace caf::hash { namespace caf::hash {
...@@ -37,69 +39,119 @@ namespace caf::hash { ...@@ -37,69 +39,119 @@ namespace caf::hash {
/// ///
/// @tparam T One of `uint32_t`, `uint64_t`, or `size_t`. /// @tparam T One of `uint32_t`, `uint64_t`, or `size_t`.
template <class T> template <class T>
class fnv : public read_inspector<fnv<T>> { class fnv : public save_inspector {
public: public:
static_assert(sizeof(T) == 4 || sizeof(T) == 8); static_assert(sizeof(T) == 4 || sizeof(T) == 8);
using result_type = void; using super = save_inspector;
constexpr fnv() noexcept : value(init()) { constexpr fnv() noexcept : result(init()) {
// nop // nop
} }
static constexpr bool has_human_readable_format() noexcept {
return false;
}
constexpr bool begin_object(string_view) {
return true;
}
constexpr bool end_object() {
return true;
}
bool begin_field(string_view) {
return true;
}
bool begin_field(string_view, bool is_present) {
return value(static_cast<uint8_t>(is_present));
}
bool begin_field(string_view, span<const type_id_t>, size_t index) {
return value(index);
}
bool begin_field(string_view, bool is_present, span<const type_id_t>,
size_t index) {
value(static_cast<uint8_t>(is_present));
if (is_present)
value(index);
return true;
}
constexpr bool end_field() {
return true;
}
constexpr bool begin_tuple(size_t) {
return true;
}
constexpr bool end_tuple() {
return true;
}
constexpr bool begin_sequence(size_t) {
return true;
}
constexpr bool end_sequence() {
return true;
}
template <class Integral> template <class Integral>
std::enable_if_t<std::is_integral<Integral>::value> std::enable_if_t<std::is_integral<Integral>::value, bool>
apply(Integral x) noexcept { value(Integral x) noexcept {
auto begin = reinterpret_cast<const uint8_t*>(&x); auto begin = reinterpret_cast<const uint8_t*>(&x);
append(begin, begin + sizeof(Integral)); append(begin, begin + sizeof(Integral));
return true;
} }
void apply(bool x) noexcept { bool value(bool x) noexcept {
auto tmp = static_cast<uint8_t>(x); auto tmp = static_cast<uint8_t>(x);
apply(tmp); return value(tmp);
} }
void apply(float x) noexcept { bool value(float x) noexcept {
apply(detail::pack754(x)); return value(detail::pack754(x));
} }
void apply(double x) noexcept { bool value(double x) noexcept {
apply(detail::pack754(x)); return value(detail::pack754(x));
} }
void apply(string_view x) noexcept { bool value(string_view x) noexcept {
auto begin = reinterpret_cast<const uint8_t*>(x.data()); auto begin = reinterpret_cast<const uint8_t*>(x.data());
append(begin, begin + x.size()); append(begin, begin + x.size());
return true;
} }
void apply(span<const byte> x) noexcept { bool value(span<const byte> x) noexcept {
auto begin = reinterpret_cast<const uint8_t*>(x.data()); auto begin = reinterpret_cast<const uint8_t*>(x.data());
append(begin, begin + x.size()); append(begin, begin + x.size());
return true;
} }
template <class Enum> template <class Object>
std::enable_if_t<std::is_enum<Enum>::value> apply(Enum x) noexcept { constexpr auto object(Object&) noexcept {
return apply(static_cast<std::underlying_type_t<Enum>>(x)); return super::object_t<fnv>{type_name_or_anonymous<Object>(), this};
}
void begin_sequence(size_t) noexcept {
// nop
}
void end_sequence() noexcept {
// nop
} }
/// Convenience function for computing an FNV1a hash value for given /// Convenience function for computing an FNV1a hash value for given
/// arguments in one shot. /// arguments in one shot.
template <class... Ts> template <class... Ts>
static T compute(Ts&&... xs) noexcept { static T compute(Ts&&... xs) noexcept {
using detail::as_mutable_ref;
fnv f; fnv f;
f(std::forward<Ts>(xs)...); auto inspect_result = (inspect_object(f, as_mutable_ref(xs)) && ...);
return f.value; // Discard inspection result: always true.
static_cast<void>(inspect_result);
return f.result;
} }
T value; T result;
private: private:
static constexpr T init() noexcept { static constexpr T init() noexcept {
...@@ -112,10 +164,10 @@ private: ...@@ -112,10 +164,10 @@ private:
void append(const uint8_t* begin, const uint8_t* end) noexcept { void append(const uint8_t* begin, const uint8_t* end) noexcept {
if constexpr (sizeof(T) == 4) if constexpr (sizeof(T) == 4)
while (begin != end) while (begin != end)
value = (*begin++ ^ value) * 0x01000193u; result = (*begin++ ^ result) * 0x01000193u;
else else
while (begin != end) while (begin != end)
value = (*begin++ ^ value) * 1099511628211ull; result = (*begin++ ^ result) * 1099511628211ull;
} }
}; };
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 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 <functional>
#include <string>
#include <tuple>
#include "caf/detail/core_export.hpp"
#include "caf/meta/type_name.hpp"
namespace caf {
/// Marker for representing placeholders at runtime.
struct CAF_CORE_EXPORT index_mapping {
int value;
explicit index_mapping(int x) : value(x) {
// nop
}
template <class T,
class E
= typename std::enable_if<std::is_placeholder<T>::value != 0>::type>
index_mapping(T) : value(std::is_placeholder<T>::value) {
// nop
}
};
inline bool operator==(const index_mapping& x, const index_mapping& y) {
return x.value == y.value;
}
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, index_mapping& x) {
return f(meta::type_name("index_mapping"), x.value);
}
} // namespace caf
This diff is collapsed.
...@@ -21,47 +21,76 @@ ...@@ -21,47 +21,76 @@
#include <type_traits> #include <type_traits>
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
namespace caf { namespace caf {
/// Wraps tag types for static dispatching. /// Wraps tag types for static dispatching.
struct inspector_access_type { struct inspector_access_type {
/// Flags types that provide an `inspect()` overload.
struct inspect {};
/// Flags builtin integral types.
struct integral {};
/// Flags types with builtin support via `.value()`.
struct builtin {};
/// Flags `enum` types.
struct enumeration {};
/// Flags stateless message types. /// Flags stateless message types.
struct empty {}; struct empty {};
/// Flags allowed unsafe message types. /// Flags allowed unsafe message types.
struct unsafe {}; struct unsafe {};
/// Flags builtin integral types.
struct integral {};
/// Flags type with user-defined `inspect` overloads.
struct inspect {};
/// Flags native C array types. /// Flags native C array types.
struct array {}; struct array {};
/// Flags types with `std::tuple`-like API. /// Flags types with `std::tuple`-like API.
struct tuple {}; struct tuple {};
/// Flags type that specialize `inspector_access_boxed_value_traits`.
struct boxed_value {};
/// Flags types with `std::map`-like API. /// Flags types with `std::map`-like API.
struct map {}; struct map {};
/// Flags types with `std::vector`-like API. /// Flags types with `std::vector`-like API.
struct list {}; struct list {};
/// Flags types without any default access.
struct none {};
}; };
/// @relates inspector_access_type /// @relates inspector_access_type
template <class T> template <class Inspector, class T>
constexpr auto guess_inspector_access_type() { constexpr auto guess_inspector_access_type() {
if constexpr (std::is_empty<T>::value) { // User-defined `inspect` overloads always come first.
using namespace detail;
if constexpr (is_inspectable<Inspector, T>::value) {
return inspector_access_type::inspect{};
} else if constexpr (std::is_integral<T>::value) {
return inspector_access_type::integral{};
} else if constexpr (is_trivially_inspectable<Inspector, T>::value) {
return inspector_access_type::builtin{};
} else if constexpr (std::is_enum<T>::value) {
return inspector_access_type::enumeration{};
} else if constexpr (std::is_empty<T>::value) {
return inspector_access_type::empty{}; return inspector_access_type::empty{};
} else if constexpr (is_allowed_unsafe_message_type_v<T>) { } else if constexpr (is_allowed_unsafe_message_type_v<T>) {
return inspector_access_type::unsafe{}; return inspector_access_type::unsafe{};
} else if constexpr (std::is_integral<T>::value) {
return inspector_access_type::integral{};
} else if constexpr (std::is_array<T>::value) { } else if constexpr (std::is_array<T>::value) {
return inspector_access_type::array{}; return inspector_access_type::array{};
} else if constexpr (detail::is_stl_tuple_type_v<T>) { } else if constexpr (is_stl_tuple_type_v<T>) {
return inspector_access_type::tuple{}; return inspector_access_type::tuple{};
} else if constexpr (detail::is_map_like_v<T>) { } else if constexpr (is_map_like_v<T>) {
return inspector_access_type::map{}; return inspector_access_type::map{};
} else { } else if constexpr (is_list_like_v<T>) {
static_assert(detail::is_list_like_v<T>);
return inspector_access_type::list{}; return inspector_access_type::list{};
} else {
return inspector_access_type::none{};
} }
} }
......
...@@ -43,8 +43,9 @@ constexpr bool operator!=(new_round_result x, new_round_result y) { ...@@ -43,8 +43,9 @@ constexpr bool operator!=(new_round_result x, new_round_result y) {
} }
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, new_round_result& x) { bool inspect(Inspector& f, new_round_result& x) {
return f(meta::type_name("new_round_result"), x.consumed_items, x.stop_all); return f.object(x).fields(f.field("consumed_items", x.consumed_items),
f.field("stop_all", x.stop_all));
} }
} // namespace caf::intrusive } // namespace caf::intrusive
...@@ -49,6 +49,8 @@ public: ...@@ -49,6 +49,8 @@ public:
using element_type = T; using element_type = T;
using value_type = T;
using reference = T&; using reference = T&;
using const_reference = const T&; using const_reference = const T&;
...@@ -117,6 +119,11 @@ public: ...@@ -117,6 +119,11 @@ public:
intrusive_ptr_release(old); intrusive_ptr_release(old);
} }
template <class... Ts>
void emplace(Ts&&... xs) {
reset(new T(std::forward<Ts>(xs)...), false);
}
intrusive_ptr& operator=(pointer ptr) noexcept { intrusive_ptr& operator=(pointer ptr) noexcept {
reset(ptr); reset(ptr);
return *this; return *this;
......
...@@ -104,9 +104,8 @@ public: ...@@ -104,9 +104,8 @@ public:
// -- inspection ------------------------------------------------------------- // -- inspection -------------------------------------------------------------
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type friend bool inspect(Inspector& f, ipv4_address& x) {
inspect(Inspector& f, ipv4_address& x) { return f.object(x).fields(f.field("value", x.bits_));
return f(x.bits_);
} }
private: private:
......
...@@ -72,9 +72,9 @@ public: ...@@ -72,9 +72,9 @@ public:
long compare(ipv4_endpoint x) const noexcept; long compare(ipv4_endpoint x) const noexcept;
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type friend bool inspect(Inspector& f, ipv4_endpoint& x) {
inspect(Inspector& f, ipv4_endpoint& x) { return f.object(x).fields(f.field("address", x.address_),
return f(meta::type_name("ipv4_endpoint"), x.address_, x.port_); f.field("port", x.port_));
} }
private: private:
......
...@@ -60,6 +60,14 @@ public: ...@@ -60,6 +60,14 @@ public:
int compare(const ipv4_subnet& other) const noexcept; int compare(const ipv4_subnet& other) const noexcept;
// -- inspection -------------------------------------------------------------
template <class Inspector>
friend bool inspect(Inspector& f, ipv4_subnet& x) {
return f.object(x).fields(f.field("address", x.address_),
f.field("prefix_length", x.prefix_length_));
}
private: private:
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
......
...@@ -116,9 +116,9 @@ public: ...@@ -116,9 +116,9 @@ public:
// -- inspection ------------------------------------------------------------- // -- inspection -------------------------------------------------------------
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type friend bool
inspect(Inspector& f, ipv6_address& x) { inspect(Inspector& f, ipv6_address& x) {
return f(x.bytes_); return f.object(x).fields(f.field("bytes", x.bytes_));
} }
friend CAF_CORE_EXPORT std::string to_string(ipv6_address x); friend CAF_CORE_EXPORT std::string to_string(ipv6_address x);
......
...@@ -82,9 +82,9 @@ public: ...@@ -82,9 +82,9 @@ public:
long compare(ipv4_endpoint x) const noexcept; long compare(ipv4_endpoint x) const noexcept;
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type friend bool inspect(Inspector& f, ipv6_endpoint& x) {
inspect(Inspector& f, ipv6_endpoint& x) { return f.object(x).fields(f.field("address", x.address_),
return f(meta::type_name("ipv6_endpoint"), x.address_, x.port_); f.field("port", x.port_));
} }
private: private:
......
...@@ -90,8 +90,9 @@ public: ...@@ -90,8 +90,9 @@ public:
// -- inspection ------------------------------------------------------------- // -- inspection -------------------------------------------------------------
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, ipv6_subnet& x) { friend bool inspect(Inspector& f, ipv6_subnet& x) {
return f(x.address_, x.prefix_length_); return f.object(x).fields(f.field("address", x.address_),
f.field("prefix_length", x.prefix_length_));
} }
private: private:
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/inspector_access.hpp" #include "caf/inspector_access.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
...@@ -30,7 +32,7 @@ namespace caf { ...@@ -30,7 +32,7 @@ namespace caf {
/// from this class enables the inspector DSL. /// from this class enables the inspector DSL.
/// @note The derived type still needs to provide an `object()` member function /// @note The derived type still needs to provide an `object()` member function
/// for the DSL. /// for the DSL.
class load_inspector { class CAF_CORE_EXPORT load_inspector {
public: public:
// -- constants -------------------------------------------------------------- // -- constants --------------------------------------------------------------
...@@ -44,15 +46,37 @@ public: ...@@ -44,15 +46,37 @@ 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;
/// A load inspector never reads the state of an object. // -- legacy API -------------------------------------------------------------
static constexpr bool reads_state = false; static constexpr bool reads_state = false;
/// A load inspector overrides the state of an object.
static constexpr bool writes_state = true; static constexpr bool writes_state = true;
/// Inspecting objects, fields and values always returns a `bool`.
using result_type = bool; using result_type = bool;
// -- constructors, destructors, and assignment operators --------------------
virtual ~load_inspector();
// -- properties -------------------------------------------------------------
void set_error(error stop_reason) {
err_ = std::move(stop_reason);
}
template <class... Ts>
void emplace_error(Ts&&... xs) {
err_ = make_error(xs...);
}
const error& get_error() const noexcept {
return err_;
}
error&& move_error() noexcept {
return std::move(err_);
}
// -- DSL types for regular fields ------------------------------------------- // -- DSL types for regular fields -------------------------------------------
template <class T, class U, class Predicate> template <class T, class U, class Predicate>
...@@ -247,6 +271,41 @@ public: ...@@ -247,6 +271,41 @@ public:
} }
}; };
template <class Inspector, class LoadCallback>
struct object_with_load_callback_t {
string_view object_name;
Inspector* f;
LoadCallback load_callback;
template <class... Fields>
bool fields(Fields&&... fs) {
using load_callback_result = decltype(load_callback());
if (!(f->begin_object(object_name) && (fs(*f) && ...)))
return false;
if constexpr (std::is_same<load_callback_result, bool>::value) {
if (!load_callback()) {
f->set_error(sec::load_callback_failed);
return false;
}
} else {
if (auto err = load_callback()) {
f->set_error(std::move(err));
return false;
}
}
return f->end_object();
}
auto pretty_name(string_view name) && {
return object_t{name, f};
}
template <class F>
object_with_load_callback_t&& on_save(F&&) && {
return std::move(*this);
}
};
template <class Inspector> template <class Inspector>
struct object_t { struct object_t {
string_view object_name; string_view object_name;
...@@ -260,6 +319,20 @@ public: ...@@ -260,6 +319,20 @@ public:
auto pretty_name(string_view name) && { auto pretty_name(string_view name) && {
return object_t{name, f}; return object_t{name, f};
} }
template <class F>
object_t&& on_save(F&&) && {
return std::move(*this);
}
template <class F>
auto on_load(F fun) && {
return object_with_load_callback_t<Inspector, F>{
object_name,
f,
std::move(fun),
};
}
}; };
// -- factory functions ------------------------------------------------------ // -- factory functions ------------------------------------------------------
...@@ -274,6 +347,9 @@ public: ...@@ -274,6 +347,9 @@ public:
using field_type = std::decay_t<decltype(get())>; using field_type = std::decay_t<decltype(get())>;
return virt_field_t<field_type, Set>{name, set}; return virt_field_t<field_type, Set>{name, set};
} }
protected:
error err_;
}; };
} // namespace caf } // namespace caf
...@@ -106,13 +106,13 @@ public: ...@@ -106,13 +106,13 @@ public:
/// @relates mailbox_element /// @relates mailbox_element
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, mailbox_element& x) { bool inspect(Inspector& f, mailbox_element& x) {
return f(meta::type_name("mailbox_element"), x.sender, x.mid, return f.object(x).fields(f.field("sender", x.sender), f.field("mid", x.mid),
meta::omittable_if_empty(), x.stages, f.field("stages", x.stages),
#ifdef CAF_ENABLE_ACTOR_PROFILER #ifdef CAF_ENABLE_ACTOR_PROFILER
x.tracing_id, f.field("tracing_id", x.tracing_id),
#endif // CAF_ENABLE_ACTOR_PROFILER #endif // CAF_ENABLE_ACTOR_PROFILER
x.payload); f.field("payload", x.payload));
} }
/// @relates mailbox_element /// @relates mailbox_element
......
...@@ -116,13 +116,13 @@ public: ...@@ -116,13 +116,13 @@ public:
// -- serialization ---------------------------------------------------------- // -- serialization ----------------------------------------------------------
error save(serializer& sink) const; bool save(serializer& sink) const;
error_code<sec> save(binary_serializer& sink) const; bool save(binary_serializer& sink) const;
error load(deserializer& source); bool load(deserializer& source);
error_code<sec> load(binary_deserializer& source); bool load(binary_deserializer& source);
// -- element access --------------------------------------------------------- // -- element access ---------------------------------------------------------
...@@ -202,11 +202,13 @@ message make_message(Ts&&... xs) { ...@@ -202,11 +202,13 @@ message make_message(Ts&&... xs) {
return message{std::move(ptr)}; return message{std::move(ptr)};
} }
/// @relates message
template <class Tuple, size_t... Is> template <class Tuple, size_t... Is>
message make_message_from_tuple(Tuple&& xs, std::index_sequence<Is...>) { message make_message_from_tuple(Tuple&& xs, std::index_sequence<Is...>) {
return make_message(std::get<Is>(std::forward<Tuple>(xs))...); return make_message(std::get<Is>(std::forward<Tuple>(xs))...);
} }
/// @relates message
template <class Tuple> template <class Tuple>
message make_message_from_tuple(Tuple&& xs) { message make_message_from_tuple(Tuple&& xs) {
using tuple_type = std::decay_t<Tuple>; using tuple_type = std::decay_t<Tuple>;
...@@ -215,20 +217,20 @@ message make_message_from_tuple(Tuple&& xs) { ...@@ -215,20 +217,20 @@ message make_message_from_tuple(Tuple&& xs) {
} }
/// @relates message /// @relates message
CAF_CORE_EXPORT error inspect(serializer& sink, const message& msg); template <class Inspector>
auto inspect(Inspector& f, message& x)
/// @relates message -> std::enable_if_t<Inspector::is_loading, decltype(x.load(f))> {
CAF_CORE_EXPORT error_code<sec> inspect(binary_serializer& sink, return x.load(f);
const message& msg); }
/// @relates message
CAF_CORE_EXPORT error inspect(deserializer& source, message& msg);
/// @relates message /// @relates message
CAF_CORE_EXPORT error_code<sec> template <class Inspector>
inspect(binary_deserializer& source, message& msg); auto inspect(Inspector& f, message& x)
-> std::enable_if_t<!Inspector::is_loading, decltype(x.save(f))> {
return x.save(f);
}
/// @relates message /// @relates message
CAF_CORE_EXPORT std::string to_string(const message& msg); CAF_CORE_EXPORT std::string to_string(const message& x);
} // namespace caf } // namespace caf
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/message_priority.hpp" #include "caf/message_priority.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
...@@ -191,13 +192,6 @@ public: ...@@ -191,13 +192,6 @@ public:
return *this; return *this;
} }
// -- friend functions ------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, message_id& x) {
return f(meta::type_name("message_id"), x.value_);
}
private: private:
// -- member variables ------------------------------------------------------- // -- member variables -------------------------------------------------------
...@@ -233,6 +227,31 @@ constexpr message_id make_message_id(message_priority p) { ...@@ -233,6 +227,31 @@ constexpr message_id make_message_id(message_priority p) {
return message_id{static_cast<uint64_t>(p) << message_id::category_offset}; return message_id{static_cast<uint64_t>(p) << message_id::category_offset};
} }
// -- inspection support -------------------------------------------------------
template <>
struct inspector_access<message_id> : inspector_access_base<message_id> {
template <class Inspector>
static bool apply_object(Inspector& f, message_id& x) {
auto get = [&x] { return x.integer_value(); };
auto set = [&x](uint64_t val) {
x = message_id{val};
return true;
};
return f.object(x).fields(f.field("value", get, set));
}
template <class Inspector>
static bool apply_value(Inspector& f, message_id& x) {
auto get = [&x] { return x.integer_value(); };
auto set = [&x](uint64_t val) {
x = message_id{val};
return true;
};
return inspect_value(f, get, set);
}
};
} // namespace caf } // namespace caf
namespace std { namespace std {
......
This diff is collapsed.
...@@ -23,9 +23,6 @@ ...@@ -23,9 +23,6 @@
#include <utility> #include <utility>
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/detail/safe_equal.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/unit.hpp" #include "caf/unit.hpp"
...@@ -38,6 +35,8 @@ public: ...@@ -38,6 +35,8 @@ public:
/// Typdef for `T`. /// Typdef for `T`.
using type = T; using type = T;
using value_type = T;
/// Creates an instance without value. /// Creates an instance without value.
optional(const none_t& = none) : m_valid(false) { optional(const none_t& = none) : m_valid(false) {
// nop // nop
...@@ -146,6 +145,22 @@ public: ...@@ -146,6 +145,22 @@ public:
return m_valid ? value() : default_value; return m_valid ? value() : default_value;
} }
void reset() {
destroy();
}
template <class... Ts>
T& emplace(Ts&&... xs) {
if (m_valid) {
m_value.~T();
new (std::addressof(m_value)) T(std::forward<Ts>(xs)...);
} else {
new (std::addressof(m_value)) T(std::forward<Ts>(xs)...);
m_valid = true;
}
return m_value;
}
private: private:
void destroy() { void destroy() {
if (m_valid) { if (m_valid) {
...@@ -267,44 +282,11 @@ private: ...@@ -267,44 +282,11 @@ private:
bool m_value; bool m_value;
}; };
template <class Inspector, class T>
typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type
inspect(Inspector& f, optional<T>& x) {
return x ? f(true, *x) : f(false);
}
template <class T>
struct optional_inspect_helper {
bool& enabled;
T& storage;
template <class Inspector>
friend typename Inspector::result_type
inspect(Inspector& f, optional_inspect_helper& x) {
return x.enabled ? f(x.storage) : f();
}
};
template <class Inspector, class T>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
inspect(Inspector& f, optional<T>& x) {
bool flag = false;
typename optional<T>::type tmp{};
optional_inspect_helper<T> helper{flag, tmp};
auto guard = detail::make_scope_guard([&] {
if (flag)
x = std::move(tmp);
else
x = none;
});
return f(flag, helper);
}
/// @relates optional /// @relates optional
template <class T> template <class T>
std::string to_string(const optional<T>& x) { auto to_string(const optional<T>& x)
return x ? "*" + deep_to_string(*x) : "none"; -> decltype(to_string(std::declval<const T&>())) {
return x ? "*" + to_string(*x) : "null";
} }
/// Returns an rvalue to the value managed by `x`. /// Returns an rvalue to the value managed by `x`.
......
...@@ -178,9 +178,12 @@ public: ...@@ -178,9 +178,12 @@ public:
/// @relates outbound_path /// @relates outbound_path
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, outbound_path& x) { bool inspect(Inspector& f, outbound_path& x) {
return f(meta::type_name("outbound_path"), x.slots, x.hdl, x.next_batch_id, return f.object(x).fields(f.field("slots", x.slots), f.field("hdl", x.hdl),
x.open_credit, x.desired_batch_size, x.next_ack_id); f.field("next_batch_id", x.next_batch_id),
f.field("open_credit", x.open_credit),
f.field("desired_batch_size", x.desired_batch_size),
f.field("next_ack_id", x.next_ack_id));
} }
} // namespace caf } // namespace caf
...@@ -18,7 +18,12 @@ ...@@ -18,7 +18,12 @@
#pragma once #pragma once
#include <utility>
#include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/inspector_access.hpp" #include "caf/inspector_access.hpp"
#include "caf/sec.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
namespace caf { namespace caf {
...@@ -27,7 +32,7 @@ namespace caf { ...@@ -27,7 +32,7 @@ namespace caf {
/// from this class enables the inspector DSL. /// from this class enables the inspector DSL.
/// @note The derived type still needs to provide an `object()` member function /// @note The derived type still needs to provide an `object()` member function
/// for the DSL. /// for the DSL.
class save_inspector { class CAF_CORE_EXPORT save_inspector {
public: public:
// -- constants -------------------------------------------------------------- // -- constants --------------------------------------------------------------
...@@ -41,15 +46,37 @@ public: ...@@ -41,15 +46,37 @@ 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;
/// A save inspector only reads the state of an object. // -- legacy API -------------------------------------------------------------
static constexpr bool reads_state = true; static constexpr bool reads_state = true;
/// A load inspector never modifies the state of an object.
static constexpr bool writes_state = false; static constexpr bool writes_state = false;
/// Inspecting objects, fields and values always returns a `bool`.
using result_type = bool; using result_type = bool;
// -- constructors, destructors, and assignment operators --------------------
virtual ~save_inspector();
// -- properties -------------------------------------------------------------
void set_error(error stop_reason) {
err_ = std::move(stop_reason);
}
template <class... Ts>
void emplace_error(Ts&&... xs) {
err_ = make_error(xs...);
}
const error& get_error() const noexcept {
return err_;
}
error&& move_error() noexcept {
return std::move(err_);
}
// -- DSL types for regular fields ------------------------------------------- // -- DSL types for regular fields -------------------------------------------
template <class T, class U> template <class T, class U>
...@@ -139,6 +166,41 @@ public: ...@@ -139,6 +166,41 @@ public:
} }
}; };
template <class Inspector, class SaveCallback>
struct object_with_save_callback_t {
string_view object_name;
Inspector* f;
SaveCallback save_callback;
template <class... Fields>
bool fields(Fields&&... fs) {
using save_callback_result = decltype(save_callback());
if (!(f->begin_object(object_name) && (fs(*f) && ...)))
return false;
if constexpr (std::is_same<save_callback_result, bool>::value) {
if (!save_callback()) {
f->set_error(sec::save_callback_failed);
return false;
}
} else {
if (auto err = save_callback()) {
f->set_error(std::move(err));
return false;
}
}
return f->end_object();
}
auto pretty_name(string_view name) && {
return object_t{name, f};
}
template <class F>
object_with_save_callback_t&& on_load(F&&) && {
return std::move(*this);
}
};
template <class Inspector> template <class Inspector>
struct object_t { struct object_t {
string_view object_name; string_view object_name;
...@@ -152,6 +214,20 @@ public: ...@@ -152,6 +214,20 @@ public:
auto pretty_name(string_view name) && { auto pretty_name(string_view name) && {
return object_t{name, f}; return object_t{name, f};
} }
template <class F>
object_t&& on_load(F&&) && {
return std::move(*this);
}
template <class F>
auto on_save(F fun) && {
return object_with_save_callback_t<Inspector, F>{
object_name,
f,
std::move(fun),
};
}
}; };
// -- factory functions ------------------------------------------------------ // -- factory functions ------------------------------------------------------
...@@ -166,6 +242,9 @@ public: ...@@ -166,6 +242,9 @@ public:
using field_type = std::decay_t<decltype(get())>; using field_type = std::decay_t<decltype(get())>;
return virt_field_t<field_type, Get>{name, get}; return virt_field_t<field_type, Get>{name, get};
} }
protected:
error err_;
}; };
} // namespace caf } // namespace caf
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/stream_manager.hpp" #include "caf/stream_manager.hpp"
#include "caf/telemetry/timer.hpp" #include "caf/telemetry/timer.hpp"
#include "caf/to_string.hpp"
namespace caf { namespace caf {
......
...@@ -154,6 +154,10 @@ enum class sec : uint8_t { ...@@ -154,6 +154,10 @@ enum class sec : uint8_t {
invalid_field_type, invalid_field_type,
/// Serialization failed because a type was flagged as unsafe message type. /// Serialization failed because a type was flagged as unsafe message type.
unsafe_type, unsafe_type,
/// Serialization failed, because a save callback returned `false`.
save_callback_failed,
/// Deserialization failed, because a load callback returned `false`.
load_callback_failed,
}; };
/// @relates sec /// @relates sec
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/annotation.hpp" #include "caf/meta/annotation.hpp"
#include "caf/meta/save_callback.hpp" #include "caf/meta/save_callback.hpp"
#include "caf/read_inspector.hpp" #include "caf/save_inspector.hpp"
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
...@@ -38,12 +38,8 @@ namespace caf { ...@@ -38,12 +38,8 @@ namespace caf {
/// @ingroup TypeSystem /// @ingroup TypeSystem
/// Technology-independent serialization interface. /// Technology-independent serialization interface.
class CAF_CORE_EXPORT serializer : public read_inspector<serializer> { class CAF_CORE_EXPORT serializer : public save_inspector {
public: public:
// -- member types -----------------------------------------------------------
using result_type = error;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
explicit serializer(actor_system& sys) noexcept; explicit serializer(actor_system& sys) noexcept;
...@@ -58,88 +54,115 @@ public: ...@@ -58,88 +54,115 @@ public:
return context_; return context_;
} }
bool has_human_readable_format() const noexcept {
return has_human_readable_format_;
}
// -- interface functions ---------------------------------------------------- // -- interface functions ----------------------------------------------------
/// Begins processing of an object. Saves the type information /// Begins processing of an object. Saves the type information
/// to the underlying storage. /// to the underlying storage.
virtual result_type begin_object(type_id_t type) = 0; virtual bool begin_object(string_view name) = 0;
/// Ends processing of an object. /// Ends processing of an object.
virtual result_type end_object() = 0; virtual bool end_object() = 0;
virtual bool begin_field(string_view) = 0;
virtual bool begin_field(string_view name, bool is_present) = 0;
virtual bool
begin_field(string_view name, span<const type_id_t> types, size_t index)
= 0;
virtual bool begin_field(string_view name, bool is_present,
span<const type_id_t> types, size_t index)
= 0;
virtual bool end_field() = 0;
/// Begins processing of a sequence. Saves the size /// Begins processing of a tuple.
/// to the underlying storage when in saving mode, otherwise virtual bool begin_tuple(size_t size) = 0;
/// sets `num` accordingly.
virtual result_type begin_sequence(size_t num) = 0; /// Ends processing of a tuple.
virtual bool end_tuple() = 0;
/// Begins processing of a sequence. Saves the size to the underlying storage.
virtual bool begin_sequence(size_t size) = 0;
/// Ends processing of a sequence. /// Ends processing of a sequence.
virtual result_type end_sequence() = 0; virtual bool end_sequence() = 0;
/// 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.
virtual result_type apply(bool x) = 0; virtual bool value(bool x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int8_t x) = 0; virtual bool value(int8_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint8_t x) = 0; virtual bool value(uint8_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int16_t x) = 0; virtual bool value(int16_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint16_t x) = 0; virtual bool value(uint16_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int32_t x) = 0; virtual bool value(int32_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint32_t x) = 0; virtual bool value(uint32_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(int64_t x) = 0; virtual bool value(int64_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(uint64_t x) = 0; virtual bool value(uint64_t x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(float x) = 0; virtual bool value(float x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(double x) = 0; virtual bool value(double x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(long double x) = 0; virtual bool value(long double x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(string_view x) = 0; virtual bool value(string_view x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(const std::u16string& x) = 0; virtual bool value(const std::u16string& x) = 0;
/// @copydoc apply /// @copydoc value
virtual result_type apply(const std::u32string& x) = 0; virtual bool value(const std::u32string& x) = 0;
template <class Enum, class = std::enable_if_t<std::is_enum<Enum>::value>>
auto apply(Enum x) {
return apply(static_cast<std::underlying_type_t<Enum>>(x));
}
/// Adds `x` as raw byte block to the output. /// Adds `x` as raw byte block to the output.
/// @param x The byte sequence. /// @param x The byte sequence.
/// @returns A non-zero error code on failure, `sec::success` otherwise. /// @returns A non-zero error code on failure, `sec::success` otherwise.
virtual result_type apply(span<const byte> x) = 0; virtual bool value(span<const byte> x) = 0;
/// Adds each boolean in `xs` to the output. Derived classes can override this /// Adds each boolean in `xs` to the output. Derived classes can override this
/// member function to pack the booleans, for example to avoid using one byte /// member function to pack the booleans, for example to avoid using one byte
/// for each value in a binary output format. /// for each value in a binary output format.
virtual result_type apply(const std::vector<bool>& xs); virtual bool value(const std::vector<bool>& xs);
// -- DSL entry point --------------------------------------------------------
template <class T>
constexpr auto object(T&) noexcept {
return object_t<serializer>{type_name_or_anonymous<T>(), this};
}
protected: protected:
/// Provides access to the ::proxy_registry and to the ::actor_system. /// Provides access to the ::proxy_registry and to the ::actor_system.
execution_unit* context_; execution_unit* context_;
/// Configures whether client code should assume human-readable output.
bool has_human_readable_format_ = false;
}; };
} // namespace caf } // namespace caf
...@@ -36,8 +36,8 @@ public: ...@@ -36,8 +36,8 @@ public:
/// @relates stream /// @relates stream
template <class Inspector, class T> template <class Inspector, class T>
auto inspect(Inspector& f, stream<T>&) { auto inspect(Inspector& f, stream<T>& x) {
return f(meta::type_name(type_name_v<stream<T>>)); return f.object(x).fields();
} }
} // namespace caf } // namespace caf
...@@ -149,9 +149,8 @@ public: ...@@ -149,9 +149,8 @@ public:
// -- serialization ---------------------------------------------------------- // -- serialization ----------------------------------------------------------
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type friend bool inspect(Inspector& f, outbound_stream_slot& x) {
inspect(Inspector& f, outbound_stream_slot& x) { return f.object(x).fields(f.field("value_", x.value_));
return f(x.value_);
} }
private: private:
...@@ -160,8 +159,9 @@ private: ...@@ -160,8 +159,9 @@ private:
/// @relates stream_slots /// @relates stream_slots
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, stream_slots& x) { bool inspect(Inspector& f, stream_slots& x) {
return f(x.sender, x.receiver); return f.object(x).fields(f.field("sender", x.sender),
f.field("receiver", x.receiver));
} }
} // namespace caf } // namespace caf
...@@ -49,8 +49,9 @@ inline bool operator==(const exit_msg& x, const exit_msg& y) noexcept { ...@@ -49,8 +49,9 @@ inline bool operator==(const exit_msg& x, const exit_msg& y) noexcept {
/// @relates exit_msg /// @relates exit_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, exit_msg& x) { bool inspect(Inspector& f, exit_msg& x) {
return f(meta::type_name("exit_msg"), x.source, x.reason); return f.object(x).fields(f.field("source", x.source),
f.field("reason", x.reason));
} }
/// Sent to all actors monitoring an actor when it is terminated. /// Sent to all actors monitoring an actor when it is terminated.
...@@ -74,8 +75,9 @@ inline bool operator!=(const down_msg& x, const down_msg& y) noexcept { ...@@ -74,8 +75,9 @@ inline bool operator!=(const down_msg& x, const down_msg& y) noexcept {
/// @relates down_msg /// @relates down_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, down_msg& x) { bool inspect(Inspector& f, down_msg& x) {
return f(meta::type_name("down_msg"), x.source, x.reason); return f.object(x).fields(f.field("source", x.source),
f.field("reason", x.reason));
} }
/// Sent to all members of a group when it goes offline. /// Sent to all members of a group when it goes offline.
...@@ -86,8 +88,8 @@ struct group_down_msg { ...@@ -86,8 +88,8 @@ struct group_down_msg {
/// @relates group_down_msg /// @relates group_down_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, group_down_msg& x) { bool inspect(Inspector& f, group_down_msg& x) {
return f(meta::type_name("group_down_msg"), x.source); return f.object(x).fields(f.field("source", x.source));
} }
/// Sent to all actors monitoring a node when CAF loses connection to it. /// Sent to all actors monitoring a node when CAF loses connection to it.
...@@ -114,8 +116,9 @@ inline bool operator!=(const node_down_msg& x, ...@@ -114,8 +116,9 @@ inline bool operator!=(const node_down_msg& x,
/// @relates node_down_msg /// @relates node_down_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, node_down_msg& x) { bool inspect(Inspector& f, node_down_msg& x) {
return f(meta::type_name("node_down_msg"), x.node, x.reason); return f.object(x).fields(f.field("node", x.node),
f.field("reason", x.reason));
} }
/// Signalizes a timeout event. /// Signalizes a timeout event.
...@@ -129,8 +132,9 @@ struct timeout_msg { ...@@ -129,8 +132,9 @@ struct timeout_msg {
/// @relates timeout_msg /// @relates timeout_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, timeout_msg& x) { bool inspect(Inspector& f, timeout_msg& x) {
return f(meta::type_name("timeout_msg"), x.type, x.timeout_id); return f.object(x).fields(f.field("type", x.type),
f.field("timeout_id", x.timeout_id));
} }
/// Demands the receiver to open a new stream from the sender to the receiver. /// Demands the receiver to open a new stream from the sender to the receiver.
...@@ -154,9 +158,12 @@ struct open_stream_msg { ...@@ -154,9 +158,12 @@ struct open_stream_msg {
/// @relates open_stream_msg /// @relates open_stream_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, open_stream_msg& x) { bool inspect(Inspector& f, open_stream_msg& x) {
return f(meta::type_name("open_stream_msg"), x.slot, x.msg, x.prev_stage, return f.object(x).fields(f.field("slot", x.slot), //
x.original_stage, x.priority); f.field("msg", x.msg),
f.field("prev_stage", x.prev_stage),
f.field("original_stage", x.original_stage),
f.field("priority", x.priority));
} }
} // namespace caf } // namespace caf
...@@ -34,27 +34,26 @@ public: ...@@ -34,27 +34,26 @@ public:
virtual ~tracing_data(); virtual ~tracing_data();
/// Writes the content of this object to `sink`. /// Writes the content of this object to `sink`.
virtual error serialize(serializer& sink) const = 0; virtual bool serialize(serializer& sink) const = 0;
/// @copydoc serialize /// @copydoc serialize
virtual error_code<sec> serialize(binary_serializer& sink) const = 0; virtual bool serialize(binary_serializer& sink) const = 0;
}; };
/// @relates tracing_data /// @relates tracing_data
using tracing_data_ptr = std::unique_ptr<tracing_data>; using tracing_data_ptr = std::unique_ptr<tracing_data>;
/// @relates tracing_data /// @relates tracing_data
CAF_CORE_EXPORT error inspect(serializer& sink, const tracing_data_ptr& x); CAF_CORE_EXPORT bool inspect(serializer& sink, const tracing_data_ptr& x);
/// @relates tracing_data /// @relates tracing_data
CAF_CORE_EXPORT error_code<sec> CAF_CORE_EXPORT bool inspect(binary_serializer& sink,
inspect(binary_serializer& sink, const tracing_data_ptr& x); const tracing_data_ptr& x);
/// @relates tracing_data /// @relates tracing_data
CAF_CORE_EXPORT error inspect(deserializer& source, tracing_data_ptr& x); CAF_CORE_EXPORT bool inspect(deserializer& source, tracing_data_ptr& x);
/// @relates tracing_data /// @relates tracing_data
CAF_CORE_EXPORT error_code<sec> CAF_CORE_EXPORT bool inspect(binary_deserializer& source, tracing_data_ptr& x);
inspect(binary_deserializer& source, tracing_data_ptr& x);
} // namespace caf } // namespace caf
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "caf/detail/squashed_int.hpp" #include "caf/detail/squashed_int.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
#include "caf/string_view.hpp"
#include "caf/timespan.hpp" #include "caf/timespan.hpp"
#include "caf/timestamp.hpp" #include "caf/timestamp.hpp"
...@@ -67,7 +68,7 @@ struct type_name_by_id; ...@@ -67,7 +68,7 @@ struct type_name_by_id;
/// Convenience alias for `type_name_by_id<I>::value`. /// Convenience alias for `type_name_by_id<I>::value`.
/// @relates type_name_by_id /// @relates type_name_by_id
template <type_id_t I> template <type_id_t I>
constexpr const char* type_name_by_id_v = type_name_by_id<I>::value; constexpr string_view type_name_by_id_v = type_name_by_id<I>::value;
/// Convenience type that resolves to `type_name_by_id<type_id_v<T>>`. /// Convenience type that resolves to `type_name_by_id<type_id_v<T>>`.
template <class T> template <class T>
...@@ -77,13 +78,13 @@ struct type_name; ...@@ -77,13 +78,13 @@ struct type_name;
/// manually. /// manually.
template <> template <>
struct type_name<void> { struct type_name<void> {
static constexpr const char* value = "void"; static constexpr string_view value = "void";
}; };
/// Convenience alias for `type_name<T>::value`. /// Convenience alias for `type_name<T>::value`.
/// @relates type_name /// @relates type_name
template <class T> template <class T>
constexpr const char* type_name_v = type_name<T>::value; constexpr string_view type_name_v = type_name<T>::value;
/// The first type ID not reserved by CAF and its modules. /// The first type ID not reserved by CAF and its modules.
constexpr type_id_t first_custom_type_id = 200; constexpr type_id_t first_custom_type_id = 200;
...@@ -98,6 +99,15 @@ struct has_type_id { ...@@ -98,6 +99,15 @@ struct has_type_id {
static constexpr bool value = detail::is_complete<type_id<T>>; static constexpr bool value = detail::is_complete<type_id<T>>;
}; };
/// Returns `type_name_v<T>` if available, "anonymous" otherwise.
template <class T>
string_view type_name_or_anonymous() {
if constexpr (has_type_id<T>)
return type_name_v<T>;
else
return "anonymous";
}
} // namespace caf } // namespace caf
/// Starts a code block for registering custom types to CAF. Stores the first ID /// Starts a code block for registering custom types to CAF. Stores the first ID
...@@ -133,7 +143,7 @@ struct has_type_id { ...@@ -133,7 +143,7 @@ struct has_type_id {
}; \ }; \
template <> \ template <> \
struct type_name<CAF_PP_EXPAND fully_qualified_name> { \ struct type_name<CAF_PP_EXPAND fully_qualified_name> { \
static constexpr const char* value \ static constexpr string_view value \
= CAF_PP_STR(CAF_PP_EXPAND fully_qualified_name); \ = CAF_PP_STR(CAF_PP_EXPAND fully_qualified_name); \
}; \ }; \
template <> \ template <> \
...@@ -155,7 +165,7 @@ struct has_type_id { ...@@ -155,7 +165,7 @@ struct has_type_id {
}; \ }; \
template <> \ template <> \
struct type_name<CAF_PP_EXPAND fully_qualified_name> { \ struct type_name<CAF_PP_EXPAND fully_qualified_name> { \
static constexpr const char* value \ static constexpr string_view value \
= CAF_PP_STR(CAF_PP_EXPAND fully_qualified_name); \ = CAF_PP_STR(CAF_PP_EXPAND fully_qualified_name); \
}; \ }; \
template <> \ template <> \
...@@ -176,8 +186,8 @@ struct has_type_id { ...@@ -176,8 +186,8 @@ struct has_type_id {
return false; \ return false; \
} \ } \
template <class Inspector> \ template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \ bool inspect(Inspector& f, atom_name& x) { \
return f(caf::meta::type_name(#atom_name)); \ return f.object(x).fields(); \
} \ } \
CAF_ADD_TYPE_ID(project_name, (atom_name)) CAF_ADD_TYPE_ID(project_name, (atom_name))
...@@ -193,8 +203,8 @@ struct has_type_id { ...@@ -193,8 +203,8 @@ struct has_type_id {
return false; \ return false; \
} \ } \
template <class Inspector> \ template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \ bool 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))
...@@ -277,15 +287,26 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0) ...@@ -277,15 +287,26 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID(core_module, (caf::dictionary<caf::config_value>) ) CAF_ADD_TYPE_ID(core_module, (caf::dictionary<caf::config_value>) )
CAF_ADD_TYPE_ID(core_module, (caf::down_msg)) CAF_ADD_TYPE_ID(core_module, (caf::down_msg))
CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg)) CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg))
CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg_batch))
CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg_close))
CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg_forced_close))
CAF_ADD_TYPE_ID(core_module, (caf::error)) CAF_ADD_TYPE_ID(core_module, (caf::error))
CAF_ADD_TYPE_ID(core_module, (caf::exit_msg)) CAF_ADD_TYPE_ID(core_module, (caf::exit_msg))
CAF_ADD_TYPE_ID(core_module, (caf::exit_reason)) CAF_ADD_TYPE_ID(core_module, (caf::exit_reason))
CAF_ADD_TYPE_ID(core_module, (caf::group)) CAF_ADD_TYPE_ID(core_module, (caf::group))
CAF_ADD_TYPE_ID(core_module, (caf::group_down_msg)) CAF_ADD_TYPE_ID(core_module, (caf::group_down_msg))
CAF_ADD_TYPE_ID(core_module, (caf::hashed_node_id))
CAF_ADD_TYPE_ID(core_module, (caf::ipv4_address))
CAF_ADD_TYPE_ID(core_module, (caf::ipv4_endpoint))
CAF_ADD_TYPE_ID(core_module, (caf::ipv4_subnet))
CAF_ADD_TYPE_ID(core_module, (caf::ipv6_address))
CAF_ADD_TYPE_ID(core_module, (caf::ipv6_endpoint))
CAF_ADD_TYPE_ID(core_module, (caf::ipv6_subnet))
CAF_ADD_TYPE_ID(core_module, (caf::message)) CAF_ADD_TYPE_ID(core_module, (caf::message))
CAF_ADD_TYPE_ID(core_module, (caf::message_id)) CAF_ADD_TYPE_ID(core_module, (caf::message_id))
CAF_ADD_TYPE_ID(core_module, (caf::node_down_msg)) CAF_ADD_TYPE_ID(core_module, (caf::node_down_msg))
CAF_ADD_TYPE_ID(core_module, (caf::node_id)) CAF_ADD_TYPE_ID(core_module, (caf::node_id))
CAF_ADD_TYPE_ID(core_module, (caf::none_t))
CAF_ADD_TYPE_ID(core_module, (caf::open_stream_msg)) CAF_ADD_TYPE_ID(core_module, (caf::open_stream_msg))
CAF_ADD_TYPE_ID(core_module, (caf::pec)) CAF_ADD_TYPE_ID(core_module, (caf::pec))
CAF_ADD_TYPE_ID(core_module, (caf::sec)) CAF_ADD_TYPE_ID(core_module, (caf::sec))
...@@ -295,6 +316,10 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0) ...@@ -295,6 +316,10 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID(core_module, (caf::timestamp)) CAF_ADD_TYPE_ID(core_module, (caf::timestamp))
CAF_ADD_TYPE_ID(core_module, (caf::unit_t)) CAF_ADD_TYPE_ID(core_module, (caf::unit_t))
CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg)) CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg))
CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_ack_batch))
CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_ack_open))
CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_drop))
CAF_ADD_TYPE_ID(core_module, (caf::upstream_msg_forced_drop))
CAF_ADD_TYPE_ID(core_module, (caf::uri)) CAF_ADD_TYPE_ID(core_module, (caf::uri))
CAF_ADD_TYPE_ID(core_module, (caf::weak_actor_ptr)) CAF_ADD_TYPE_ID(core_module, (caf::weak_actor_ptr))
CAF_ADD_TYPE_ID(core_module, (std::vector<caf::actor>) ) CAF_ADD_TYPE_ID(core_module, (std::vector<caf::actor>) )
......
...@@ -236,8 +236,8 @@ public: ...@@ -236,8 +236,8 @@ public:
} }
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, typed_actor& x) { friend bool inspect(Inspector& f, typed_actor& x) {
return f(x.ptr_); return inspect(f, x.ptr_);
} }
/// Releases the reference held by handle `x`. Using the /// Releases the reference held by handle `x`. Using the
......
...@@ -35,67 +35,75 @@ ...@@ -35,67 +35,75 @@
namespace caf { namespace caf {
/// Stream messages that flow upstream, i.e., acks and drop messages. /// Acknowledges a previous `open` message and finalizes a stream handshake.
struct CAF_CORE_EXPORT upstream_msg : tag::boxing_type { /// Also signalizes initial demand.
// -- nested types ----------------------------------------------------------- struct upstream_msg_ack_open {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
/// Allows actors to participate in a stream instead of the actor
/// originally receiving the `open` message. No effect when set to
/// `nullptr`. This mechanism enables pipeline definitions consisting of
/// proxy actors that are replaced with actual actors on demand.
actor_addr rebind_from;
/// Points to sender_, but with a strong reference.
strong_actor_ptr rebind_to;
/// Grants credit to the source.
int32_t initial_demand;
/// Desired size of individual batches.
int32_t desired_batch_size;
};
/// Acknowledges a previous `open` message and finalizes a stream handshake. /// Cumulatively acknowledges received batches and signalizes new demand from a
/// Also signalizes initial demand. /// sink to its source.
struct ack_open { struct upstream_msg_ack_batch {
/// Allows the testing DSL to unbox this type automagically. /// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg; using outer_type = upstream_msg;
/// Allows actors to participate in a stream instead of the actor /// Newly available credit.
/// originally receiving the `open` message. No effect when set to int32_t new_capacity;
/// `nullptr`. This mechanism enables pipeline definitions consisting of
/// proxy actors that are replaced with actual actors on demand.
actor_addr rebind_from;
/// Points to sender_, but with a strong reference. /// Desired size of individual batches for the next cycle.
strong_actor_ptr rebind_to; int32_t desired_batch_size;
/// Grants credit to the source. /// Cumulative ack ID.
int32_t initial_demand; int64_t acknowledged_id;
/// Desired size of individual batches. /// Maximum capacity on this path. Stages can consider this metric for
int32_t desired_batch_size; /// downstream actors when calculating their own maximum capactiy.
}; int32_t max_capacity;
};
/// Cumulatively acknowledges received batches and signalizes new demand from /// Asks the source to discard any remaining credit and close this path after
/// a sink to its source. /// receiving an ACK for the last batch.
struct ack_batch { struct upstream_msg_drop {
/// Allows the testing DSL to unbox this type automagically. /// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg; using outer_type = upstream_msg;
};
/// Newly available credit. /// Propagates a fatal error from sinks to sources.
int32_t new_capacity; struct upstream_msg_forced_drop {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
/// Desired size of individual batches for the next cycle. /// Reason for shutting down the stream.
int32_t desired_batch_size; error reason;
};
/// Cumulative ack ID. /// Stream messages that flow upstream, i.e., acks and drop messages.
int64_t acknowledged_id; struct CAF_CORE_EXPORT upstream_msg : tag::boxing_type {
// -- nested types -----------------------------------------------------------
/// Maximum capacity on this path. Stages can consider this metric for using ack_open = upstream_msg_ack_open;
/// downstream actors when calculating their own maximum capactiy.
int32_t max_capacity;
};
/// Asks the source to discard any remaining credit and close this path using ack_batch = upstream_msg_ack_batch;
/// after receiving an ACK for the last batch.
struct drop {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
};
/// Propagates a fatal error from sinks to sources. using drop = upstream_msg_drop;
struct forced_drop {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
/// Reason for shutting down the stream. using forced_drop = upstream_msg_forced_drop;
error reason;
};
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
...@@ -158,37 +166,40 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) { ...@@ -158,37 +166,40 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) {
/// @relates upstream_msg::ack_open /// @relates upstream_msg::ack_open
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, upstream_msg::ack_open& x) {
inspect(Inspector& f, upstream_msg::ack_open& x) { return f.object(x).fields(
return f(meta::type_name("ack_open"), x.rebind_from, x.rebind_to, f.field("rebind_from", x.rebind_from), f.field("rebind_to", x.rebind_to),
x.initial_demand, x.desired_batch_size); f.field("initial_demand", x.initial_demand),
f.field("desired_batch_size", x.desired_batch_size));
} }
/// @relates upstream_msg::ack_batch /// @relates upstream_msg::ack_batch
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, upstream_msg::ack_batch& x) {
inspect(Inspector& f, upstream_msg::ack_batch& x) { return f.object(x).fields(f.field("new_capacity", x.new_capacity),
return f(meta::type_name("ack_batch"), x.new_capacity, x.desired_batch_size, f.field("desired_batch_size", x.desired_batch_size),
x.acknowledged_id, x.max_capacity); f.field("acknowledged_id", x.acknowledged_id),
f.field("max_capacity", x.max_capacity));
} }
/// @relates upstream_msg::drop /// @relates upstream_msg::drop
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, upstream_msg::drop&) { bool inspect(Inspector& f, upstream_msg::drop& x) {
return f(meta::type_name("drop")); return f.object(x).fields();
} }
/// @relates upstream_msg::forced_drop /// @relates upstream_msg::forced_drop
template <class Inspector> template <class Inspector>
typename Inspector::result_type bool inspect(Inspector& f, upstream_msg::forced_drop& x) {
inspect(Inspector& f, upstream_msg::forced_drop& x) { return f.object(x).fields(f.field("reason", x.reason));
return f(meta::type_name("forced_drop"), x.reason);
} }
/// @relates upstream_msg /// @relates upstream_msg
template <class Inspector> template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, upstream_msg& x) { bool inspect(Inspector& f, upstream_msg& x) {
return f(meta::type_name("upstream_msg"), x.slots, x.sender, x.content); return f.object(x).fields(f.field("slots", x.slots),
f.field("sender", x.sender),
f.field("content", x.content));
} }
} // namespace caf } // namespace caf
This diff is collapsed.
...@@ -32,7 +32,7 @@ public: ...@@ -32,7 +32,7 @@ public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
/// Pointer to implementation. /// Pointer to implementation.
using impl_ptr = intrusive_ptr<detail::uri_impl>; using impl_ptr = intrusive_ptr<uri::impl_type>;
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
......
...@@ -24,18 +24,15 @@ ...@@ -24,18 +24,15 @@
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/default_sum_type_access.hpp" #include "caf/default_sum_type_access.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/variant_data.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
#include "caf/static_visitor.hpp" #include "caf/static_visitor.hpp"
#include "caf/sum_type.hpp" #include "caf/sum_type.hpp"
#include "caf/sum_type_access.hpp" #include "caf/sum_type_access.hpp"
#include "caf/meta/omittable.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/detail/variant_data.hpp"
#define CAF_VARIANT_CASE(n) \ #define CAF_VARIANT_CASE(n) \
case n: \ case n: \
return f(std::forward<Us>(xs)..., \ return f(std::forward<Us>(xs)..., \
...@@ -433,87 +430,4 @@ bool operator>=(const variant<Ts...>& x, const variant<Ts...>& y) { ...@@ -433,87 +430,4 @@ bool operator>=(const variant<Ts...>& x, const variant<Ts...>& y) {
return !(x < y); return !(x < y);
} }
/// @relates variant
template <class T>
struct variant_reader {
uint8_t& type_tag;
T& x;
};
/// @relates variant
template <class Inspector, class... Ts>
typename Inspector::result_type
inspect(Inspector& f, variant_reader<variant<Ts...>>& x) {
return x.x.template apply<typename Inspector::result_type>(f);
}
/// @relates variant
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type
inspect(Inspector& f, variant<Ts...>& x) {
// We use a single byte for the type index on the wire.
auto type_tag = static_cast<uint8_t>(x.index());
variant_reader<variant<Ts...>> helper{type_tag, x};
return f(meta::omittable(), type_tag, helper);
}
/// @relates variant
template <class T>
struct variant_writer {
uint8_t& type_tag;
T& x;
};
/// @relates variant
template <class Inspector, class... Ts>
typename Inspector::result_type
inspect(Inspector& f, variant_writer<variant<Ts...>>& x) {
switch (x.type_tag) {
default: CAF_RAISE_ERROR("invalid type found");
CAF_VARIANT_ASSIGN_CASE(0);
CAF_VARIANT_ASSIGN_CASE(1);
CAF_VARIANT_ASSIGN_CASE(2);
CAF_VARIANT_ASSIGN_CASE(3);
CAF_VARIANT_ASSIGN_CASE(4);
CAF_VARIANT_ASSIGN_CASE(5);
CAF_VARIANT_ASSIGN_CASE(6);
CAF_VARIANT_ASSIGN_CASE(7);
CAF_VARIANT_ASSIGN_CASE(8);
CAF_VARIANT_ASSIGN_CASE(9);
CAF_VARIANT_ASSIGN_CASE(10);
CAF_VARIANT_ASSIGN_CASE(11);
CAF_VARIANT_ASSIGN_CASE(12);
CAF_VARIANT_ASSIGN_CASE(13);
CAF_VARIANT_ASSIGN_CASE(14);
CAF_VARIANT_ASSIGN_CASE(15);
CAF_VARIANT_ASSIGN_CASE(16);
CAF_VARIANT_ASSIGN_CASE(17);
CAF_VARIANT_ASSIGN_CASE(18);
CAF_VARIANT_ASSIGN_CASE(19);
CAF_VARIANT_ASSIGN_CASE(20);
CAF_VARIANT_ASSIGN_CASE(21);
CAF_VARIANT_ASSIGN_CASE(22);
CAF_VARIANT_ASSIGN_CASE(23);
CAF_VARIANT_ASSIGN_CASE(24);
CAF_VARIANT_ASSIGN_CASE(25);
CAF_VARIANT_ASSIGN_CASE(26);
CAF_VARIANT_ASSIGN_CASE(27);
CAF_VARIANT_ASSIGN_CASE(28);
CAF_VARIANT_ASSIGN_CASE(29);
}
}
/// @relates variant
template <class Inspector, class... Ts>
typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type
inspect(Inspector& f, variant<Ts...>& x) {
// We use a single byte for the type index on the wire.
uint8_t type_tag;
variant_writer<variant<Ts...>> helper{type_tag, x};
return f(meta::omittable(), type_tag, helper);
}
} // namespace caf } // namespace caf
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "caf/scheduler/test_coordinator.hpp" #include "caf/scheduler/test_coordinator.hpp"
#include "caf/send.hpp" #include "caf/send.hpp"
#include "caf/stateful_actor.hpp" #include "caf/stateful_actor.hpp"
#include "caf/to_string.hpp"
namespace caf { namespace caf {
...@@ -294,13 +293,13 @@ actor_system::actor_system(actor_system_config& cfg) ...@@ -294,13 +293,13 @@ actor_system::actor_system(actor_system_config& cfg)
// Make sure meta objects are loaded. // Make sure meta objects are loaded.
auto gmos = detail::global_meta_objects(); auto gmos = detail::global_meta_objects();
if (gmos.size() < id_block::core_module::end if (gmos.size() < id_block::core_module::end
|| gmos[id_block::core_module::begin].type_name == nullptr) { || gmos[id_block::core_module::begin].type_name.empty()) {
CAF_CRITICAL("actor_system created without calling " CAF_CRITICAL("actor_system created without calling "
"caf::init_global_meta_objects<>() before"); "caf::init_global_meta_objects<>() before");
} }
if (modules_[module::middleman] != nullptr) { if (modules_[module::middleman] != nullptr) {
if (gmos.size() < detail::io_module_end if (gmos.size() < detail::io_module_end
|| gmos[detail::io_module_begin].type_name == nullptr) { || gmos[detail::io_module_begin].type_name.empty()) {
CAF_CRITICAL("I/O module loaded without calling " CAF_CRITICAL("I/O module loaded without calling "
"caf::io::middleman::init_global_meta_objects() before"); "caf::io::middleman::init_global_meta_objects() before");
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -35,15 +35,15 @@ deserializer::~deserializer() { ...@@ -35,15 +35,15 @@ deserializer::~deserializer() {
// nop // nop
} }
auto deserializer::apply(std::vector<bool>& x) noexcept -> result_type { bool deserializer::value(std::vector<bool>& x) {
x.clear(); x.clear();
size_t size = 0; size_t size = 0;
if (auto err = begin_sequence(size)) if (!begin_sequence(size))
return err; return false;
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
bool tmp = false; bool tmp = false;
if (auto err = apply(tmp)) if (!value(tmp))
return err; return false;
x.emplace_back(tmp); x.emplace_back(tmp);
} }
return end_sequence(); return end_sequence();
......
This diff is collapsed.
...@@ -57,25 +57,6 @@ struct meta_objects_cleanup { ...@@ -57,25 +57,6 @@ struct meta_objects_cleanup {
} // namespace } // namespace
caf::error save(const meta_object& meta, caf::serializer& sink,
const void* obj) {
return meta.save(sink, obj);
}
caf::error_code<sec> save(const meta_object& meta, caf::binary_serializer& sink,
const void* obj) {
return meta.save_binary(sink, obj);
}
caf::error load(const meta_object& meta, caf::deserializer& source, void* obj) {
return meta.load(source, obj);
}
caf::error_code<sec> load(const meta_object& meta,
caf::binary_deserializer& source, void* obj) {
return meta.load_binary(source, obj);
}
span<const meta_object> global_meta_objects() { span<const meta_object> global_meta_objects() {
return {meta_objects, meta_objects_size}; return {meta_objects, meta_objects_size};
} }
...@@ -83,7 +64,7 @@ span<const meta_object> global_meta_objects() { ...@@ -83,7 +64,7 @@ span<const meta_object> global_meta_objects() {
const meta_object* global_meta_object(type_id_t id) { const meta_object* global_meta_object(type_id_t id) {
CAF_ASSERT(id < meta_objects_size); CAF_ASSERT(id < meta_objects_size);
auto& meta = meta_objects[id]; auto& meta = meta_objects[id];
return meta.type_name != nullptr ? &meta : nullptr; return !meta.type_name.empty() ? &meta : nullptr;
} }
void clear_global_meta_objects() { void clear_global_meta_objects() {
...@@ -115,18 +96,21 @@ void set_global_meta_objects(type_id_t first_id, span<const meta_object> xs) { ...@@ -115,18 +96,21 @@ void set_global_meta_objects(type_id_t first_id, span<const meta_object> xs) {
"'new_size > meta_objects_size'"); "'new_size > meta_objects_size'");
auto out = meta_objects + first_id; auto out = meta_objects + first_id;
for (const auto& x : xs) { for (const auto& x : xs) {
if (out->type_name == nullptr) { if (out->type_name.empty()) {
// We support calling set_global_meta_objects for building the global // We support calling set_global_meta_objects for building the global
// table chunk-by-chunk. // table chunk-by-chunk.
*out = x; *out = x;
} else if (strcmp(out->type_name, x.type_name) == 0) { } else if (out->type_name == x.type_name) {
// nop: set_global_meta_objects implements idempotency. // nop: set_global_meta_objects implements idempotency.
} else { } else {
// Get null-terminated strings.
auto name1 = to_string(out->type_name);
auto name2 = to_string(x.type_name);
fprintf(stderr, fprintf(stderr,
"FATAL: type ID %d already assigned to %s (tried to override " "FATAL: type ID %d already assigned to %s (tried to override "
"with %s)\n", "with %s)\n",
static_cast<int>(std::distance(meta_objects, out)), static_cast<int>(std::distance(meta_objects, out)),
out->type_name, x.type_name); name1.c_str(), name2.c_str());
abort(); abort();
} }
++out; ++out;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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