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

Merge pull request #1192

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