Add serialization and deserialization for vector
This commit is contained in:
parent
efcbc8e86a
commit
eafa3aff85
3 changed files with 88 additions and 2 deletions
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <larra/serialization/error.hpp>
|
#include <larra/serialization/error.hpp>
|
||||||
#include <nameof.hpp>
|
#include <nameof.hpp>
|
||||||
|
#include <ranges>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utempl/utils.hpp>
|
#include <utempl/utils.hpp>
|
||||||
|
|
||||||
|
@ -169,8 +170,8 @@ struct Serialization<std::variant<Ts...>> : SerializationBase<> {
|
||||||
}
|
}
|
||||||
static constexpr auto Serialize(xmlpp::Element* element, const std::variant<Ts...>& object) -> void {
|
static constexpr auto Serialize(xmlpp::Element* element, const std::variant<Ts...>& object) -> void {
|
||||||
std::visit(
|
std::visit(
|
||||||
[&](const auto& object) {
|
[&]<typename T>(const T& object) {
|
||||||
element << object;
|
Serialization<T>::Serialize(element, object);
|
||||||
},
|
},
|
||||||
object);
|
object);
|
||||||
}
|
}
|
||||||
|
@ -191,4 +192,42 @@ struct Serialization<std::monostate> : SerializationBase<> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Serialization<std::vector<T>> : SerializationBase<> {
|
||||||
|
static constexpr auto Parse(xmlpp::Element* element) -> std::vector<T> {
|
||||||
|
return element->get_children(Serialization<T>::kDefaultName) | std::views::transform([](xmlpp::Node* node) {
|
||||||
|
auto itemElement = dynamic_cast<xmlpp::Element*>(node);
|
||||||
|
if(!itemElement) {
|
||||||
|
throw serialization::ParsingError{"Can't convert xmlpp::Node to xmlpp::Element ]"};
|
||||||
|
}
|
||||||
|
return Serialization<T>::Parse(itemElement);
|
||||||
|
}) |
|
||||||
|
std::ranges::to<std::vector<T>>();
|
||||||
|
}
|
||||||
|
static constexpr auto TryParse(xmlpp::Element* element) -> std::optional<std::vector<T>> {
|
||||||
|
auto chd = element->get_children(Serialization<T>::kDefaultName);
|
||||||
|
auto range = chd | std::views::transform([](xmlpp::Node* node) -> std::optional<T> {
|
||||||
|
auto itemElement = dynamic_cast<xmlpp::Element*>(node);
|
||||||
|
if(!itemElement) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return Serialization<T>::TryParse(itemElement);
|
||||||
|
});
|
||||||
|
std::vector<T> 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<T>& value) -> void {
|
||||||
|
for(const T& element : value) {
|
||||||
|
Serialization<T>::Serialize(node->add_child_element(Serialization<T>::kDefaultName), element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace larra::xmpp
|
} // namespace larra::xmpp
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <boost/pfr.hpp>
|
#include <boost/pfr.hpp>
|
||||||
#include <larra/serialization.hpp>
|
#include <larra/serialization.hpp>
|
||||||
#include <larra/serialization/error.hpp>
|
#include <larra/serialization/error.hpp>
|
||||||
|
#include <ranges>
|
||||||
#include <utempl/constexpr_string.hpp>
|
#include <utempl/constexpr_string.hpp>
|
||||||
#include <utempl/tuple.hpp>
|
#include <utempl/tuple.hpp>
|
||||||
#include <utempl/utils.hpp>
|
#include <utempl/utils.hpp>
|
||||||
|
@ -154,6 +155,25 @@ struct ElementSerializer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, auto& Config, typename Info>
|
||||||
|
struct ElementSerializer<std::vector<T>, Config, Info> {
|
||||||
|
static constexpr auto Parse(xmlpp::Element* element) {
|
||||||
|
try {
|
||||||
|
return Serialization<std::vector<T>>::Parse(element);
|
||||||
|
} catch(const std::exception& error) {
|
||||||
|
throw ElementParsingError(
|
||||||
|
std::format("[{}: {}] parsing error: [ {} ]", Info::kName, nameof::nameof_full_type<std::vector<T>>(), error.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static constexpr auto Serialize(xmlpp::Element* node, const std::vector<T>& element) {
|
||||||
|
try {
|
||||||
|
return Serialization<std::vector<T>>::Serialize(node, element);
|
||||||
|
} catch(const std::exception& error) {
|
||||||
|
throw ElementSerializaionError(
|
||||||
|
std::format("[{}: {}] serialization error: [ {} ]", Info::kName, nameof::nameof_full_type<std::vector<T>>(), error.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct SomeStruct {
|
||||||
std::string value;
|
std::string value;
|
||||||
[[nodiscard]] static auto Parse(xmlpp::Element* element) -> SomeStruct;
|
[[nodiscard]] static auto Parse(xmlpp::Element* element) -> SomeStruct;
|
||||||
friend auto operator<<(xmlpp::Element* element, const SomeStruct& self);
|
friend auto operator<<(xmlpp::Element* element, const SomeStruct& self);
|
||||||
|
constexpr auto operator==(const SomeStruct&) const -> bool = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SomeStruct2 {
|
struct SomeStruct2 {
|
||||||
|
@ -65,6 +66,12 @@ struct SomeStruct5 {
|
||||||
friend auto operator<<(xmlpp::Element* element, const SomeStruct5& self);
|
friend auto operator<<(xmlpp::Element* element, const SomeStruct5& self);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SomeStruct6 {
|
||||||
|
static constexpr auto kDefaultName = "some6";
|
||||||
|
std::vector<SomeStruct> some;
|
||||||
|
[[nodiscard]] static auto Parse(xmlpp::Element* element) -> SomeStruct6;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace tests::serialization
|
} // namespace tests::serialization
|
||||||
|
|
||||||
namespace serialization {
|
namespace serialization {
|
||||||
|
@ -81,6 +88,9 @@ constexpr auto kSerializationConfig<tests::serialization::SomeStruct4> = Seriali
|
||||||
template <>
|
template <>
|
||||||
constexpr auto kSerializationConfig<tests::serialization::SomeStruct5> = SerializationConfig<tests::serialization::SomeStruct5>{};
|
constexpr auto kSerializationConfig<tests::serialization::SomeStruct5> = SerializationConfig<tests::serialization::SomeStruct5>{};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr auto kSerializationConfig<tests::serialization::SomeStruct6> =
|
||||||
|
SerializationConfig<tests::serialization::SomeStruct6>{}.With<"some">({Config<std::vector<tests::serialization::SomeStruct>>{}});
|
||||||
} // namespace serialization
|
} // namespace serialization
|
||||||
|
|
||||||
namespace tests::serialization {
|
namespace tests::serialization {
|
||||||
|
@ -105,6 +115,10 @@ auto SomeStruct5::Parse(xmlpp::Element* element) -> SomeStruct5 {
|
||||||
return ::larra::xmpp::serialization::Parse<tests::serialization::SomeStruct5>(element);
|
return ::larra::xmpp::serialization::Parse<tests::serialization::SomeStruct5>(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto SomeStruct6::Parse(xmlpp::Element* element) -> SomeStruct6 {
|
||||||
|
return ::larra::xmpp::serialization::Parse<tests::serialization::SomeStruct6>(element);
|
||||||
|
}
|
||||||
|
|
||||||
auto operator<<(xmlpp::Element* element, const SomeStruct& self) {
|
auto operator<<(xmlpp::Element* element, const SomeStruct& self) {
|
||||||
::larra::xmpp::serialization::Serialize(element, self);
|
::larra::xmpp::serialization::Serialize(element, self);
|
||||||
}
|
}
|
||||||
|
@ -144,6 +158,19 @@ TEST(AutoParse, Attribute) {
|
||||||
EXPECT_EQ(a.value.username, "user"sv);
|
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<tests::serialization::SomeStruct6>::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<std::vector<tests::serialization::SomeStruct>>());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(AutoSerialize, Basic) {
|
TEST(AutoSerialize, Basic) {
|
||||||
xmlpp::Document doc;
|
xmlpp::Document doc;
|
||||||
auto node = doc.create_root_node("some2");
|
auto node = doc.create_root_node("some2");
|
||||||
|
|
Loading…
Reference in a new issue