Skip to content

Commit

Permalink
Support variant types in json_reader
Browse files Browse the repository at this point in the history
  • Loading branch information
Neverlord committed Feb 22, 2021
1 parent c2b3e26 commit 5d6d6b4
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 9 deletions.
21 changes: 21 additions & 0 deletions libcaf_core/caf/json_reader.hpp
Expand Up @@ -79,6 +79,11 @@ class CAF_CORE_EXPORT json_reader : public deserializer {
invalid,
};

// -- constants --------------------------------------------------------------

/// The value value for `field_type_suffix()`.
static constexpr string_view field_type_suffix_default = "-type";

// -- constructors, destructors, and assignment operators --------------------

json_reader();
Expand All @@ -93,6 +98,20 @@ class CAF_CORE_EXPORT json_reader : public deserializer {

~json_reader() override;

// -- properties -------------------------------------------------------------

/// Returns the suffix for generating type annotation fields for variant
/// fields. For example, CAF inserts field called "@foo${field_type_suffix}"
/// for a variant field called "foo".
[[nodiscard]] string_view field_type_suffix() const noexcept {
return field_type_suffix_;
}

/// Configures whether the writer omits empty fields.
void field_type_suffix(string_view suffix) noexcept {
field_type_suffix_ = suffix;
}

// -- modifiers --------------------------------------------------------------

/// Parses @p json_text into an internal representation. After loading the
Expand Down Expand Up @@ -217,6 +236,8 @@ class CAF_CORE_EXPORT json_reader : public deserializer {
stack_type* st_ = nullptr;

detail::json::value* root_ = nullptr;

string_view field_type_suffix_ = field_type_suffix_default;
};

} // namespace caf
61 changes: 52 additions & 9 deletions libcaf_core/src/json_reader.cpp
Expand Up @@ -6,6 +6,7 @@

#include "caf/detail/bounds_checker.hpp"
#include "caf/detail/print.hpp"
#include "caf/string_algorithms.hpp"

namespace {

Expand Down Expand Up @@ -77,6 +78,24 @@ find_member(const caf::detail::json::object* obj, caf::string_view key) {
return nullptr;
}

caf::string_view field_type(const caf::detail::json::object* obj,
caf::string_view name, caf::string_view suffix) {
namespace json = caf::detail::json;
for (const auto& member : *obj) {
if (member.val && member.val->data.index() == json::value::string_index
&& !member.key.empty() && member.key[0] == '@') {
auto key = member.key;
key.remove_prefix(1);
if (caf::starts_with(key, name)) {
key.remove_prefix(name.size());
if (key == suffix)
return std::get<caf::string_view>(member.val->data);
}
}
}
return {};
}

} // namespace

#define FN_DECL static constexpr const char* fn = __func__
Expand Down Expand Up @@ -258,17 +277,41 @@ bool json_reader::begin_field(string_view name, bool& is_present) {
return true;
}

bool json_reader::begin_field(string_view, span<const type_id_t>, size_t&) {
emplace_error(sec::runtime_error, class_name, __func__,
"variant fields are currently not supported for JSON input");
return false;
bool json_reader::begin_field(string_view name, span<const type_id_t> types,
size_t& index) {
bool is_present = false;
if (begin_field(name, is_present, types, index)) {
if (is_present) {
return true;
} else {
emplace_error(sec::runtime_error, class_name, __func__,
"mandatory field missing");
return false;
}
} else {
return false;
}
}

bool json_reader::begin_field(string_view, bool&, span<const type_id_t>,
size_t&) {
emplace_error(sec::runtime_error, class_name, __func__,
"variant fields are currently not supported for JSON input");
return false;
bool json_reader::begin_field(string_view name, bool& is_present,
span<const type_id_t> types, size_t& index) {
SCOPE(position::object);
if (auto member = find_member(top<position::object>(), name);
member != nullptr
&& member->val->data.index() != detail::json::value::null_index) {
auto ft = field_type(top<position::object>(), name, field_type_suffix_);
if (auto id = query_type_id(ft); id != invalid_type_id) {
if (auto i = std::find(types.begin(), types.end(), id);
i != types.end()) {
index = static_cast<size_t>(std::distance(types.begin(), i));
push(member->val);
is_present = true;
return true;
}
}
}
is_present = false;
return true;
}

bool json_reader::end_field() {
Expand Down
14 changes: 14 additions & 0 deletions libcaf_core/test/json_reader.cpp
Expand Up @@ -93,6 +93,20 @@ fixture::fixture() {
R"({"Bob": 5556837,)"
R"( "Jon": 5559347}})",
phone_book{"Model City", {{"Bob", 5556837}, {"Jon", 5559347}}});
add_test_case(R"({"@type": "widget", )"
R"("color": "red", )"
R"("@shape-type": "circle", )"
R"("shape": )"
R"({"center": {"x": 15, "y": 15}, )"
R"("radius": 5}})",
widget{"red", circle{{15, 15}, 5}});
add_test_case(R"({"@type": "widget", )"
R"("color": "blue", )"
R"("@shape-type": "rectangle", )"
R"("shape": )"
R"({"top-left": {"x": 10, "y": 10}, )"
R"("bottom-right": {"x": 20, "y": 20}}})",
widget{"blue", rectangle{{10, 10}, {20, 20}}});
}

} // namespace
Expand Down

0 comments on commit 5d6d6b4

Please sign in to comment.