Better serialization of complex types under `Vec<T>`

This commit is contained in:
rsdy 2022-09-29 17:45:17 +01:00 committed by Dirkjan Ochtman
parent 4d627b514a
commit 55c7c5db99
2 changed files with 58 additions and 7 deletions

View File

@ -317,6 +317,7 @@ fn decode(input: &str) -> Cow<'_, str> {
Cow::Owned(result)
}
const VEC_LIST_TAG: &str = "list";
const VEC_ELEMENT_TAG: &str = "element";
impl<'xml, T> FromXml<'xml> for Vec<T>
@ -325,10 +326,11 @@ where
{
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
let mut result = Self::new();
let kind = <T as FromXml<'xml>>::KIND;
while let Some(Ok(node)) = deserializer.next() {
match node {
Node::Open(data) => {
match (&kind, node) {
(Kind::Scalar, Node::Open(data)) => {
let id = deserializer.element_id(&data)?;
match id.name {
@ -339,6 +341,10 @@ where
_ => return Err(Error::UnexpectedState),
}
}
(Kind::Vec | Kind::Element(_), Node::Open(data)) => {
let mut nested = deserializer.nested(data);
result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?)
}
_ => return Err(Error::UnexpectedState),
}
}
@ -357,11 +363,29 @@ where
&self,
serializer: &mut Serializer<W>,
) -> Result<(), Error> {
for i in self {
let prefix = serializer.write_start(VEC_ELEMENT_TAG, "", false)?;
serializer.end_start()?;
i.serialize(serializer)?;
serializer.write_close(prefix, VEC_ELEMENT_TAG)?;
match <T as ToXml>::KIND {
Kind::Element(_) => {
for i in self {
i.serialize(serializer)?;
}
}
Kind::Scalar => {
for i in self {
let prefix = serializer.write_start(VEC_ELEMENT_TAG, "", false)?;
serializer.end_start()?;
i.serialize(serializer)?;
serializer.write_close(prefix, VEC_ELEMENT_TAG)?;
}
}
// this would be a Vec<Vec<T>>, where the internal field is unnamed
Kind::Vec => {
for i in self {
let prefix = serializer.write_start(VEC_LIST_TAG, "", false)?;
serializer.end_start()?;
i.serialize(serializer)?;
serializer.write_close(prefix, VEC_LIST_TAG)?;
}
}
}
Ok(())

View File

@ -13,6 +13,33 @@ struct StructSpecialEntities<'a> {
vec: Vec<String>,
}
#[derive(Debug, PartialEq, Eq, FromXml, ToXml)]
#[xml(ns("URI"))]
struct VecEntities<'a> {
complex: Vec<StructSpecialEntities<'a>>,
list1: Vec<String>,
list2: Vec<Vec<String>>,
}
#[test]
fn vec_entities() {
let serialized = r#"<VecEntities xmlns="URI"><complex><StructSpecialEntities><string>&lt;&gt;&amp;&quot;&apos;adsad&quot;</string><str>str</str><cow>str&amp;</cow><vec><element xmlns="">one</element><element xmlns="">two</element><element xmlns="">three</element></vec></StructSpecialEntities></complex><list1><element xmlns="">a</element><element xmlns="">b</element></list1><list2><list xmlns=""><element xmlns="">a</element><element xmlns="">b</element></list></list2></VecEntities>"#;
let instance = VecEntities {
complex: vec![StructSpecialEntities {
string: String::from("<>&\"'adsad\""),
str: "str",
cow: Cow::Owned("str&".to_string()),
vec: vec!["one".into(), "two".into(), "three".into()],
}],
list1: vec!["a".into(), "b".into()],
list2: vec![vec!["a".into(), "b".into()]],
};
assert_eq!(to_string(&instance).unwrap(), serialized);
assert_eq!(from_str(serialized), Ok(instance));
}
#[test]
fn escape_back() {
assert_eq!(