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 <nameof.hpp>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#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 {
|
||||
std::visit(
|
||||
[&](const auto& object) {
|
||||
element << object;
|
||||
[&]<typename T>(const T& object) {
|
||||
Serialization<T>::Serialize(element, 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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <boost/pfr.hpp>
|
||||
#include <larra/serialization.hpp>
|
||||
#include <larra/serialization/error.hpp>
|
||||
#include <ranges>
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
#include <utempl/tuple.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 {
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -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<SomeStruct> some;
|
||||
[[nodiscard]] static auto Parse(xmlpp::Element* element) -> SomeStruct6;
|
||||
};
|
||||
|
||||
} // namespace tests::serialization
|
||||
|
||||
namespace serialization {
|
||||
|
@ -81,6 +88,9 @@ constexpr auto kSerializationConfig<tests::serialization::SomeStruct4> = Seriali
|
|||
template <>
|
||||
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 tests::serialization {
|
||||
|
@ -105,6 +115,10 @@ auto SomeStruct5::Parse(xmlpp::Element* element) -> SomeStruct5 {
|
|||
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) {
|
||||
::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<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) {
|
||||
xmlpp::Document doc;
|
||||
auto node = doc.create_root_node("some2");
|
||||
|
|
Loading…
Reference in a new issue