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 {
};
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a, x.b);
bool inspect(Inspector& f, foo& x) {
return f.object(x).fields(f.field("a", x.a), f.field("b", x.b));
}
// --(rst-foo-end)--
......@@ -57,8 +57,8 @@ struct foo2 {
// foo2 also needs to be serializable
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo2& x) {
return f(meta::type_name("foo2"), x.a, x.b);
bool inspect(Inspector& f, foo2& x) {
return f.objects(x).fields(f.field("a", x.a), f.field("b", x.b));
}
// receives our custom message types
......
......@@ -47,8 +47,8 @@ public:
}
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, foo& x) {
return f(meta::type_name("foo"), x.a_, x.b_);
friend bool inspect(Inspector& f, foo& x) {
return f.object(x).fields(f.field("a", x.a_), f.field("b", x.b_));
}
private:
......
......@@ -83,19 +83,19 @@ scope_guard<Fun> make_scope_guard(Fun f) {
// --(rst-inspect-begin)--
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, foo& x) {
if constexpr (Inspector::reads_state) {
return f(meta::type_name("foo"), x.a(), x.b());
} else {
int a;
int b;
// write back to x at scope exit
auto g = make_scope_guard([&] {
x.set_a(a);
x.set_b(b);
});
return f(meta::type_name("foo"), a, b);
}
bool inspect(Inspector& f, foo& x) {
auto get_a = [&x] { return x.a(); };
auto set_a = [&x](int val) {
x.a(val);
return true;
};
auto get_b = [&x] { return x.b(); };
auto set_b = [&x](int val) {
x.b(val);
return true;
};
return f.object(x).fields(f.field("a", get_a, set_a),
f.field("b", get_b, set_b));
}
// --(rst-inspect-end)--
......
......@@ -103,7 +103,6 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/detail/thread_safe_actor_clock.cpp
src/detail/tick_emitter.cpp
src/detail/type_id_list_builder.cpp
src/detail/uri_impl.cpp
src/downstream_manager.cpp
src/downstream_manager_base.cpp
src/error.cpp
......@@ -125,6 +124,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/ipv6_address.cpp
src/ipv6_endpoint.cpp
src/ipv6_subnet.cpp
src/load_inspector.cpp
src/local_actor.cpp
src/logger.cpp
src/mailbox_element.cpp
......@@ -148,6 +148,7 @@ add_library(libcaf_core_obj OBJECT ${CAF_CORE_HEADERS}
src/replies_to.cpp
src/response_promise.cpp
src/resumable.cpp
src/save_inspector.cpp
src/scheduled_actor.cpp
src/scheduler/abstract_coordinator.cpp
src/scheduler/test_coordinator.cpp
......
......@@ -22,6 +22,7 @@
#include <string>
#include "caf/abstract_channel.hpp"
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp"
#include "caf/attachable.hpp"
#include "caf/detail/core_export.hpp"
......@@ -46,12 +47,6 @@ public:
// -- 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
/// or `false` if `who` is already subscribed.
virtual bool subscribe(strong_actor_ptr who) = 0;
......@@ -64,22 +59,28 @@ public:
// -- observers --------------------------------------------------------------
/// Returns the parent module.
group_module& module() const {
return parent_;
}
/// Returns the hosting system.
actor_system& system() const {
return system_;
}
/// Returns the parent module.
group_module& module() const {
return parent_;
}
/// 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.
const std::string& identifier() const {
return identifier_;
}
/// @private
const actor& dispatcher() {
return dispatcher_;
}
protected:
abstract_group(group_module& mod, std::string id, node_id nid);
......@@ -87,6 +88,7 @@ protected:
group_module& parent_;
std::string identifier_;
node_id origin_;
actor dispatcher_;
};
/// A smart pointer type that manages instances of {@link group}.
......
......@@ -147,7 +147,7 @@ public:
}
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_);
}
......
......@@ -110,7 +110,7 @@ public:
}
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_);
}
......
......@@ -25,10 +25,6 @@
#include "caf/error.hpp"
#include "caf/fwd.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/weak_intrusive_ptr.hpp"
......@@ -97,7 +93,7 @@ public:
static_assert(sizeof(std::atomic<size_t>) == sizeof(void*),
"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");
static_assert(sizeof(node_id) == sizeof(void*),
......@@ -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);
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;
node_id nid;
if constexpr (!Inspector::is_loading) {
if (x) {
aid = x->aid;
nid = x->nid;
}
auto load = [&] { return load_actor(x, context_of(&f), aid, nid); };
auto save = [&] { return save_actor(x, context_of(&f), aid, nid); };
return f(meta::type_name("actor"), aid, meta::omittable_if_none(), nid,
meta::load_callback(load), meta::save_callback(save));
}
auto load_cb = [&] { return load_actor(x, context_of(&f), aid, nid); };
auto save_cb = [&] { return save_actor(x, context_of(&f), aid, nid); };
return f.object(x)
.pretty_name("actor")
.on_load(load_cb)
.on_save(save_cb)
.fields(f.field("id", aid), f.field("node", nid));
}
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, weak_actor_ptr& x) {
// inspect as strong pointer, then write back to weak pointer on save
bool inspect(Inspector& f, weak_actor_ptr& x) {
// Inspect as strong pointer, then write back to weak pointer on save.
auto tmp = x.lock();
auto load = [&] { x.reset(tmp.get()); };
return f(tmp, meta::load_callback(load));
auto result = inspect(f, tmp);
if constexpr (!Inspector::is_loading) {
if (result)
x.reset(tmp.get());
}
return result;
}
} // namespace caf
......
......@@ -75,8 +75,8 @@ struct typed_mpi_access<result<Out...>(In...)> {
std::string operator()() const {
static_assert(sizeof...(In) > 0, "typed MPI without inputs");
static_assert(sizeof...(Out) > 0, "typed MPI without outputs");
std::vector<std::string> inputs{type_name_v<In>...};
std::vector<std::string> outputs1{type_name_v<Out>...};
std::vector<std::string> inputs{to_string(type_name_v<In>)...};
std::vector<std::string> outputs1{to_string(type_name_v<Out>)...};
std::string result = "(";
result += join(inputs, ",");
result += ") -> (";
......
......@@ -38,7 +38,6 @@
#include "caf/dictionary.hpp"
#include "caf/fwd.hpp"
#include "caf/is_typed_actor.hpp"
#include "caf/named_actor_config.hpp"
#include "caf/settings.hpp"
#include "caf/stream.hpp"
#include "caf/thread_hook.hpp"
......@@ -75,8 +74,6 @@ public:
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;
// -- constructors, destructors, and assignment operators --------------------
......@@ -253,9 +250,6 @@ public:
// -- 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&);
// -- default error rendering functions --------------------------------------
......
......@@ -70,7 +70,6 @@
#include "caf/fused_downstream_manager.hpp"
#include "caf/group.hpp"
#include "caf/hash/fnv.hpp"
#include "caf/index_mapping.hpp"
#include "caf/init_global_meta_objects.hpp"
#include "caf/local_actor.hpp"
#include "caf/logger.hpp"
......@@ -106,7 +105,6 @@
#include "caf/term.hpp"
#include "caf/thread_hook.hpp"
#include "caf/timeout_definition.hpp"
#include "caf/to_string.hpp"
#include "caf/tracing_data.hpp"
#include "caf/tracing_data_factory.hpp"
#include "caf/type_id.hpp"
......
......@@ -26,21 +26,16 @@
#include "caf/detail/core_export.hpp"
#include "caf/error_code.hpp"
#include "caf/fwd.hpp"
#include "caf/load_inspector.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include "caf/string_view.hpp"
#include "caf/write_inspector.hpp"
namespace caf {
/// Deserializes objects from sequence of bytes.
class CAF_CORE_EXPORT binary_deserializer
: public write_inspector<binary_deserializer> {
class CAF_CORE_EXPORT binary_deserializer : public load_inspector {
public:
// -- member types -----------------------------------------------------------
using result_type = error_code<sec>;
// -- constructors, destructors, and assignment operators --------------------
template <class Container>
......@@ -87,7 +82,7 @@ public:
/// Jumps `num_bytes` forward.
/// @pre `num_bytes <= remaining()`
void skip(size_t num_bytes) noexcept;
void skip(size_t num_bytes);
/// Assigns a new input.
void reset(span<const byte> bytes) noexcept;
......@@ -102,56 +97,92 @@ public:
return end_;
}
static constexpr bool has_human_readable_format() noexcept {
return false;
}
// -- 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>>
auto apply(Enum& x) noexcept {
return apply(reinterpret_cast<std::underlying_type_t<Enum>&>(x));
}
bool value(float& x) noexcept;
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:
explicit binary_deserializer(actor_system& sys) noexcept;
......
......@@ -31,20 +31,17 @@
#include "caf/detail/squashed_int.hpp"
#include "caf/error_code.hpp"
#include "caf/fwd.hpp"
#include "caf/read_inspector.hpp"
#include "caf/save_inspector.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
namespace caf {
/// Serializes objects into a sequence of bytes.
class CAF_CORE_EXPORT binary_serializer
: public read_inspector<binary_serializer> {
class CAF_CORE_EXPORT binary_serializer : public save_inspector {
public:
// -- member types -----------------------------------------------------------
using result_type = error_code<sec>;
using container_type = byte_buffer;
using value_type = byte;
......@@ -81,6 +78,10 @@ public:
return write_pos_;
}
static constexpr bool has_human_readable_format() noexcept {
return false;
}
// -- position management ----------------------------------------------------
/// Sets the write position to `offset`.
......@@ -95,52 +96,83 @@ public:
// -- 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>
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));
}
bool value(int32_t x);
template <class Enum>
std::enable_if_t<std::is_enum<Enum>::value> apply(Enum x) {
return apply(static_cast<std::underlying_type_t<Enum>>(x));
}
bool value(uint32_t 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:
/// Stores the serialized output.
......
......@@ -850,8 +850,51 @@ config_value make_config_value_list(Ts&&... xs) {
/// @relates config_value
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, config_value& x) {
return f(meta::type_name("config_value"), x.get_data());
bool inspect(Inspector& f, config_value& x) {
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
......@@ -21,6 +21,7 @@
#include <tuple>
#include "caf/detail/comparable.hpp"
#include "caf/inspector_access.hpp"
#include "caf/make_copy_on_write.hpp"
#include "caf/ref_counted.hpp"
......@@ -114,22 +115,6 @@ private:
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.
/// @relates cow_tuple
template <class... Ts>
......@@ -144,4 +129,66 @@ auto get(const cow_tuple<Ts...>& xs) -> decltype(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
......@@ -34,28 +34,23 @@ template <class... Ts>
std::string deep_to_string(const Ts&... xs) {
std::string result;
detail::stringification_inspector f{result};
f(xs...);
auto inspect_result = (inspect_object(f, xs) && ...);
static_cast<void>(inspect_result); // Always true.
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...))`.
template <class... Ts>
std::string deep_to_string_as_tuple(const Ts&... 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
......@@ -27,19 +27,16 @@
#include "caf/byte.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
#include "caf/load_inspector.hpp"
#include "caf/span.hpp"
#include "caf/write_inspector.hpp"
#include "caf/type_id.hpp"
namespace caf {
/// @ingroup TypeSystem
/// Technology-independent deserialization interface.
class CAF_CORE_EXPORT deserializer : public write_inspector<deserializer> {
class CAF_CORE_EXPORT deserializer : public load_inspector {
public:
// -- member types -----------------------------------------------------------
using result_type = error;
// -- constructors, destructors, and assignment operators --------------------
explicit deserializer(actor_system& sys) noexcept;
......@@ -54,86 +51,114 @@ public:
return context_;
}
bool has_human_readable_format() const noexcept {
return has_human_readable_format_;
}
// -- interface functions ----------------------------------------------------
/// 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.
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.
virtual result_type begin_sequence(size_t& size) = 0;
virtual bool begin_sequence(size_t& size) = 0;
/// Ends processing of a sequence.
virtual result_type end_sequence() = 0;
virtual bool end_sequence() = 0;
/// Reads primitive value from the input.
/// @param x The primitive value.
/// @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
virtual result_type apply(int8_t&) = 0;
/// @copydoc value
virtual bool value(int8_t&) = 0;
/// @copydoc apply
virtual result_type apply(uint8_t&) = 0;
/// @copydoc value
virtual bool value(uint8_t&) = 0;
/// @copydoc apply
virtual result_type apply(int16_t&) = 0;
/// @copydoc value
virtual bool value(int16_t&) = 0;
/// @copydoc apply
virtual result_type apply(uint16_t&) = 0;
/// @copydoc value
virtual bool value(uint16_t&) = 0;
/// @copydoc apply
virtual result_type apply(int32_t&) = 0;
/// @copydoc value
virtual bool value(int32_t&) = 0;
/// @copydoc apply
virtual result_type apply(uint32_t&) = 0;
/// @copydoc value
virtual bool value(uint32_t&) = 0;
/// @copydoc apply
virtual result_type apply(int64_t&) = 0;
/// @copydoc value
virtual bool value(int64_t&) = 0;
/// @copydoc apply
virtual result_type apply(uint64_t&) = 0;
/// @copydoc value
virtual bool value(uint64_t&) = 0;
/// @copydoc apply
virtual result_type apply(float&) = 0;
/// @copydoc value
virtual bool value(float&) = 0;
/// @copydoc apply
virtual result_type apply(double&) = 0;
/// @copydoc value
virtual bool value(double&) = 0;
/// @copydoc apply
virtual result_type apply(long double&) = 0;
/// @copydoc value
virtual bool value(long double&) = 0;
/// @copydoc apply
virtual result_type apply(std::string&) = 0;
/// @copydoc value
virtual bool value(std::string&) = 0;
/// @copydoc apply
virtual result_type apply(std::u16string&) = 0;
/// @copydoc value
virtual bool value(std::u16string&) = 0;
/// @copydoc apply
virtual result_type apply(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));
}
/// @copydoc value
virtual bool value(std::u32string&) = 0;
/// Reads a byte sequence from the input.
/// @param x The byte sequence.
/// @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
/// member function to pack the booleans, for example to avoid using one byte
/// 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:
/// Provides access to the ::proxy_registry and to the ::actor_system.
execution_unit* context_;
/// Configures whether client code should assume human-readable output.
bool has_human_readable_format_ = false;
};
} // namespace caf
......@@ -25,6 +25,7 @@
#include "caf/config_value_adaptor_field.hpp"
#include "caf/config_value_field.hpp"
#include "caf/detail/config_value_field_base.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/string_view.hpp"
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 @@
#include "caf/detail/meta_object.hpp"
#include "caf/detail/padded_size.hpp"
#include "caf/detail/stringification_inspector.hpp"
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/serializer.hpp"
namespace caf::detail::default_function {
......@@ -45,33 +45,34 @@ void default_construct(void* ptr) {
template <class T>
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>
error_code<sec> save_binary(caf::binary_serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr));
bool save_binary(binary_serializer& sink, const void* ptr) {
return inspect_object(sink, as_mutable_ref(*static_cast<const T*>(ptr)));
}
template <class T>
error_code<sec> load_binary(caf::binary_deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr));
bool load_binary(binary_deserializer& source, void* ptr) {
return inspect_object(source, *static_cast<T*>(ptr));
}
template <class T>
caf::error save(caf::serializer& sink, const void* ptr) {
return sink(*reinterpret_cast<const T*>(ptr));
bool save(serializer& sink, const void* ptr) {
return inspect_object(sink, as_mutable_ref(*static_cast<const T*>(ptr)));
}
template <class T>
caf::error load(caf::deserializer& source, void* ptr) {
return source(*reinterpret_cast<T*>(ptr));
bool load(deserializer& source, void* ptr) {
return inspect_object(source, *static_cast<T*>(ptr));
}
template <class T>
void stringify(std::string& buf, const void* ptr) {
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
......@@ -79,7 +80,7 @@ void stringify(std::string& buf, const void* ptr) {
namespace caf::detail {
template <class T>
meta_object make_meta_object(const char* type_name) {
meta_object make_meta_object(string_view type_name) {
return {
type_name,
padded_size_v<T>,
......
......@@ -115,13 +115,13 @@ public:
/// @copydoc at
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:
mutable std::atomic<size_t> rc_;
......
......@@ -24,6 +24,7 @@
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp"
#include "caf/span.hpp"
#include "caf/string_view.hpp"
namespace caf::detail {
......@@ -31,7 +32,7 @@ namespace caf::detail {
/// pointers.
struct meta_object {
/// 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
/// aligning to `max_align_t`.
......@@ -49,36 +50,44 @@ struct meta_object {
void (*copy_construct)(void*, const void*);
/// 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.
error_code<sec> (*load_binary)(caf::binary_deserializer&, void*);
bool (*load_binary)(caf::binary_deserializer&, void*);
/// 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.
caf::error (*load)(caf::deserializer&, void*);
bool (*load)(caf::deserializer&, void*);
/// Appends a string representation of an object to a buffer.
void (*stringify)(std::string&, const void*);
};
/// Convenience function for calling `meta.save(sink, obj)`.
CAF_CORE_EXPORT caf::error save(const meta_object& meta, caf::serializer& sink,
const void* obj);
inline bool save(const meta_object& meta, caf::serializer& sink,
const void* obj) {
return meta.save(sink, obj);
}
/// Convenience function for calling `meta.save_binary(sink, obj)`.
CAF_CORE_EXPORT caf::error_code<sec>
save(const meta_object& meta, caf::binary_serializer& sink, const void* obj);
inline bool save(const meta_object& meta, caf::binary_serializer& sink,
const void* obj) {
return meta.save_binary(sink, obj);
}
/// Convenience function for calling `meta.load(source, obj)`.
CAF_CORE_EXPORT caf::error load(const meta_object& meta,
caf::deserializer& source, void* obj);
inline bool load(const meta_object& meta, caf::deserializer& source,
void* obj) {
return meta.load(source, obj);
}
/// Convenience function for calling `meta.load_binary(source, obj)`.
CAF_CORE_EXPORT caf::error_code<sec>
load(const meta_object& meta, caf::binary_deserializer& source, void* obj);
inline bool load(const meta_object& meta, caf::binary_deserializer& source,
void* obj) {
return meta.load_binary(source, obj);
}
/// Returns the global storage for all meta objects. The ::type_id of an object
/// is the index for accessing the corresonding meta object.
......
......@@ -34,65 +34,81 @@ public:
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:
size_t result_ = 0;
};
template <class T>
size_t serialized_size(actor_system& sys, const T& x) {
serialized_size_inspector f{sys};
auto err = f(x);
static_cast<void>(err);
size_t serialized_size(const T& x) {
serialized_size_inspector f;
auto inspection_res = inspect_object(f, x);
static_cast<void>(inspection_res); // Always true.
return f.result();
}
template <class T>
size_t serialized_size(const T& x) {
serialized_size_inspector f{nullptr};
auto err = f(x);
static_cast<void>(err);
size_t serialized_size(actor_system& sys, const T& x) {
serialized_size_inspector f{sys};
auto inspection_res = inspect_object(f, x);
static_cast<void>(inspection_res); // Always true.
return f.result();
}
......
......@@ -19,38 +19,24 @@
#pragma once
#include <chrono>
#include <functional>
#include <string>
#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/inspect.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
#include "caf/meta/annotation.hpp"
#include "caf/meta/hex_formatted.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/inspector_access.hpp"
#include "caf/save_inspector.hpp"
#include "caf/string_view.hpp"
#include "caf/timespan.hpp"
#include "caf/timestamp.hpp"
namespace caf::detail {
class CAF_CORE_EXPORT stringification_inspector {
class CAF_CORE_EXPORT stringification_inspector : public save_inspector {
public:
// -- member types required by Inspector concept -----------------------------
// -- member types -----------------------------------------------------------
using result_type = void;
static constexpr bool reads_state = true;
static constexpr bool writes_state = false;
using super = save_inspector;
// -- constructors, destructors, and assignment operators --------------------
......@@ -58,216 +44,92 @@ public:
// nop
}
// -- serializer interface ---------------------------------------------------
// -- properties -------------------------------------------------------------
void begin_object(type_id_t) {
// nop
constexpr bool has_human_readable_format() const noexcept {
return true;
}
void end_object() {
// nop
}
void begin_sequence(size_t) {
// nop
}
// -- serializer interface ---------------------------------------------------
void end_sequence() {
// nop
}
bool begin_object(string_view name);
// -- operator() -------------------------------------------------------------
bool end_object();
template <class... Ts>
void operator()(Ts&&... xs) {
traverse(xs...);
}
bool begin_field(string_view);
/// Prints a separator to the result string.
void sep();
bool begin_field(string_view name, bool is_present);
void consume(const timespan& x);
bool begin_field(string_view name, span<const type_id_t>, size_t);
void consume(const timestamp& x);
bool begin_field(string_view name, bool, span<const type_id_t>, size_t);
void consume(const bool& x);
bool end_field();
void consume(const std::vector<bool>& xs);
bool begin_sequence(size_t size);
template <class T, size_t N>
void consume(const T (&xs)[N]) {
consume_range(xs, xs + N);
}
bool end_sequence();
template <class T>
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>";
}
}
bool begin_tuple(size_t size);
template <class Clock, class Duration>
void consume(const std::chrono::time_point<Clock, Duration>& x) {
timestamp tmp{std::chrono::duration_cast<timespan>(x.time_since_epoch())};
consume(tmp);
}
bool end_tuple();
template <class Rep, class Period>
void consume(const std::chrono::duration<Rep, Period>& x) {
auto tmp = std::chrono::duration_cast<timespan>(x);
consume(tmp);
}
bool value(bool x);
// Unwrap std::ref.
template <class T>
void consume(const std::reference_wrapper<T>& x) {
return consume(x.get());
template <class Integral>
std::enable_if_t<std::is_integral<Integral>::value, bool> value(Integral x) {
if constexpr (std::is_signed<Integral>::value)
return int_value(static_cast<int64_t>(x));
else
return int_value(static_cast<uint64_t>(x));
}
template <class F, class S>
void consume(const std::pair<F, S>& x) {
result_ += '(';
traverse(x.first, x.second);
result_ += ')';
}
bool value(float x);
template <class... Ts>
void consume(const std::tuple<Ts...>& x) {
result_ += '(';
apply_args(*this, get_indices(x), x);
result_ += ')';
}
bool value(double x);
void traverse() {
// end of recursion
}
bool value(long double x);
template <class T, class... Ts>
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...);
}
bool value(string_view x);
template <class T, class... Ts>
void traverse(const meta::omittable_if_none_t&, const T& x, const Ts&... xs) {
if (x != none) {
sep();
consume(x);
}
traverse(xs...);
}
bool value(const std::u16string& x);
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...);
}
bool value(const std::u32string& x);
template <class T, class... Ts>
void traverse(const meta::omittable_t&, const T&, const Ts&... xs) {
traverse(xs...);
template <class T>
std::enable_if_t<has_to_string<T>::value, bool> value(const T& x) {
auto str = to_string(x);
append(str);
return true;
}
template <class... Ts>
void traverse(const meta::type_name_t& x, const Ts&... xs) {
template <class T>
void append(T&& str) {
sep();
result_ += x.value;
result_ += '(';
traverse(xs...);
result_ += ')';
result_.insert(result_.end(), str.begin(), str.end());
}
template <class... Ts>
void traverse(const meta::annotation&, const Ts&... xs) {
traverse(xs...);
}
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>
bool opaque_value(const T&) {
result_ += "<unprintable>";
return true;
}
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:
template <class Iterator>
void consume_range(Iterator first, Iterator last) {
result_ += '[';
while (first != last) {
sep();
consume(*first++);
}
result_ += ']';
}
// -- DSL entry point --------------------------------------------------------
template <class T>
void consume_ptr(const T* ptr) {
if (ptr) {
result_ += '*';
consume(*ptr);
} else {
result_ += "nullptr";
template <class Object>
constexpr auto object(Object&) noexcept {
using wrapper_type = object_t<stringification_inspector>;
return wrapper_type{type_name_or_anonymous<Object>(), this};
}
}
void consume_str(string_view str);
void consume_ptr(const void* ptr);
void consume_ptr(const char* cstr);
private:
bool int_value(int64_t x);
void consume_int(int64_t x);
bool int_value(uint64_t x);
void consume_int(uint64_t x);
void sep();
std::string& result_;
};
......
......@@ -67,6 +67,9 @@
namespace caf::detail {
template <class T>
constexpr T* null_v = nullptr;
// -- backport of C++14 additions ----------------------------------------------
template <class T>
......@@ -651,12 +654,44 @@ struct is_map_like {
template <class T>
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`.
template <class T>
struct is_list_like {
static constexpr bool value = is_iterable<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>
......@@ -747,6 +782,71 @@ struct is_stl_tuple_type {
template <class T>
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
#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,12 +35,8 @@
namespace caf {
/// Stream messages that travel downstream, i.e., batches and close messages.
struct CAF_CORE_EXPORT downstream_msg : tag::boxing_type {
// -- nested types -----------------------------------------------------------
/// Transmits stream data.
struct batch {
/// Transmits stream data.
struct downstream_msg_batch {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
......@@ -52,22 +48,32 @@ struct CAF_CORE_EXPORT downstream_msg : tag::boxing_type {
/// ID of this batch (ascending numbering).
int64_t id;
};
};
/// Orderly shuts down a stream after receiving an ACK for the last batch.
struct close {
/// Orderly shuts down a stream after receiving an ACK for the last batch.
struct downstream_msg_close {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
};
};
/// Propagates a fatal error from sources to sinks.
struct forced_close {
/// Propagates a fatal error from sources to sinks.
struct downstream_msg_forced_close {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = downstream_msg;
/// Reason for shutting down the stream.
error reason;
};
};
/// Stream messages that travel downstream, i.e., batches and close messages.
struct CAF_CORE_EXPORT downstream_msg : tag::boxing_type {
// -- nested types -----------------------------------------------------------
using batch = downstream_msg_batch;
using close = downstream_msg_close;
using forced_close = downstream_msg_forced_close;
// -- member types -----------------------------------------------------------
......@@ -129,28 +135,33 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) {
/// @relates downstream_msg::batch
template <class Inspector>
typename Inspector::result_type
inspect(Inspector& f, downstream_msg::batch& x) {
return f(meta::type_name("batch"), meta::omittable(), x.xs_size, x.xs, x.id);
bool inspect(Inspector& f, downstream_msg::batch& x) {
return f.object(x).pretty_name("batch").fields(f.field("size", x.xs_size),
f.field("xs", x.xs),
f.field("id", x.id));
}
/// @relates downstream_msg::close
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, downstream_msg::close&) {
return f(meta::type_name("close"));
bool inspect(Inspector& f, downstream_msg::close& x) {
return f.object(x).pretty_name("close").fields();
}
/// @relates downstream_msg::forced_close
template <class Inspector>
typename Inspector::result_type
inspect(Inspector& f, downstream_msg::forced_close& x) {
return f(meta::type_name("forced_close"), x.reason);
bool inspect(Inspector& f, downstream_msg::forced_close& x) {
return f.object(x)
.pretty_name("forced_close")
.fields(f.field("reason", x.reason));
}
/// @relates downstream_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, downstream_msg& x) {
return f(meta::type_name("downstream_msg"), x.slots, x.sender, x.content);
bool inspect(Inspector& f, downstream_msg& x) {
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
......@@ -26,12 +26,9 @@
#include "caf/detail/core_export.hpp"
#include "caf/error_code.hpp"
#include "caf/fwd.hpp"
#include "caf/inspector_access.hpp"
#include "caf/is_error_code_enum.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/type_id.hpp"
......@@ -67,6 +64,21 @@ namespace caf {
/// instead.
class CAF_CORE_EXPORT error : detail::comparable<error> {
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 --------------------
error() noexcept = default;
......@@ -139,6 +151,11 @@ public:
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(uint8_t code, type_id_t category) const noexcept;
......@@ -162,31 +179,8 @@ public:
// -- friend functions -------------------------------------------------------
template <class Inspector>
friend auto inspect(Inspector& f, error& x) {
using result_type = typename Inspector::result_type;
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);
}
friend bool inspect(Inspector& f, error& x) {
return f.object(x).fields(f.field("data", x.data_));
}
private:
......@@ -196,19 +190,17 @@ private:
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 -------------------------------------------------------
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
CAF_CORE_EXPORT std::string to_string(const error& x);
......
......@@ -46,7 +46,6 @@ template <class> class stream_source;
template <class> class weak_intrusive_ptr;
template <class> struct inspector_access;
template <class> struct inspector_access_traits;
template <class> struct timeout_definition;
template <class> struct type_id;
......@@ -83,6 +82,7 @@ template <class...> class variant;
// -- classes ------------------------------------------------------------------
class [[nodiscard]] error;
class abstract_actor;
class abstract_group;
class actor;
......@@ -108,12 +108,12 @@ class config_value;
class deserializer;
class downstream_manager;
class downstream_manager_base;
class [[nodiscard]] error;
class event_based_actor;
class execution_unit;
class forwarding_actor_proxy;
class group;
class group_module;
class hashed_node_id;
class inbound_path;
class ipv4_address;
class ipv4_endpoint;
......@@ -128,6 +128,7 @@ class message_builder;
class message_handler;
class message_id;
class node_id;
class node_id_data;
class outbound_path;
class proxy_registry;
class ref_counted;
......@@ -156,18 +157,26 @@ class stateful_actor;
struct down_msg;
struct downstream_msg;
struct downstream_msg_batch;
struct downstream_msg_close;
struct downstream_msg_forced_close;
struct exit_msg;
struct group_down_msg;
struct illegal_message_element;
struct invalid_actor_addr_t;
struct invalid_actor_t;
struct node_down_msg;
struct none_t;
struct open_stream_msg;
struct prohibit_top_level_spawn_marker;
struct stream_slots;
struct timeout_msg;
struct unit_t;
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 --------------------------------------------------
......@@ -352,14 +361,9 @@ class dynamic_message_data;
class group_manager;
class message_data;
class private_thread;
class uri_impl;
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
CAF_CORE_EXPORT void intrusive_ptr_add_ref(const dynamic_message_data*);
CAF_CORE_EXPORT void intrusive_ptr_release(const dynamic_message_data*);
......
......@@ -80,14 +80,6 @@ public:
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 {
return ptr_.get();
}
......@@ -122,6 +114,42 @@ public:
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
private:
......@@ -140,11 +168,14 @@ CAF_CORE_EXPORT std::string to_string(const group& x);
} // namespace caf
namespace std {
template <>
struct hash<caf::group> {
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());
}
};
} // namespace std
......@@ -79,6 +79,11 @@ public:
/// Returns the module named `name` if it exists, otherwise `none`.
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:
// -- constructors, destructors, and assignment operators --------------------
......
......@@ -52,11 +52,10 @@ public:
/// @threadsafe
virtual expected<group> get(const std::string& group_name) = 0;
/// Loads a group of this module from `source` and stores it in `storage`.
virtual error load(deserializer& source, group& storage) = 0;
/// Loads a group of this module from `source` and stores it in `storage`.
virtual error_code<sec> load(binary_deserializer& source, group& storage) = 0;
/// Returns a pointer to the group associated with the name `group_name`.
/// @threadsafe
virtual expected<group>
get(const std::string& group_name, const caf::actor& dispatcher) = 0;
// -- observers --------------------------------------------------------------
......
......@@ -22,9 +22,11 @@
#include <type_traits>
#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/string_view.hpp"
#include "caf/type_id.hpp"
namespace caf::hash {
......@@ -37,69 +39,119 @@ namespace caf::hash {
///
/// @tparam T One of `uint32_t`, `uint64_t`, or `size_t`.
template <class T>
class fnv : public read_inspector<fnv<T>> {
class fnv : public save_inspector {
public:
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
}
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>
std::enable_if_t<std::is_integral<Integral>::value>
apply(Integral x) noexcept {
std::enable_if_t<std::is_integral<Integral>::value, bool>
value(Integral x) noexcept {
auto begin = reinterpret_cast<const uint8_t*>(&x);
append(begin, begin + sizeof(Integral));
return true;
}
void apply(bool x) noexcept {
bool value(bool x) noexcept {
auto tmp = static_cast<uint8_t>(x);
apply(tmp);
return value(tmp);
}
void apply(float x) noexcept {
apply(detail::pack754(x));
bool value(float x) noexcept {
return value(detail::pack754(x));
}
void apply(double x) noexcept {
apply(detail::pack754(x));
bool value(double x) noexcept {
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());
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());
append(begin, begin + x.size());
return true;
}
template <class Enum>
std::enable_if_t<std::is_enum<Enum>::value> apply(Enum x) noexcept {
return apply(static_cast<std::underlying_type_t<Enum>>(x));
}
void begin_sequence(size_t) noexcept {
// nop
}
void end_sequence() noexcept {
// nop
template <class Object>
constexpr auto object(Object&) noexcept {
return super::object_t<fnv>{type_name_or_anonymous<Object>(), this};
}
/// Convenience function for computing an FNV1a hash value for given
/// arguments in one shot.
template <class... Ts>
static T compute(Ts&&... xs) noexcept {
using detail::as_mutable_ref;
fnv f;
f(std::forward<Ts>(xs)...);
return f.value;
auto inspect_result = (inspect_object(f, as_mutable_ref(xs)) && ...);
// Discard inspection result: always true.
static_cast<void>(inspect_result);
return f.result;
}
T value;
T result;
private:
static constexpr T init() noexcept {
......@@ -112,10 +164,10 @@ private:
void append(const uint8_t* begin, const uint8_t* end) noexcept {
if constexpr (sizeof(T) == 4)
while (begin != end)
value = (*begin++ ^ value) * 0x01000193u;
result = (*begin++ ^ result) * 0x01000193u;
else
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 @@
#include <type_traits>
#include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
namespace caf {
/// Wraps tag types for static dispatching.
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.
struct empty {};
/// Flags allowed unsafe message types.
struct unsafe {};
/// Flags builtin integral types.
struct integral {};
/// Flags type with user-defined `inspect` overloads.
struct inspect {};
/// Flags native C array types.
struct array {};
/// Flags types with `std::tuple`-like API.
struct tuple {};
/// Flags type that specialize `inspector_access_boxed_value_traits`.
struct boxed_value {};
/// Flags types with `std::map`-like API.
struct map {};
/// Flags types with `std::vector`-like API.
struct list {};
/// Flags types without any default access.
struct none {};
};
/// @relates inspector_access_type
template <class T>
template <class Inspector, class T>
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{};
} else if constexpr (is_allowed_unsafe_message_type_v<T>) {
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) {
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{};
} else if constexpr (detail::is_map_like_v<T>) {
} else if constexpr (is_map_like_v<T>) {
return inspector_access_type::map{};
} else {
static_assert(detail::is_list_like_v<T>);
} else if constexpr (is_list_like_v<T>) {
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) {
}
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, new_round_result& x) {
return f(meta::type_name("new_round_result"), x.consumed_items, x.stop_all);
bool inspect(Inspector& f, new_round_result& x) {
return f.object(x).fields(f.field("consumed_items", x.consumed_items),
f.field("stop_all", x.stop_all));
}
} // namespace caf::intrusive
......@@ -49,6 +49,8 @@ public:
using element_type = T;
using value_type = T;
using reference = T&;
using const_reference = const T&;
......@@ -117,6 +119,11 @@ public:
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 {
reset(ptr);
return *this;
......
......@@ -104,9 +104,8 @@ public:
// -- inspection -------------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type
inspect(Inspector& f, ipv4_address& x) {
return f(x.bits_);
friend bool inspect(Inspector& f, ipv4_address& x) {
return f.object(x).fields(f.field("value", x.bits_));
}
private:
......
......@@ -72,9 +72,9 @@ public:
long compare(ipv4_endpoint x) const noexcept;
template <class Inspector>
friend typename Inspector::result_type
inspect(Inspector& f, ipv4_endpoint& x) {
return f(meta::type_name("ipv4_endpoint"), x.address_, x.port_);
friend bool inspect(Inspector& f, ipv4_endpoint& x) {
return f.object(x).fields(f.field("address", x.address_),
f.field("port", x.port_));
}
private:
......
......@@ -60,6 +60,14 @@ public:
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:
// -- member variables -------------------------------------------------------
......
......@@ -116,9 +116,9 @@ public:
// -- inspection -------------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type
friend bool
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);
......
......@@ -82,9 +82,9 @@ public:
long compare(ipv4_endpoint x) const noexcept;
template <class Inspector>
friend typename Inspector::result_type
inspect(Inspector& f, ipv6_endpoint& x) {
return f(meta::type_name("ipv6_endpoint"), x.address_, x.port_);
friend bool inspect(Inspector& f, ipv6_endpoint& x) {
return f.object(x).fields(f.field("address", x.address_),
f.field("port", x.port_));
}
private:
......
......@@ -90,8 +90,9 @@ public:
// -- inspection -------------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, ipv6_subnet& x) {
return f(x.address_, x.prefix_length_);
friend bool inspect(Inspector& f, ipv6_subnet& x) {
return f.object(x).fields(f.field("address", x.address_),
f.field("prefix_length", x.prefix_length_));
}
private:
......
......@@ -21,6 +21,8 @@
#include <type_traits>
#include <utility>
#include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/string_view.hpp"
......@@ -30,7 +32,7 @@ namespace caf {
/// from this class enables the inspector DSL.
/// @note The derived type still needs to provide an `object()` member function
/// for the DSL.
class load_inspector {
class CAF_CORE_EXPORT load_inspector {
public:
// -- constants --------------------------------------------------------------
......@@ -44,15 +46,37 @@ public:
/// Enables dispatching on the inspector type.
static constexpr bool is_loading = true;
/// A load inspector never reads the state of an object.
// -- legacy API -------------------------------------------------------------
static constexpr bool reads_state = false;
/// A load inspector overrides the state of an object.
static constexpr bool writes_state = true;
/// Inspecting objects, fields and values always returns a `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 -------------------------------------------
template <class T, class U, class Predicate>
......@@ -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>
struct object_t {
string_view object_name;
......@@ -260,6 +319,20 @@ public:
auto pretty_name(string_view name) && {
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 ------------------------------------------------------
......@@ -274,6 +347,9 @@ public:
using field_type = std::decay_t<decltype(get())>;
return virt_field_t<field_type, Set>{name, set};
}
protected:
error err_;
};
} // namespace caf
......@@ -106,13 +106,13 @@ public:
/// @relates mailbox_element
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, mailbox_element& x) {
return f(meta::type_name("mailbox_element"), x.sender, x.mid,
meta::omittable_if_empty(), x.stages,
bool inspect(Inspector& f, mailbox_element& x) {
return f.object(x).fields(f.field("sender", x.sender), f.field("mid", x.mid),
f.field("stages", x.stages),
#ifdef CAF_ENABLE_ACTOR_PROFILER
x.tracing_id,
f.field("tracing_id", x.tracing_id),
#endif // CAF_ENABLE_ACTOR_PROFILER
x.payload);
f.field("payload", x.payload));
}
/// @relates mailbox_element
......
......@@ -116,13 +116,13 @@ public:
// -- 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 ---------------------------------------------------------
......@@ -202,11 +202,13 @@ message make_message(Ts&&... xs) {
return message{std::move(ptr)};
}
/// @relates message
template <class Tuple, size_t... Is>
message make_message_from_tuple(Tuple&& xs, std::index_sequence<Is...>) {
return make_message(std::get<Is>(std::forward<Tuple>(xs))...);
}
/// @relates message
template <class Tuple>
message make_message_from_tuple(Tuple&& xs) {
using tuple_type = std::decay_t<Tuple>;
......@@ -215,20 +217,20 @@ message make_message_from_tuple(Tuple&& xs) {
}
/// @relates message
CAF_CORE_EXPORT error inspect(serializer& sink, const message& msg);
/// @relates message
CAF_CORE_EXPORT error_code<sec> inspect(binary_serializer& sink,
const message& msg);
/// @relates message
CAF_CORE_EXPORT error inspect(deserializer& source, message& msg);
template <class Inspector>
auto inspect(Inspector& f, message& x)
-> std::enable_if_t<Inspector::is_loading, decltype(x.load(f))> {
return x.load(f);
}
/// @relates message
CAF_CORE_EXPORT error_code<sec>
inspect(binary_deserializer& source, message& msg);
template <class Inspector>
auto inspect(Inspector& f, message& x)
-> std::enable_if_t<!Inspector::is_loading, decltype(x.save(f))> {
return x.save(f);
}
/// @relates message
CAF_CORE_EXPORT std::string to_string(const message& msg);
CAF_CORE_EXPORT std::string to_string(const message& x);
} // namespace caf
......@@ -26,6 +26,7 @@
#include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp"
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/message_priority.hpp"
#include "caf/meta/type_name.hpp"
......@@ -191,13 +192,6 @@ public:
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:
// -- member variables -------------------------------------------------------
......@@ -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};
}
// -- 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 std {
......
This diff is collapsed.
......@@ -23,9 +23,6 @@
#include <utility>
#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/unit.hpp"
......@@ -38,6 +35,8 @@ public:
/// Typdef for `T`.
using type = T;
using value_type = T;
/// Creates an instance without value.
optional(const none_t& = none) : m_valid(false) {
// nop
......@@ -146,6 +145,22 @@ public:
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:
void destroy() {
if (m_valid) {
......@@ -267,44 +282,11 @@ private:
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
template <class T>
std::string to_string(const optional<T>& x) {
return x ? "*" + deep_to_string(*x) : "none";
auto to_string(const optional<T>& x)
-> decltype(to_string(std::declval<const T&>())) {
return x ? "*" + to_string(*x) : "null";
}
/// Returns an rvalue to the value managed by `x`.
......
......@@ -178,9 +178,12 @@ public:
/// @relates outbound_path
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, outbound_path& x) {
return f(meta::type_name("outbound_path"), x.slots, x.hdl, x.next_batch_id,
x.open_credit, x.desired_batch_size, x.next_ack_id);
bool inspect(Inspector& f, outbound_path& x) {
return f.object(x).fields(f.field("slots", x.slots), f.field("hdl", x.hdl),
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
......@@ -18,7 +18,12 @@
#pragma once
#include <utility>
#include "caf/detail/core_export.hpp"
#include "caf/error.hpp"
#include "caf/inspector_access.hpp"
#include "caf/sec.hpp"
#include "caf/string_view.hpp"
namespace caf {
......@@ -27,7 +32,7 @@ namespace caf {
/// from this class enables the inspector DSL.
/// @note The derived type still needs to provide an `object()` member function
/// for the DSL.
class save_inspector {
class CAF_CORE_EXPORT save_inspector {
public:
// -- constants --------------------------------------------------------------
......@@ -41,15 +46,37 @@ public:
/// Enables dispatching on the inspector type.
static constexpr bool is_loading = false;
/// A save inspector only reads the state of an object.
// -- legacy API -------------------------------------------------------------
static constexpr bool reads_state = true;
/// A load inspector never modifies the state of an object.
static constexpr bool writes_state = false;
/// Inspecting objects, fields and values always returns a `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 -------------------------------------------
template <class T, class U>
......@@ -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>
struct object_t {
string_view object_name;
......@@ -152,6 +214,20 @@ public:
auto pretty_name(string_view name) && {
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 ------------------------------------------------------
......@@ -166,6 +242,9 @@ public:
using field_type = std::decay_t<decltype(get())>;
return virt_field_t<field_type, Get>{name, get};
}
protected:
error err_;
};
} // namespace caf
......@@ -61,7 +61,6 @@
#include "caf/sec.hpp"
#include "caf/stream_manager.hpp"
#include "caf/telemetry/timer.hpp"
#include "caf/to_string.hpp"
namespace caf {
......
......@@ -154,6 +154,10 @@ enum class sec : uint8_t {
invalid_field_type,
/// Serialization failed because a type was flagged as unsafe message 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
......
......@@ -29,7 +29,7 @@
#include "caf/fwd.hpp"
#include "caf/meta/annotation.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/read_inspector.hpp"
#include "caf/save_inspector.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
#include "caf/string_view.hpp"
......@@ -38,12 +38,8 @@ namespace caf {
/// @ingroup TypeSystem
/// Technology-independent serialization interface.
class CAF_CORE_EXPORT serializer : public read_inspector<serializer> {
class CAF_CORE_EXPORT serializer : public save_inspector {
public:
// -- member types -----------------------------------------------------------
using result_type = error;
// -- constructors, destructors, and assignment operators --------------------
explicit serializer(actor_system& sys) noexcept;
......@@ -58,88 +54,115 @@ public:
return context_;
}
bool has_human_readable_format() const noexcept {
return has_human_readable_format_;
}
// -- interface functions ----------------------------------------------------
/// Begins processing of an object. Saves the type information
/// 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.
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
/// to the underlying storage when in saving mode, otherwise
/// sets `num` accordingly.
virtual result_type begin_sequence(size_t num) = 0;
/// Begins processing of a tuple.
virtual bool begin_tuple(size_t size) = 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.
virtual result_type end_sequence() = 0;
virtual bool end_sequence() = 0;
/// Adds the primitive type `x` to the output.
/// @param x The primitive value.
/// @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
virtual result_type apply(int8_t x) = 0;
/// @copydoc value
virtual bool value(int8_t x) = 0;
/// @copydoc apply
virtual result_type apply(uint8_t x) = 0;
/// @copydoc value
virtual bool value(uint8_t x) = 0;
/// @copydoc apply
virtual result_type apply(int16_t x) = 0;
/// @copydoc value
virtual bool value(int16_t x) = 0;
/// @copydoc apply
virtual result_type apply(uint16_t x) = 0;
/// @copydoc value
virtual bool value(uint16_t x) = 0;
/// @copydoc apply
virtual result_type apply(int32_t x) = 0;
/// @copydoc value
virtual bool value(int32_t x) = 0;
/// @copydoc apply
virtual result_type apply(uint32_t x) = 0;
/// @copydoc value
virtual bool value(uint32_t x) = 0;
/// @copydoc apply
virtual result_type apply(int64_t x) = 0;
/// @copydoc value
virtual bool value(int64_t x) = 0;
/// @copydoc apply
virtual result_type apply(uint64_t x) = 0;
/// @copydoc value
virtual bool value(uint64_t x) = 0;
/// @copydoc apply
virtual result_type apply(float x) = 0;
/// @copydoc value
virtual bool value(float x) = 0;
/// @copydoc apply
virtual result_type apply(double x) = 0;
/// @copydoc value
virtual bool value(double x) = 0;
/// @copydoc apply
virtual result_type apply(long double x) = 0;
/// @copydoc value
virtual bool value(long double x) = 0;
/// @copydoc apply
virtual result_type apply(string_view x) = 0;
/// @copydoc value
virtual bool value(string_view x) = 0;
/// @copydoc apply
virtual result_type apply(const std::u16string& x) = 0;
/// @copydoc value
virtual bool value(const std::u16string& x) = 0;
/// @copydoc apply
virtual result_type apply(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));
}
/// @copydoc value
virtual bool value(const std::u32string& x) = 0;
/// Adds `x` as raw byte block to the output.
/// @param x The byte sequence.
/// @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
/// member function to pack the booleans, for example to avoid using one byte
/// 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:
/// Provides access to the ::proxy_registry and to the ::actor_system.
execution_unit* context_;
/// Configures whether client code should assume human-readable output.
bool has_human_readable_format_ = false;
};
} // namespace caf
......@@ -36,8 +36,8 @@ public:
/// @relates stream
template <class Inspector, class T>
auto inspect(Inspector& f, stream<T>&) {
return f(meta::type_name(type_name_v<stream<T>>));
auto inspect(Inspector& f, stream<T>& x) {
return f.object(x).fields();
}
} // namespace caf
......@@ -149,9 +149,8 @@ public:
// -- serialization ----------------------------------------------------------
template <class Inspector>
friend typename Inspector::result_type
inspect(Inspector& f, outbound_stream_slot& x) {
return f(x.value_);
friend bool inspect(Inspector& f, outbound_stream_slot& x) {
return f.object(x).fields(f.field("value_", x.value_));
}
private:
......@@ -160,8 +159,9 @@ private:
/// @relates stream_slots
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, stream_slots& x) {
return f(x.sender, x.receiver);
bool inspect(Inspector& f, stream_slots& x) {
return f.object(x).fields(f.field("sender", x.sender),
f.field("receiver", x.receiver));
}
} // namespace caf
......@@ -49,8 +49,9 @@ inline bool operator==(const exit_msg& x, const exit_msg& y) noexcept {
/// @relates exit_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, exit_msg& x) {
return f(meta::type_name("exit_msg"), x.source, x.reason);
bool inspect(Inspector& f, exit_msg& x) {
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.
......@@ -74,8 +75,9 @@ inline bool operator!=(const down_msg& x, const down_msg& y) noexcept {
/// @relates down_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, down_msg& x) {
return f(meta::type_name("down_msg"), x.source, x.reason);
bool inspect(Inspector& f, down_msg& x) {
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.
......@@ -86,8 +88,8 @@ struct group_down_msg {
/// @relates group_down_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, group_down_msg& x) {
return f(meta::type_name("group_down_msg"), x.source);
bool inspect(Inspector& f, group_down_msg& x) {
return f.object(x).fields(f.field("source", x.source));
}
/// 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,
/// @relates node_down_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, node_down_msg& x) {
return f(meta::type_name("node_down_msg"), x.node, x.reason);
bool inspect(Inspector& f, node_down_msg& x) {
return f.object(x).fields(f.field("node", x.node),
f.field("reason", x.reason));
}
/// Signalizes a timeout event.
......@@ -129,8 +132,9 @@ struct timeout_msg {
/// @relates timeout_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, timeout_msg& x) {
return f(meta::type_name("timeout_msg"), x.type, x.timeout_id);
bool inspect(Inspector& f, timeout_msg& x) {
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.
......@@ -154,9 +158,12 @@ struct open_stream_msg {
/// @relates open_stream_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, open_stream_msg& x) {
return f(meta::type_name("open_stream_msg"), x.slot, x.msg, x.prev_stage,
x.original_stage, x.priority);
bool inspect(Inspector& f, open_stream_msg& x) {
return f.object(x).fields(f.field("slot", x.slot), //
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
......@@ -34,27 +34,26 @@ public:
virtual ~tracing_data();
/// Writes the content of this object to `sink`.
virtual error serialize(serializer& sink) const = 0;
virtual bool serialize(serializer& sink) const = 0;
/// @copydoc serialize
virtual error_code<sec> serialize(binary_serializer& sink) const = 0;
virtual bool serialize(binary_serializer& sink) const = 0;
};
/// @relates tracing_data
using tracing_data_ptr = std::unique_ptr<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
CAF_CORE_EXPORT error_code<sec>
inspect(binary_serializer& sink, const tracing_data_ptr& x);
CAF_CORE_EXPORT bool inspect(binary_serializer& sink,
const tracing_data_ptr& x);
/// @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
CAF_CORE_EXPORT error_code<sec>
inspect(binary_deserializer& source, tracing_data_ptr& x);
CAF_CORE_EXPORT bool inspect(binary_deserializer& source, tracing_data_ptr& x);
} // namespace caf
......@@ -29,6 +29,7 @@
#include "caf/detail/squashed_int.hpp"
#include "caf/fwd.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/string_view.hpp"
#include "caf/timespan.hpp"
#include "caf/timestamp.hpp"
......@@ -67,7 +68,7 @@ struct type_name_by_id;
/// Convenience alias for `type_name_by_id<I>::value`.
/// @relates type_name_by_id
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>>`.
template <class T>
......@@ -77,13 +78,13 @@ struct type_name;
/// manually.
template <>
struct type_name<void> {
static constexpr const char* value = "void";
static constexpr string_view value = "void";
};
/// Convenience alias for `type_name<T>::value`.
/// @relates type_name
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.
constexpr type_id_t first_custom_type_id = 200;
......@@ -98,6 +99,15 @@ struct has_type_id {
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
/// Starts a code block for registering custom types to CAF. Stores the first ID
......@@ -133,7 +143,7 @@ struct has_type_id {
}; \
template <> \
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); \
}; \
template <> \
......@@ -155,7 +165,7 @@ struct has_type_id {
}; \
template <> \
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); \
}; \
template <> \
......@@ -176,8 +186,8 @@ struct has_type_id {
return false; \
} \
template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \
return f(caf::meta::type_name(#atom_name)); \
bool inspect(Inspector& f, atom_name& x) { \
return f.object(x).fields(); \
} \
CAF_ADD_TYPE_ID(project_name, (atom_name))
......@@ -193,8 +203,8 @@ struct has_type_id {
return false; \
} \
template <class Inspector> \
auto inspect(Inspector& f, atom_name&) { \
return f(caf::meta::type_name(#atom_namespace "::" #atom_name)); \
bool inspect(Inspector& f, atom_name& x) { \
return f.object(x).fields(); \
} \
} \
CAF_ADD_TYPE_ID(project_name, (atom_namespace::atom_name))
......@@ -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::down_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::exit_msg))
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_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_id))
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::none_t))
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::sec))
......@@ -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::unit_t))
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::weak_actor_ptr))
CAF_ADD_TYPE_ID(core_module, (std::vector<caf::actor>) )
......
......@@ -236,8 +236,8 @@ public:
}
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, typed_actor& x) {
return f(x.ptr_);
friend bool inspect(Inspector& f, typed_actor& x) {
return inspect(f, x.ptr_);
}
/// Releases the reference held by handle `x`. Using the
......
......@@ -35,13 +35,9 @@
namespace caf {
/// Stream messages that flow upstream, i.e., acks and drop messages.
struct CAF_CORE_EXPORT upstream_msg : tag::boxing_type {
// -- nested types -----------------------------------------------------------
/// Acknowledges a previous `open` message and finalizes a stream handshake.
/// Also signalizes initial demand.
struct ack_open {
/// Acknowledges a previous `open` message and finalizes a stream handshake.
/// Also signalizes initial demand.
struct upstream_msg_ack_open {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
......@@ -59,11 +55,11 @@ struct CAF_CORE_EXPORT upstream_msg : tag::boxing_type {
/// Desired size of individual batches.
int32_t desired_batch_size;
};
};
/// Cumulatively acknowledges received batches and signalizes new demand from
/// a sink to its source.
struct ack_batch {
/// Cumulatively acknowledges received batches and signalizes new demand from a
/// sink to its source.
struct upstream_msg_ack_batch {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
......@@ -79,23 +75,35 @@ struct CAF_CORE_EXPORT upstream_msg : tag::boxing_type {
/// Maximum capacity on this path. Stages can consider this metric for
/// downstream actors when calculating their own maximum capactiy.
int32_t max_capacity;
};
};
/// Asks the source to discard any remaining credit and close this path
/// after receiving an ACK for the last batch.
struct drop {
/// Asks the source to discard any remaining credit and close this path after
/// receiving an ACK for the last batch.
struct upstream_msg_drop {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
};
};
/// Propagates a fatal error from sinks to sources.
struct forced_drop {
/// Propagates a fatal error from sinks to sources.
struct upstream_msg_forced_drop {
/// Allows the testing DSL to unbox this type automagically.
using outer_type = upstream_msg;
/// Reason for shutting down the stream.
error reason;
};
};
/// Stream messages that flow upstream, i.e., acks and drop messages.
struct CAF_CORE_EXPORT upstream_msg : tag::boxing_type {
// -- nested types -----------------------------------------------------------
using ack_open = upstream_msg_ack_open;
using ack_batch = upstream_msg_ack_batch;
using drop = upstream_msg_drop;
using forced_drop = upstream_msg_forced_drop;
// -- member types -----------------------------------------------------------
......@@ -158,37 +166,40 @@ make(stream_slots slots, actor_addr addr, Ts&&... xs) {
/// @relates upstream_msg::ack_open
template <class Inspector>
typename Inspector::result_type
inspect(Inspector& f, upstream_msg::ack_open& x) {
return f(meta::type_name("ack_open"), x.rebind_from, x.rebind_to,
x.initial_demand, x.desired_batch_size);
bool inspect(Inspector& f, upstream_msg::ack_open& x) {
return f.object(x).fields(
f.field("rebind_from", x.rebind_from), f.field("rebind_to", x.rebind_to),
f.field("initial_demand", x.initial_demand),
f.field("desired_batch_size", x.desired_batch_size));
}
/// @relates upstream_msg::ack_batch
template <class Inspector>
typename Inspector::result_type
inspect(Inspector& f, upstream_msg::ack_batch& x) {
return f(meta::type_name("ack_batch"), x.new_capacity, x.desired_batch_size,
x.acknowledged_id, x.max_capacity);
bool inspect(Inspector& f, upstream_msg::ack_batch& x) {
return f.object(x).fields(f.field("new_capacity", x.new_capacity),
f.field("desired_batch_size", x.desired_batch_size),
f.field("acknowledged_id", x.acknowledged_id),
f.field("max_capacity", x.max_capacity));
}
/// @relates upstream_msg::drop
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, upstream_msg::drop&) {
return f(meta::type_name("drop"));
bool inspect(Inspector& f, upstream_msg::drop& x) {
return f.object(x).fields();
}
/// @relates upstream_msg::forced_drop
template <class Inspector>
typename Inspector::result_type
inspect(Inspector& f, upstream_msg::forced_drop& x) {
return f(meta::type_name("forced_drop"), x.reason);
bool inspect(Inspector& f, upstream_msg::forced_drop& x) {
return f.object(x).fields(f.field("reason", x.reason));
}
/// @relates upstream_msg
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, upstream_msg& x) {
return f(meta::type_name("upstream_msg"), x.slots, x.sender, x.content);
bool inspect(Inspector& f, upstream_msg& x) {
return f.object(x).fields(f.field("slots", x.slots),
f.field("sender", x.sender),
f.field("content", x.content));
}
} // namespace caf
......@@ -25,6 +25,9 @@
#include "caf/detail/core_export.hpp"
#include "caf/detail/unordered_flat_map.hpp"
#include "caf/fwd.hpp"
#include "caf/hash/fnv.hpp"
#include "caf/inspector_access.hpp"
#include "caf/intrusive_cow_ptr.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/ip_address.hpp"
#include "caf/string_view.hpp"
......@@ -36,10 +39,12 @@ namespace caf {
class CAF_CORE_EXPORT uri : detail::comparable<uri>,
detail::comparable<uri, string_view> {
public:
// -- member types -----------------------------------------------------------
// -- friends -
/// Pointer to implementation.
using impl_ptr = intrusive_ptr<const detail::uri_impl>;
template <class>
friend struct inspector_access;
// -- member types -----------------------------------------------------------
/// Host subcomponent of the authority component. Either an IP address or
/// an hostname as string.
......@@ -70,6 +75,71 @@ public:
/// Separates the query component into key-value pairs.
using query_map = detail::unordered_flat_map<std::string, std::string>;
class CAF_CORE_EXPORT impl_type {
public:
// -- constructors, destructors, and assignment operators ------------------
impl_type();
impl_type(const impl_type&) = delete;
impl_type& operator=(const impl_type&) = delete;
// -- member variables -----------------------------------------------------
/// 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());
}
bool unique() const noexcept {
return rc_.load() == 1;
}
// -- modifiers ------------------------------------------------------------
/// Assembles the human-readable string representation for this URI.
void assemble_str();
// -- friend functions -----------------------------------------------------
friend void intrusive_ptr_add_ref(const impl_type* p) {
p->rc_.fetch_add(1, std::memory_order_relaxed);
}
friend void intrusive_ptr_release(const impl_type* p) {
if (p->rc_ == 1 || p->rc_.fetch_sub(1, std::memory_order_acq_rel) == 1)
delete p;
}
private:
// -- member variables -----------------------------------------------------
mutable std::atomic<size_t> rc_;
};
/// Pointer to implementation.
using impl_ptr = intrusive_ptr<impl_type>;
// -- constructors, destructors, and assignment operators --------------------
uri();
......@@ -87,25 +157,44 @@ public:
// -- properties -------------------------------------------------------------
/// Returns whether all components of this URI are empty.
bool empty() const noexcept;
bool empty() const noexcept {
return str().empty();
}
/// Returns whether the URI contains valid content.
bool valid() const noexcept {
return !empty();
}
/// Returns the full URI as provided by the user.
string_view str() const noexcept;
string_view str() const noexcept {
return impl_->str;
}
/// Returns the scheme component.
string_view scheme() const noexcept;
string_view scheme() const noexcept {
return impl_->scheme;
}
/// Returns the authority component.
const authority_type& authority() const noexcept;
const authority_type& authority() const noexcept {
return impl_->authority;
}
/// Returns the path component as provided by the user.
string_view path() const noexcept;
string_view path() const noexcept {
return impl_->path;
}
/// Returns the query component as key-value map.
const query_map& query() const noexcept;
const query_map& query() const noexcept {
return impl_->query;
}
/// Returns the fragment component.
string_view fragment() const noexcept;
string_view fragment() const noexcept {
return impl_->fragment;
}
/// Returns a hash code over all components.
size_t hash_code() const noexcept;
......@@ -117,26 +206,19 @@ public:
// -- comparison -------------------------------------------------------------
int compare(const uri& other) const noexcept;
auto compare(const uri& other) const noexcept {
return str().compare(other.str());
}
int compare(string_view x) const noexcept;
auto compare(string_view x) const noexcept {
return str().compare(x);
}
// -- parsing ----------------------------------------------------------------
/// Returns whether `parse` would produce a valid URI.
static bool can_parse(string_view str) noexcept;
// -- friend functions -------------------------------------------------------
friend CAF_CORE_EXPORT error inspect(caf::serializer& dst, uri& x);
friend CAF_CORE_EXPORT error_code<sec>
inspect(caf::binary_serializer& dst, uri& x);
friend CAF_CORE_EXPORT error inspect(caf::deserializer& src, uri& x);
friend error_code<sec> inspect(caf::binary_deserializer& src, uri& x);
private:
impl_ptr impl_;
};
......@@ -144,8 +226,22 @@ private:
// -- related free functions ---------------------------------------------------
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri::authority_type& x) {
return f(x.userinfo, x.host, x.port);
bool inspect(Inspector& f, uri::authority_type& x) {
return f.object(x).fields(f.field("userinfo", x.userinfo),
f.field("host", x.host), f.field("port", x.port));
}
template <class Inspector>
bool inspect(Inspector& f, uri::impl_type& x) {
auto load_cb = [&] {
x.assemble_str();
return true;
};
return f.object(x)
.on_load(load_cb) //
.fields(f.field("str", x.str), f.field("scheme", x.scheme),
f.field("authority", x.authority), f.field("path", x.path),
f.field("query", x.query), f.field("fragment", x.fragment));
}
/// @relates uri
......@@ -160,6 +256,47 @@ CAF_CORE_EXPORT error parse(string_view str, uri& dest);
/// @relates uri
CAF_CORE_EXPORT expected<uri> make_uri(string_view str);
template <>
struct inspector_access<uri> : inspector_access_base<uri> {
template <class Inspector>
static bool apply_object(Inspector& f, uri& x) {
if (f.has_human_readable_format()) {
// TODO: extend the inspector DSL to promote string_view to std::string
// automatically to avoid unnecessary to_string conversions.
auto get = [&x] { return to_string(x); };
// TODO: setters should be able to return the error directly to avoid loss
// of information.
auto set = [&x](std::string str) {
auto err = parse(str, x);
return err.empty();
};
return f.object(x).fields(f.field("value", get, set));
} else {
if constexpr (Inspector::is_loading)
if (!x.impl_->unique())
x.impl_.reset(new uri::impl_type);
return inspect(f, *x.impl_);
}
}
template <class Inspector>
static bool apply_value(Inspector& f, uri& x) {
if (f.has_human_readable_format()) {
auto get = [&x] { return to_string(x); };
auto set = [&x](std::string str) {
auto err = parse(str, x);
return err.empty();
};
return inspect_value(f, get, set);
} else {
if constexpr (Inspector::is_loading)
if (!x.impl_->unique())
x.impl_.reset(new uri::impl_type);
return inspect(f, *x.impl_);
}
}
};
} // namespace caf
namespace std {
......@@ -167,7 +304,7 @@ namespace std {
template <>
struct hash<caf::uri> {
size_t operator()(const caf::uri& x) const noexcept {
return x.hash_code();
return caf::hash::fnv<size_t>::compute(x);
}
};
......
......@@ -32,7 +32,7 @@ public:
// -- member types -----------------------------------------------------------
/// Pointer to implementation.
using impl_ptr = intrusive_ptr<detail::uri_impl>;
using impl_ptr = intrusive_ptr<uri::impl_type>;
// -- constructors, destructors, and assignment operators --------------------
......
This diff is collapsed.
......@@ -33,7 +33,6 @@
#include "caf/scheduler/test_coordinator.hpp"
#include "caf/send.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/to_string.hpp"
namespace caf {
......@@ -294,13 +293,13 @@ actor_system::actor_system(actor_system_config& cfg)
// Make sure meta objects are loaded.
auto gmos = detail::global_meta_objects();
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::init_global_meta_objects<>() before");
}
if (modules_[module::middleman] != nullptr) {
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::io::middleman::init_global_meta_objects() before");
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -34,7 +34,7 @@ namespace {
struct dyn_type_id_list {
explicit dyn_type_id_list(type_id_t* storage) noexcept : storage(storage) {
CAF_ASSERT(storage != nullptr);
auto first = reinterpret_cast<const uint8_t*>(storage);
auto first = reinterpret_cast<const byte*>(storage);
auto last = first + ((storage[0] + 1) * sizeof(type_id_t));
hash = caf::hash::fnv<size_t>::compute(make_span(first, last));
}
......
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