Provide field context to Deserializer implementations

Also reorders deserialize() arguments.
This commit is contained in:
Dirkjan Ochtman 2023-02-22 16:04:58 +01:00
parent 7a2e6ac735
commit c983e10a88
5 changed files with 71 additions and 46 deletions

View File

@ -67,8 +67,9 @@ fn deserialize_scalar_enum(
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), ::instant_xml::Error> { ) -> Result<(), ::instant_xml::Error> {
use ::instant_xml::Error; use ::instant_xml::Error;
@ -104,6 +105,7 @@ fn deserialize_forward_enum(
} }
let ident = &input.ident; let ident = &input.ident;
let field_str = format!("{ident}::0");
let mut matches = TokenStream::new(); let mut matches = TokenStream::new();
let mut variants = TokenStream::new(); let mut variants = TokenStream::new();
let mut borrowed = BTreeSet::new(); let mut borrowed = BTreeSet::new();
@ -145,7 +147,7 @@ fn deserialize_forward_enum(
variants.extend( variants.extend(
quote!(if <#no_lifetime_type as FromXml>::matches(id, None) { quote!(if <#no_lifetime_type as FromXml>::matches(id, None) {
let mut value = 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); *into = value.map(#ident::#v_ident);
}), }),
); );
@ -163,8 +165,9 @@ fn deserialize_forward_enum(
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), ::instant_xml::Error> { ) -> Result<(), ::instant_xml::Error> {
use ::instant_xml::de::Node; use ::instant_xml::de::Node;
use ::instant_xml::{Accumulate, Error, FromXml}; use ::instant_xml::{Accumulate, Error, FromXml};
@ -284,8 +287,9 @@ fn deserialize_struct(
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), ::instant_xml::Error> { ) -> Result<(), ::instant_xml::Error> {
use ::instant_xml::de::Node; use ::instant_xml::de::Node;
use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind}; use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind};
@ -418,6 +422,7 @@ fn named_field(
}) })
.transpose()?; .transpose()?;
let field_str = format!("{type_name}::{field_name}");
if !field_meta.attribute { if !field_meta.attribute {
if let Some(with) = deserialize_with { if let Some(with) = deserialize_with {
if field_meta.direct { if field_meta.direct {
@ -430,14 +435,14 @@ fn named_field(
tokens.r#match.extend(quote!( tokens.r#match.extend(quote!(
__Elements::#enum_name => { __Elements::#enum_name => {
let mut nested = deserializer.nested(data); 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 { } else if field_meta.direct {
direct.extend(quote!( direct.extend(quote!(
Node::Text(text) => { Node::Text(text) => {
let mut nested = deserializer.for_node(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 { } else {
@ -445,11 +450,11 @@ fn named_field(
__Elements::#enum_name => match <#no_lifetime_type as FromXml>::KIND { __Elements::#enum_name => match <#no_lifetime_type as FromXml>::KIND {
Kind::Element => { Kind::Element => {
let mut nested = deserializer.nested(data); 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 => { Kind::Scalar => {
let mut nested = deserializer.nested(data); 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()?; nested.ignore()?;
} }
}, },
@ -467,20 +472,19 @@ fn named_field(
tokens.r#match.extend(quote!( tokens.r#match.extend(quote!(
__Attributes::#enum_name => { __Attributes::#enum_name => {
let mut nested = deserializer.nested(data); let mut nested = deserializer.nested(data);
#with(&mut nested, &mut #enum_name)?; #with(&mut #enum_name, #field_str, &mut nested)?;
}, },
)); ));
} else { } else {
tokens.r#match.extend(quote!( tokens.r#match.extend(quote!(
__Attributes::#enum_name => { __Attributes::#enum_name => {
let mut nested = deserializer.for_node(Node::AttributeValue(attr.value)); 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!( return_val.extend(quote!(
#field_name: #enum_name.try_done(#field_str)?, #field_name: #enum_name.try_done(#field_str)?,
)); ));
@ -539,8 +543,9 @@ fn deserialize_tuple_struct(
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), ::instant_xml::Error> { ) -> Result<(), ::instant_xml::Error> {
use ::instant_xml::de::Node; use ::instant_xml::de::Node;
use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind}; use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind};
@ -578,7 +583,7 @@ fn unnamed_field(
Some(Ok(Node::Open(data))) => { Some(Ok(Node::Open(data))) => {
let mut nested = deserializer.nested(data); let mut nested = deserializer.nested(data);
let mut value = <#no_lifetime_type as FromXml>::Accumulator::default(); 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()?; nested.ignore()?;
value value
} }
@ -588,13 +593,12 @@ fn unnamed_field(
} }
Kind::Scalar => { Kind::Scalar => {
let mut value = <#no_lifetime_type as FromXml>::Accumulator::default(); 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 value
} }
}; };
)); ));
let field_str = format!("{type_name}::{index}");
return_val.extend(quote!( return_val.extend(quote!(
#name.try_done(#field_str)?, #name.try_done(#field_str)?,
)); ));
@ -617,8 +621,9 @@ fn deserialize_unit_struct(input: &syn::DeriveInput, meta: &ContainerMeta) -> To
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> Result<(), ::instant_xml::Error> { ) -> Result<(), ::instant_xml::Error> {
deserializer.ignore()?; deserializer.ignore()?;
*into = Some(Self); *into = Some(Self);

View File

@ -333,8 +333,9 @@ impl<'xml> Iterator for Context<'xml> {
} }
pub fn borrow_cow_str<'xml>( pub fn borrow_cow_str<'xml>(
deserializer: &mut Deserializer<'_, 'xml>,
into: &mut Option<Cow<'xml, str>>, into: &mut Option<Cow<'xml, str>>,
_: &'static str,
deserializer: &mut Deserializer<'_, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -349,8 +350,9 @@ pub fn borrow_cow_str<'xml>(
} }
pub fn borrow_cow_slice_u8<'xml>( pub fn borrow_cow_slice_u8<'xml>(
deserializer: &mut Deserializer<'_, 'xml>,
into: &mut Option<Cow<'xml, [u8]>>, into: &mut Option<Cow<'xml, [u8]>>,
_: &'static str,
deserializer: &mut Deserializer<'_, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);

View File

@ -48,8 +48,9 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
} }
fn deserialize( fn deserialize(
deserializer: &mut Deserializer<'_, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'_, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -66,7 +67,7 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
Ok(()) Ok(())
} }
Err(_) => Err(Error::UnexpectedValue(format!( Err(_) => Err(Error::UnexpectedValue(format!(
"unable to parse {} from `{value}`", "unable to parse {} from `{value}` for {field}",
type_name::<T>() type_name::<T>()
))), ))),
} }
@ -86,8 +87,9 @@ impl<'xml> FromXml<'xml> for bool {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -103,7 +105,7 @@ impl<'xml> FromXml<'xml> for bool {
"false" | "0" => false, "false" | "0" => false,
val => { val => {
return Err(Error::UnexpectedValue(format!( 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>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
} }
let mut value = None; let mut value = None;
FromXmlStr::<Self>::deserialize(deserializer, &mut value)?; FromXmlStr::<Self>::deserialize(&mut value, field, deserializer)?;
if let Some(value) = value { if let Some(value) = value {
*into = Some(value.0); *into = Some(value.0);
} }
@ -226,15 +229,16 @@ impl<'xml> FromXml<'xml> for char {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
} }
let mut value = None; let mut value = None;
FromXmlStr::<Self>::deserialize(deserializer, &mut value)?; FromXmlStr::<Self>::deserialize(&mut value, field, deserializer)?;
if let Some(value) = value { if let Some(value) = value {
*into = Some(value.0); *into = Some(value.0);
} }
@ -256,8 +260,9 @@ impl<'xml> FromXml<'xml> for String {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
_: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -285,8 +290,9 @@ impl<'xml> FromXml<'xml> for &'xml str {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -301,7 +307,7 @@ impl<'xml> FromXml<'xml> for &'xml str {
Cow::Borrowed(str) => *into = Some(str), Cow::Borrowed(str) => *into = Some(str),
Cow::Owned(_) => { Cow::Owned(_) => {
return Err(Error::UnexpectedValue(format!( 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( fn deserialize(
deserializer: &mut Deserializer<'_, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'_, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
} }
let mut value = <T::Owned as FromXml<'xml>>::Accumulator::default(); let mut value = <T::Owned as FromXml<'xml>>::Accumulator::default();
T::Owned::deserialize(deserializer, &mut value)?; T::Owned::deserialize(&mut value, field, deserializer)?;
*into = Some(Cow::Owned(value.try_done("Cow<T>")?)); *into = Some(Cow::Owned(value.try_done(field)?));
Ok(()) Ok(())
} }
@ -351,10 +358,11 @@ impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Option<T> {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
<T>::deserialize(deserializer, &mut into.value)?; <T>::deserialize(&mut into.value, field, deserializer)?;
Ok(()) Ok(())
} }
@ -567,12 +575,13 @@ impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Vec<T> {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut value = T::Accumulator::default(); let mut value = T::Accumulator::default();
T::deserialize(deserializer, &mut value)?; T::deserialize(&mut value, field, deserializer)?;
into.push(value.try_done("Vec<T>")?); into.push(value.try_done(field)?);
Ok(()) Ok(())
} }
@ -640,8 +649,9 @@ impl<'xml> FromXml<'xml> for DateTime<Utc> {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
_: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -701,8 +711,9 @@ impl<'xml> FromXml<'xml> for NaiveDate {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
_: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
@ -736,8 +747,9 @@ impl<'xml> FromXml<'xml> for () {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
_: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
_: &'static str,
_: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
*into = Some(()); *into = Some(());
Ok(()) Ok(())
@ -767,15 +779,16 @@ impl<'xml> FromXml<'xml> for IpAddr {
} }
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if into.is_some() { if into.is_some() {
return Err(Error::DuplicateValue); return Err(Error::DuplicateValue);
} }
let mut value = None; let mut value = None;
FromXmlStr::<Self>::deserialize(deserializer, &mut value)?; FromXmlStr::<Self>::deserialize(&mut value, field, deserializer)?;
if let Some(value) = value { if let Some(value) = value {
*into = Some(value.0); *into = Some(value.0);
} }

View File

@ -40,8 +40,9 @@ pub trait FromXml<'xml>: Sized {
fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool; fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool;
fn deserialize<'cx>( fn deserialize<'cx>(
deserializer: &mut Deserializer<'cx, 'xml>,
into: &mut Self::Accumulator, into: &mut Self::Accumulator,
field: &'static str,
deserializer: &mut Deserializer<'cx, 'xml>,
) -> Result<(), Error>; ) -> Result<(), Error>;
type Accumulator: Accumulate<Self>; type Accumulator: Accumulate<Self>;
@ -86,8 +87,12 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
} }
let mut value = T::Accumulator::default(); let mut value = T::Accumulator::default();
T::deserialize(&mut Deserializer::new(root, &mut context), &mut value)?; T::deserialize(
value.try_done("root element") &mut value,
"<root element>",
&mut Deserializer::new(root, &mut context),
)?;
value.try_done("<root element>")
} }
pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> { pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {

View File

@ -31,7 +31,7 @@ fn escape_back() {
from_str( from_str(
"<StructSpecialEntities xmlns=\"URI\"><string>&lt;&gt;&amp;&quot;&apos;adsad&quot;</string><str>str&amp;</str></StructSpecialEntities>" "<StructSpecialEntities xmlns=\"URI\"><string>&lt;&gt;&amp;&quot;&apos;adsad&quot;</string><str>str&amp;</str></StructSpecialEntities>"
), ),
Err::<StructSpecialEntities, _>(Error::UnexpectedValue("string with escape characters cannot be deserialized as &str: 'str&amp;'".to_owned())) Err::<StructSpecialEntities, _>(Error::UnexpectedValue("string with escape characters cannot be deserialized as &str for StructSpecialEntities::str: 'str&amp;'".to_owned()))
); );
// Borrowed // Borrowed