From 887c5c52c1bcfda3b41859644875950d88baf223 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Wed, 29 May 2024 13:52:50 +0200 Subject: [PATCH] Add TagList implementation for XML --- crates/dav/src/xml/mod.rs | 1 + crates/dav/src/xml/tag_list.rs | 64 ++++++++++++++++++++++++++++++++++ crates/dav/tests/tag_list.rs | 48 +++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 crates/dav/src/xml/mod.rs create mode 100644 crates/dav/src/xml/tag_list.rs create mode 100644 crates/dav/tests/tag_list.rs diff --git a/crates/dav/src/xml/mod.rs b/crates/dav/src/xml/mod.rs new file mode 100644 index 0000000..646bf1c --- /dev/null +++ b/crates/dav/src/xml/mod.rs @@ -0,0 +1 @@ +pub mod tag_list; diff --git a/crates/dav/src/xml/tag_list.rs b/crates/dav/src/xml/tag_list.rs new file mode 100644 index 0000000..6a8a970 --- /dev/null +++ b/crates/dav/src/xml/tag_list.rs @@ -0,0 +1,64 @@ +use serde::ser::SerializeMap; + +use serde::{ + de::{MapAccess, Visitor}, + Deserialize, Serialize, +}; + +#[derive(Clone, Debug, PartialEq)] +pub struct TagList(Vec); + +struct TagListVisitor; + +impl<'de> Visitor<'de> for TagListVisitor { + type Value = TagList; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("TagList") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut tags = Vec::new(); + while let Some(key) = map.next_key::()? { + tags.push(key); + } + Ok(TagList(tags)) + } +} + +impl<'de> Deserialize<'de> for TagList { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(TagListVisitor) + } +} + +impl Serialize for TagList { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut map = serializer.serialize_map(Some(self.0.len()))?; + for name in &self.0 { + map.serialize_entry(&name, &())?; + } + map.end() + } +} + +impl From for Vec { + fn from(value: TagList) -> Self { + value.0 + } +} + +impl From> for TagList { + fn from(value: Vec) -> Self { + Self(value) + } +} diff --git a/crates/dav/tests/tag_list.rs b/crates/dav/tests/tag_list.rs new file mode 100644 index 0000000..aa04c44 --- /dev/null +++ b/crates/dav/tests/tag_list.rs @@ -0,0 +1,48 @@ +use rustical_dav::xml::tag_list::TagList; +use serde::{Deserialize, Serialize}; + +const INPUT: &str = r#" + + + + +"#; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "kebab-case")] +struct PropElement { + #[serde(flatten)] + tags: TagList, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "kebab-case")] +struct Document { + prop: PropElement, +} + +fn expected_output() -> Document { + Document { + prop: PropElement { + tags: vec!["nicename".to_owned(), "anotherprop".to_owned()].into(), + }, + } +} + +#[test] +fn test_tagname_deserialize() { + let result: Document = quick_xml::de::from_str(INPUT).unwrap(); + assert_eq!(result, expected_output()); +} + +#[test] +fn test_tagname_serialize() { + let mut result = String::new(); + let mut ser = quick_xml::se::Serializer::new(&mut result); + ser.indent(' ', 4); + + let to_serialize = &expected_output(); + to_serialize.serialize(ser).unwrap(); + + assert_eq!(result, INPUT); +}