diff --git a/docs/generic.md b/docs/generic.md index 99005d1b..8fde288a 100644 --- a/docs/generic.md +++ b/docs/generic.md @@ -5,7 +5,7 @@ reflect-cpp is intended to be used to directly parse into structs. Doing this is But in some cases, we simply cannot anticipate the complete structure of the data at compile time. For these cases, we have `rfl::Generic`. -Note that generics are not supported for Avro. +Note that generics are not supported for Avro. For XML, generics are supported but only for writing, not for reading. `rfl::Generic` is a convenience wrapper around the following type: diff --git a/include/rfl/xml/Parser.hpp b/include/rfl/xml/Parser.hpp index 2f2c4ca0..f04b7183 100644 --- a/include/rfl/xml/Parser.hpp +++ b/include/rfl/xml/Parser.hpp @@ -3,39 +3,65 @@ #include +#include "../Generic.hpp" +#include "../always_false.hpp" #include "../internal/is_attribute.hpp" #include "../parsing/NamedTupleParser.hpp" #include "../parsing/Parser.hpp" #include "Reader.hpp" #include "Writer.hpp" -namespace rfl { -namespace parsing { +namespace rfl::parsing { /// XML is very special. It doesn't have proper support for arrays, which means /// that we just need to ignore empty containers. Therefore, we need to a /// template specialization for the NamedTuple parser to accommodate for it. template -requires AreReaderAndWriter> + requires AreReaderAndWriter> struct Parser, ProcessorsType> : public NamedTupleParser { -}; + FieldTypes...> {}; + +/// The generic parser is also special, because we need to ignore empty +/// containers, which means that we need to try to read the value as an array or +/// object before trying to read it as a string. Therefore, we need to a +/// template specialization for the generic parser to accommodate for it. +template + requires AreReaderAndWriter +struct Parser { + using InputVarType = typename xml::Reader::InputVarType; + + static Result read(const xml::Reader& _r, + const InputVarType& _var) noexcept { + static_assert(always_false_v, + "XML does not support reading generic types."); + return error("XML does not support reading generic types."); + } -} // namespace parsing -} // namespace rfl + static void write(const xml::Writer& _w, const Generic& _generic, + const auto& _parent) { + Parser::write(_w, _generic.reflection(), _parent); + } + + static schema::Type to_schema( + std::map* _definitions) { + return Parser::to_schema(_definitions); + } +}; -namespace rfl { -namespace xml { +} // namespace rfl::parsing +namespace rfl::xml { template using Parser = parsing::Parser; -} -} // namespace rfl +} // namespace rfl::xml #endif diff --git a/include/rfl/xml/Reader.hpp b/include/rfl/xml/Reader.hpp index fdbc5242..8f096c70 100644 --- a/include/rfl/xml/Reader.hpp +++ b/include/rfl/xml/Reader.hpp @@ -13,8 +13,7 @@ #include "../always_false.hpp" #include "../parsing/is_view_reader.hpp" -namespace rfl { -namespace xml { +namespace rfl::xml { struct Reader { struct XMLInputArray { @@ -85,7 +84,14 @@ struct Reader { return std::visit(get_value, _var.node_or_attribute_); } else if constexpr (std::is_same, bool>()) { - return std::visit(get_value, _var.node_or_attribute_) == "true"; + const auto val = std::visit(get_value, _var.node_or_attribute_); + if (val == "true" || val == "1") { + return true; + } else if (val == "false" || val == "0") { + return false; + } else { + return error("Could not cast '" + val + "' to boolean."); + } } else if constexpr (std::is_floating_point>()) { const auto str = std::visit(get_value, _var.node_or_attribute_); @@ -178,7 +184,6 @@ struct Reader { } }; -} // namespace xml -} // namespace rfl +} // namespace rfl::xml #endif diff --git a/tests/xml/test_generic.cpp b/tests/xml/test_generic.cpp new file mode 100644 index 00000000..eac439bb --- /dev/null +++ b/tests/xml/test_generic.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include "write_and_read.hpp" + +namespace test_generic { + +TEST(xml, test_generic) { + rfl::Generic::Object cat; + cat["name"] = "Cachou"; + cat["colour"] = "black"; + cat["species"] = "cat"; + + const auto xml_string = rfl::xml::write<"cat">(cat); + + EXPECT_EQ(xml_string, + R"( + + Cachou + black + cat + +)"); +} +} // namespace test_generic