From eafa3aff8531bef5888e0e11f75e6bca3ddb890c Mon Sep 17 00:00:00 2001 From: sha512sum Date: Sun, 10 Nov 2024 14:56:41 +0000 Subject: [PATCH] Add serialization and deserialization for vector --- library/include/larra/serialization.hpp | 43 +++++++++++++++++++- library/include/larra/serialization/auto.hpp | 20 +++++++++ tests/serialization.cpp | 27 ++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/library/include/larra/serialization.hpp b/library/include/larra/serialization.hpp index a24e0a8..25a0bd6 100644 --- a/library/include/larra/serialization.hpp +++ b/library/include/larra/serialization.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -169,8 +170,8 @@ struct Serialization> : SerializationBase<> { } static constexpr auto Serialize(xmlpp::Element* element, const std::variant& object) -> void { std::visit( - [&](const auto& object) { - element << object; + [&](const T& object) { + Serialization::Serialize(element, object); }, object); } @@ -191,4 +192,42 @@ struct Serialization : SerializationBase<> { } }; +template +struct Serialization> : SerializationBase<> { + static constexpr auto Parse(xmlpp::Element* element) -> std::vector { + return element->get_children(Serialization::kDefaultName) | std::views::transform([](xmlpp::Node* node) { + auto itemElement = dynamic_cast(node); + if(!itemElement) { + throw serialization::ParsingError{"Can't convert xmlpp::Node to xmlpp::Element ]"}; + } + return Serialization::Parse(itemElement); + }) | + std::ranges::to>(); + } + static constexpr auto TryParse(xmlpp::Element* element) -> std::optional> { + auto chd = element->get_children(Serialization::kDefaultName); + auto range = chd | std::views::transform([](xmlpp::Node* node) -> std::optional { + auto itemElement = dynamic_cast(node); + if(!itemElement) { + return std::nullopt; + } + return Serialization::TryParse(itemElement); + }); + std::vector response; + response.reserve(chd.size()); + for(auto& value : range) { + if(!value) { + return std::nullopt; + } + response.push_back(std::move(*value)); + } + return response; + } + static constexpr auto Serialize(xmlpp::Element* node, const std::vector& value) -> void { + for(const T& element : value) { + Serialization::Serialize(node->add_child_element(Serialization::kDefaultName), element); + } + } +}; + } // namespace larra::xmpp diff --git a/library/include/larra/serialization/auto.hpp b/library/include/larra/serialization/auto.hpp index 6d85d72..83dc3ab 100644 --- a/library/include/larra/serialization/auto.hpp +++ b/library/include/larra/serialization/auto.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -154,6 +155,25 @@ struct ElementSerializer { } }; +template +struct ElementSerializer, Config, Info> { + static constexpr auto Parse(xmlpp::Element* element) { + try { + return Serialization>::Parse(element); + } catch(const std::exception& error) { + throw ElementParsingError( + std::format("[{}: {}] parsing error: [ {} ]", Info::kName, nameof::nameof_full_type>(), error.what())); + } + } + static constexpr auto Serialize(xmlpp::Element* node, const std::vector& element) { + try { + return Serialization>::Serialize(node, element); + } catch(const std::exception& error) { + throw ElementSerializaionError( + std::format("[{}: {}] serialization error: [ {} ]", Info::kName, nameof::nameof_full_type>(), error.what())); + } + } +}; namespace impl { template diff --git a/tests/serialization.cpp b/tests/serialization.cpp index 3e724a9..7221a49 100644 --- a/tests/serialization.cpp +++ b/tests/serialization.cpp @@ -37,6 +37,7 @@ struct SomeStruct { std::string value; [[nodiscard]] static auto Parse(xmlpp::Element* element) -> SomeStruct; friend auto operator<<(xmlpp::Element* element, const SomeStruct& self); + constexpr auto operator==(const SomeStruct&) const -> bool = default; }; struct SomeStruct2 { @@ -65,6 +66,12 @@ struct SomeStruct5 { friend auto operator<<(xmlpp::Element* element, const SomeStruct5& self); }; +struct SomeStruct6 { + static constexpr auto kDefaultName = "some6"; + std::vector some; + [[nodiscard]] static auto Parse(xmlpp::Element* element) -> SomeStruct6; +}; + } // namespace tests::serialization namespace serialization { @@ -81,6 +88,9 @@ constexpr auto kSerializationConfig = Seriali template <> constexpr auto kSerializationConfig = SerializationConfig{}; +template <> +constexpr auto kSerializationConfig = + SerializationConfig{}.With<"some">({Config>{}}); } // namespace serialization namespace tests::serialization { @@ -105,6 +115,10 @@ auto SomeStruct5::Parse(xmlpp::Element* element) -> SomeStruct5 { return ::larra::xmpp::serialization::Parse(element); } +auto SomeStruct6::Parse(xmlpp::Element* element) -> SomeStruct6 { + return ::larra::xmpp::serialization::Parse(element); +} + auto operator<<(xmlpp::Element* element, const SomeStruct& self) { ::larra::xmpp::serialization::Serialize(element, self); } @@ -144,6 +158,19 @@ TEST(AutoParse, Attribute) { EXPECT_EQ(a.value.username, "user"sv); } +TEST(AutoParse, Vector) { + xmlpp::Document doc; + auto node = doc.create_root_node("some6"); + for(auto i : std::views::iota(0, 10)) { + auto child = node->add_child_element("some"); + child->set_attribute("value", std::format("Hello {}", i)); + } + auto value = Serialization::Parse(node); + EXPECT_EQ(value.some, std::views::iota(0, 10) | std::views::transform([](auto i) -> tests::serialization::SomeStruct { + return {.value = std::format("Hello {}", i)}; + }) | std::ranges::to>()); +} + TEST(AutoSerialize, Basic) { xmlpp::Document doc; auto node = doc.create_root_node("some2");