Commit 31453f21 authored by Dominik Charousset's avatar Dominik Charousset

Extend inspector API with virtual objects

parent 7dd87b94
......@@ -51,6 +51,26 @@ public:
/// Reads run-time-type information for the next object if available.
virtual bool fetch_next_object_type(type_id_t& type) = 0;
/// Reads run-time-type information for the next object if available. The
/// default implementation calls `fetch_next_object_type` and queries the CAF
/// type name. However, implementations of the interface may retrieve the type
/// name differently and the type name may not correspond to any type known to
/// CAF. For example. the @ref json_reader returns the content of the `@type`
/// field of the current object if available.
/// @warning the characters in `type_name` may point to an internal buffer
/// that becomes invalid as soon as calling *any* other member
/// function on the deserializer. Convert the `type_name` to a string
/// before storing it.
virtual bool fetch_next_object_name(string_view& type_name);
/// Convenience function for querying `fetch_next_object_name` comparing the
/// result to `type_name` in one shot.
bool next_object_name_matches(string_view type_name);
/// Like `next_object_name_matches`, but sets an error on the deserializer
/// on a mismatch.
bool assert_next_object_name(string_view type_name);
/// Begins processing of an object, may perform a type check depending on the
/// data format.
/// @param type 16-bit ID for known types, @ref invalid_type_id otherwise.
......
......@@ -95,9 +95,6 @@ public:
// -- modifiers --------------------------------------------------------------
/// Removes any loaded JSON data and reclaims all memory resources.
void reset();
/// Parses @p json_text into an internal representation. After loading the
/// JSON input, the reader is ready for attempting to deserialize inspectable
/// objects.
......@@ -112,10 +109,15 @@ public:
/// inspectable object.
void revert();
/// Removes any loaded JSON data and reclaims memory resources.
void reset();
// -- overrides --------------------------------------------------------------
bool fetch_next_object_type(type_id_t& type) override;
bool fetch_next_object_name(string_view& type_name) override;
bool begin_object(type_id_t type, string_view name) override;
bool end_object() override;
......
......@@ -29,6 +29,10 @@ public:
type_name_or_anonymous<T>(), dptr()};
}
constexpr auto virtual_object(string_view type_name) noexcept {
return super::object_t<Subtype>{invalid_type_id, type_name, dptr()};
}
template <class T>
bool list(T& xs) {
xs.clear();
......
......@@ -24,6 +24,10 @@ public:
type_name_or_anonymous<T>(), dptr()};
}
constexpr auto virtual_object(string_view type_name) noexcept {
return super::object_t<Subtype>{invalid_type_id, type_name, dptr()};
}
template <class T>
bool list(const T& xs) {
using value_type = typename T::value_type;
......
......@@ -21,6 +21,44 @@ deserializer::~deserializer() {
// nop
}
bool deserializer::fetch_next_object_name(string_view& type_name) {
auto t = type_id_t{};
if (fetch_next_object_type(t)) {
type_name = query_type_name(t);
return true;
} else {
return false;
}
}
bool deserializer::next_object_name_matches(string_view type_name) {
string_view found;
if (fetch_next_object_name(found)) {
return type_name == found;
} else {
return false;
}
}
bool deserializer::assert_next_object_name(string_view type_name) {
string_view found;
if (fetch_next_object_name(found)) {
if (type_name == found) {
return true;
} else {
std::string str = "required type ";
str.insert(str.end(), type_name.begin(), type_name.end());
str += ", got ";
str.insert(str.end(), found.begin(), found.end());
emplace_error(sec::type_clash, __func__, std::move(str));
return false;
}
} else {
emplace_error(sec::runtime_error, __func__, "no type name available");
return false;
}
}
bool deserializer::begin_key_value_pair() {
return begin_tuple(2);
}
......
......@@ -120,11 +120,6 @@ json_reader::~json_reader() {
// -- modifiers --------------------------------------------------------------
void json_reader::reset() {
buf_.reclaim();
st_ = nullptr;
}
bool json_reader::load(string_view json_text) {
reset();
string_parser_state ps{json_text.begin(), json_text.end()};
......@@ -152,25 +147,40 @@ void json_reader::revert() {
}
}
void json_reader::reset() {
buf_.reclaim();
st_ = nullptr;
err_.reset();
}
// -- interface functions ------------------------------------------------------
bool json_reader::fetch_next_object_type(type_id_t& type) {
string_view type_name;
if (fetch_next_object_name(type_name)) {
if (auto id = query_type_id(type_name); id != invalid_type_id) {
type = id;
return true;
} else {
std::string what = "no type ID available for @type: ";
what.insert(what.end(), type_name.begin(), type_name.end());
emplace_error(sec::runtime_error, class_name, __func__, std::move(what));
return false;
}
} else {
return false;
}
}
bool json_reader::fetch_next_object_name(string_view& type_name) {
FN_DECL;
return consume<false>(fn, [this, &type](const detail::json::value& val) {
return consume<false>(fn, [this, &type_name](const detail::json::value& val) {
if (val.data.index() == detail::json::value::object_index) {
auto& obj = get<detail::json::object>(val.data);
if (auto mem_ptr = find_member(&obj, "@type")) {
if (mem_ptr->val->data.index() == detail::json::value::string_index) {
auto str = std::get<string_view>(mem_ptr->val->data);
if (auto id = query_type_id(str); id != invalid_type_id) {
type = id;
return true;
} else {
std::string what = "found an unknown @type: ";
what.insert(what.end(), str.begin(), str.end());
emplace_error(sec::runtime_error, class_name, fn, std::move(what));
return false;
}
type_name = std::get<string_view>(mem_ptr->val->data);
return true;
} else {
emplace_error(sec::runtime_error, class_name, fn,
"expected a string argument to @type");
......
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