Commit ac392c0f authored by Dominik Charousset's avatar Dominik Charousset

Support variant types in json_reader

parent f453061e
...@@ -79,6 +79,11 @@ public: ...@@ -79,6 +79,11 @@ public:
invalid, invalid,
}; };
// -- constants --------------------------------------------------------------
/// The value value for `field_type_suffix()`.
static constexpr string_view field_type_suffix_default = "-type";
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
json_reader(); json_reader();
...@@ -93,6 +98,20 @@ public: ...@@ -93,6 +98,20 @@ public:
~json_reader() override; ~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 -------------------------------------------------------------- // -- modifiers --------------------------------------------------------------
/// Parses @p json_text into an internal representation. After loading the /// Parses @p json_text into an internal representation. After loading the
...@@ -217,6 +236,8 @@ private: ...@@ -217,6 +236,8 @@ private:
stack_type* st_ = nullptr; stack_type* st_ = nullptr;
detail::json::value* root_ = nullptr; detail::json::value* root_ = nullptr;
string_view field_type_suffix_ = field_type_suffix_default;
}; };
} // namespace caf } // namespace caf
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "caf/detail/bounds_checker.hpp" #include "caf/detail/bounds_checker.hpp"
#include "caf/detail/print.hpp" #include "caf/detail/print.hpp"
#include "caf/string_algorithms.hpp"
namespace { namespace {
...@@ -77,6 +78,24 @@ find_member(const caf::detail::json::object* obj, caf::string_view key) { ...@@ -77,6 +78,24 @@ find_member(const caf::detail::json::object* obj, caf::string_view key) {
return nullptr; 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 } // namespace
#define FN_DECL static constexpr const char* fn = __func__ #define FN_DECL static constexpr const char* fn = __func__
...@@ -258,17 +277,41 @@ bool json_reader::begin_field(string_view name, bool& is_present) { ...@@ -258,17 +277,41 @@ bool json_reader::begin_field(string_view name, bool& is_present) {
return true; return true;
} }
bool json_reader::begin_field(string_view, span<const type_id_t>, size_t&) { bool json_reader::begin_field(string_view name, span<const type_id_t> types,
emplace_error(sec::runtime_error, class_name, __func__, size_t& index) {
"variant fields are currently not supported for JSON input"); bool is_present = false;
return 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>, bool json_reader::begin_field(string_view name, bool& is_present,
size_t&) { span<const type_id_t> types, size_t& index) {
emplace_error(sec::runtime_error, class_name, __func__, SCOPE(position::object);
"variant fields are currently not supported for JSON input"); if (auto member = find_member(top<position::object>(), name);
return false; 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() { bool json_reader::end_field() {
......
...@@ -93,6 +93,20 @@ fixture::fixture() { ...@@ -93,6 +93,20 @@ fixture::fixture() {
R"({"Bob": 5556837,)" R"({"Bob": 5556837,)"
R"( "Jon": 5559347}})", R"( "Jon": 5559347}})",
phone_book{"Model City", {{"Bob", 5556837}, {"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 } // namespace
......
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