From c983e10a88b729a4b47095e44e66643a64784007 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Wed, 22 Feb 2023 16:04:58 +0100 Subject: [PATCH] Provide field context to Deserializer implementations Also reorders deserialize() arguments. --- instant-xml-macros/src/de.rs | 37 ++++++++++++--------- instant-xml/src/de.rs | 6 ++-- instant-xml/src/impls.rs | 61 +++++++++++++++++++++-------------- instant-xml/src/lib.rs | 11 +++++-- instant-xml/tests/entities.rs | 2 +- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/instant-xml-macros/src/de.rs b/instant-xml-macros/src/de.rs index 9fe5c6d..88d4064 100644 --- a/instant-xml-macros/src/de.rs +++ b/instant-xml-macros/src/de.rs @@ -67,8 +67,9 @@ fn deserialize_scalar_enum( } fn deserialize<'cx>( - deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, ) -> Result<(), ::instant_xml::Error> { use ::instant_xml::Error; @@ -104,6 +105,7 @@ fn deserialize_forward_enum( } let ident = &input.ident; + let field_str = format!("{ident}::0"); let mut matches = TokenStream::new(); let mut variants = TokenStream::new(); let mut borrowed = BTreeSet::new(); @@ -145,7 +147,7 @@ fn deserialize_forward_enum( variants.extend( quote!(if <#no_lifetime_type as FromXml>::matches(id, None) { let mut value = None; - <#no_lifetime_type as FromXml>::deserialize(deserializer, &mut value)?; + <#no_lifetime_type as FromXml>::deserialize(&mut value, #field_str, deserializer)?; *into = value.map(#ident::#v_ident); }), ); @@ -163,8 +165,9 @@ fn deserialize_forward_enum( } fn deserialize<'cx>( - deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, ) -> Result<(), ::instant_xml::Error> { use ::instant_xml::de::Node; use ::instant_xml::{Accumulate, Error, FromXml}; @@ -284,8 +287,9 @@ fn deserialize_struct( } fn deserialize<'cx>( - deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, ) -> Result<(), ::instant_xml::Error> { use ::instant_xml::de::Node; use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind}; @@ -418,6 +422,7 @@ fn named_field( }) .transpose()?; + let field_str = format!("{type_name}::{field_name}"); if !field_meta.attribute { if let Some(with) = deserialize_with { if field_meta.direct { @@ -430,14 +435,14 @@ fn named_field( tokens.r#match.extend(quote!( __Elements::#enum_name => { let mut nested = deserializer.nested(data); - #with(&mut nested, &mut #enum_name)?; + #with(&mut #enum_name, #field_str, &mut nested)?; }, )); } else if field_meta.direct { direct.extend(quote!( Node::Text(text) => { let mut nested = deserializer.for_node(Node::Text(text)); - <#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?; + <#no_lifetime_type>::deserialize(&mut #enum_name, #field_str, &mut nested)?; } )); } else { @@ -445,11 +450,11 @@ fn named_field( __Elements::#enum_name => match <#no_lifetime_type as FromXml>::KIND { Kind::Element => { let mut nested = deserializer.nested(data); - <#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?; + <#no_lifetime_type>::deserialize(&mut #enum_name, #field_str, &mut nested)?; } Kind::Scalar => { let mut nested = deserializer.nested(data); - <#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?; + <#no_lifetime_type>::deserialize(&mut #enum_name, #field_str, &mut nested)?; nested.ignore()?; } }, @@ -467,20 +472,19 @@ fn named_field( tokens.r#match.extend(quote!( __Attributes::#enum_name => { let mut nested = deserializer.nested(data); - #with(&mut nested, &mut #enum_name)?; + #with(&mut #enum_name, #field_str, &mut nested)?; }, )); } else { tokens.r#match.extend(quote!( __Attributes::#enum_name => { let mut nested = deserializer.for_node(Node::AttributeValue(attr.value)); - let new = <#no_lifetime_type as FromXml>::deserialize(&mut nested, &mut #enum_name)?; + let new = <#no_lifetime_type as FromXml>::deserialize(&mut #enum_name, #field_str, &mut nested)?; }, )); } } - let field_str = format!("{type_name}::{field_name}"); return_val.extend(quote!( #field_name: #enum_name.try_done(#field_str)?, )); @@ -539,8 +543,9 @@ fn deserialize_tuple_struct( } fn deserialize<'cx>( - deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, ) -> Result<(), ::instant_xml::Error> { use ::instant_xml::de::Node; use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind}; @@ -578,7 +583,7 @@ fn unnamed_field( Some(Ok(Node::Open(data))) => { let mut nested = deserializer.nested(data); let mut value = <#no_lifetime_type as FromXml>::Accumulator::default(); - <#no_lifetime_type as FromXml>::deserialize(&mut nested, &mut value)?; + <#no_lifetime_type as FromXml>::deserialize(&mut value, #field_str, &mut nested)?; nested.ignore()?; value } @@ -588,13 +593,12 @@ fn unnamed_field( } Kind::Scalar => { let mut value = <#no_lifetime_type as FromXml>::Accumulator::default(); - <#no_lifetime_type as FromXml>::deserialize(deserializer, &mut value)?; + <#no_lifetime_type as FromXml>::deserialize(&mut value, #field_str, deserializer)?; value } }; )); - let field_str = format!("{type_name}::{index}"); return_val.extend(quote!( #name.try_done(#field_str)?, )); @@ -617,8 +621,9 @@ fn deserialize_unit_struct(input: &syn::DeriveInput, meta: &ContainerMeta) -> To } fn deserialize<'cx>( - deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>, ) -> Result<(), ::instant_xml::Error> { deserializer.ignore()?; *into = Some(Self); diff --git a/instant-xml/src/de.rs b/instant-xml/src/de.rs index 47ae278..6e4a8d6 100644 --- a/instant-xml/src/de.rs +++ b/instant-xml/src/de.rs @@ -333,8 +333,9 @@ impl<'xml> Iterator for Context<'xml> { } pub fn borrow_cow_str<'xml>( - deserializer: &mut Deserializer<'_, 'xml>, into: &mut Option>, + _: &'static str, + deserializer: &mut Deserializer<'_, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -349,8 +350,9 @@ pub fn borrow_cow_str<'xml>( } pub fn borrow_cow_slice_u8<'xml>( - deserializer: &mut Deserializer<'_, 'xml>, into: &mut Option>, + _: &'static str, + deserializer: &mut Deserializer<'_, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); diff --git a/instant-xml/src/impls.rs b/instant-xml/src/impls.rs index ff291fa..dbb54ec 100644 --- a/instant-xml/src/impls.rs +++ b/instant-xml/src/impls.rs @@ -48,8 +48,9 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr { } fn deserialize( - deserializer: &mut Deserializer<'_, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'_, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -66,7 +67,7 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr { Ok(()) } Err(_) => Err(Error::UnexpectedValue(format!( - "unable to parse {} from `{value}`", + "unable to parse {} from `{value}` for {field}", type_name::() ))), } @@ -86,8 +87,9 @@ impl<'xml> FromXml<'xml> for bool { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -103,7 +105,7 @@ impl<'xml> FromXml<'xml> for bool { "false" | "0" => false, val => { return Err(Error::UnexpectedValue(format!( - "unable to parse bool from '{val}'" + "unable to parse bool from '{val}' for {field}" ))) } }; @@ -181,15 +183,16 @@ macro_rules! from_xml_for_number { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); } let mut value = None; - FromXmlStr::::deserialize(deserializer, &mut value)?; + FromXmlStr::::deserialize(&mut value, field, deserializer)?; if let Some(value) = value { *into = Some(value.0); } @@ -226,15 +229,16 @@ impl<'xml> FromXml<'xml> for char { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); } let mut value = None; - FromXmlStr::::deserialize(deserializer, &mut value)?; + FromXmlStr::::deserialize(&mut value, field, deserializer)?; if let Some(value) = value { *into = Some(value.0); } @@ -256,8 +260,9 @@ impl<'xml> FromXml<'xml> for String { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + _: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -285,8 +290,9 @@ impl<'xml> FromXml<'xml> for &'xml str { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -301,7 +307,7 @@ impl<'xml> FromXml<'xml> for &'xml str { Cow::Borrowed(str) => *into = Some(str), Cow::Owned(_) => { return Err(Error::UnexpectedValue(format!( - "string with escape characters cannot be deserialized as &str: '{value}'", + "string with escape characters cannot be deserialized as &str for {field}: '{value}'", ))) } } @@ -327,16 +333,17 @@ where } fn deserialize( - deserializer: &mut Deserializer<'_, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'_, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); } let mut value = >::Accumulator::default(); - T::Owned::deserialize(deserializer, &mut value)?; - *into = Some(Cow::Owned(value.try_done("Cow")?)); + T::Owned::deserialize(&mut value, field, deserializer)?; + *into = Some(Cow::Owned(value.try_done(field)?)); Ok(()) } @@ -351,10 +358,11 @@ impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Option { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { - ::deserialize(deserializer, &mut into.value)?; + ::deserialize(&mut into.value, field, deserializer)?; Ok(()) } @@ -567,12 +575,13 @@ impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Vec { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { let mut value = T::Accumulator::default(); - T::deserialize(deserializer, &mut value)?; - into.push(value.try_done("Vec")?); + T::deserialize(&mut value, field, deserializer)?; + into.push(value.try_done(field)?); Ok(()) } @@ -640,8 +649,9 @@ impl<'xml> FromXml<'xml> for DateTime { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + _: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -701,8 +711,9 @@ impl<'xml> FromXml<'xml> for NaiveDate { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + _: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); @@ -736,8 +747,9 @@ impl<'xml> FromXml<'xml> for () { } fn deserialize<'cx>( - _: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + _: &'static str, + _: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { *into = Some(()); Ok(()) @@ -767,15 +779,16 @@ impl<'xml> FromXml<'xml> for IpAddr { } fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error> { if into.is_some() { return Err(Error::DuplicateValue); } let mut value = None; - FromXmlStr::::deserialize(deserializer, &mut value)?; + FromXmlStr::::deserialize(&mut value, field, deserializer)?; if let Some(value) = value { *into = Some(value.0); } diff --git a/instant-xml/src/lib.rs b/instant-xml/src/lib.rs index 58c4a86..7b26bef 100644 --- a/instant-xml/src/lib.rs +++ b/instant-xml/src/lib.rs @@ -40,8 +40,9 @@ pub trait FromXml<'xml>: Sized { fn matches(id: Id<'_>, field: Option>) -> bool; fn deserialize<'cx>( - deserializer: &mut Deserializer<'cx, 'xml>, into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, ) -> Result<(), Error>; type Accumulator: Accumulate; @@ -86,8 +87,12 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result { } let mut value = T::Accumulator::default(); - T::deserialize(&mut Deserializer::new(root, &mut context), &mut value)?; - value.try_done("root element") + T::deserialize( + &mut value, + "", + &mut Deserializer::new(root, &mut context), + )?; + value.try_done("") } pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result { diff --git a/instant-xml/tests/entities.rs b/instant-xml/tests/entities.rs index 4bde05e..4aa7a03 100644 --- a/instant-xml/tests/entities.rs +++ b/instant-xml/tests/entities.rs @@ -31,7 +31,7 @@ fn escape_back() { from_str( "<>&"'adsad"str&" ), - Err::(Error::UnexpectedValue("string with escape characters cannot be deserialized as &str: 'str&'".to_owned())) + Err::(Error::UnexpectedValue("string with escape characters cannot be deserialized as &str for StructSpecialEntities::str: 'str&'".to_owned())) ); // Borrowed