Allow direct String fields to match the empty string
Empty is not the same as missing, and the empty string crops up a lot in upnp/dlna.
This commit is contained in:
parent
dfc5894edf
commit
a1610f689f
|
@ -234,6 +234,7 @@ fn deserialize_struct(
|
|||
let mut declare_values = TokenStream::new();
|
||||
let mut return_val = TokenStream::new();
|
||||
let mut direct = TokenStream::new();
|
||||
let mut after_loop = TokenStream::new();
|
||||
|
||||
let mut borrowed = BTreeSet::new();
|
||||
for (index, field) in fields.named.iter().enumerate() {
|
||||
|
@ -263,6 +264,7 @@ fn deserialize_struct(
|
|||
field_meta,
|
||||
&input.ident,
|
||||
&container_meta,
|
||||
&mut after_loop,
|
||||
);
|
||||
|
||||
if let Err(err) = result {
|
||||
|
@ -361,6 +363,7 @@ fn deserialize_struct(
|
|||
node => return Err(Error::UnexpectedNode(format!("{:?} in {}", node, #ident_str))),
|
||||
}
|
||||
}
|
||||
#after_loop
|
||||
|
||||
*into = Some(Self { #return_val });
|
||||
Ok(())
|
||||
|
@ -401,6 +404,7 @@ fn deserialize_inline_struct(
|
|||
let mut declare_values = TokenStream::new();
|
||||
let mut return_val = TokenStream::new();
|
||||
let mut direct = TokenStream::new();
|
||||
let mut after_loop = TokenStream::new();
|
||||
|
||||
let mut borrowed = BTreeSet::new();
|
||||
let mut matches = TokenStream::new();
|
||||
|
@ -433,6 +437,7 @@ fn deserialize_inline_struct(
|
|||
field_meta,
|
||||
&input.ident,
|
||||
&meta,
|
||||
&mut after_loop,
|
||||
);
|
||||
|
||||
let data = match result {
|
||||
|
@ -548,6 +553,7 @@ fn named_field<'a>(
|
|||
mut field_meta: FieldMeta,
|
||||
type_name: &Ident,
|
||||
container_meta: &ContainerMeta,
|
||||
after_loop: &mut TokenStream,
|
||||
) -> Result<FieldData<'a>, syn::Error> {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let field_tag = field_meta.tag;
|
||||
|
@ -598,6 +604,15 @@ fn named_field<'a>(
|
|||
let mut #val_name = <#no_lifetime_type as FromXml>::Accumulator::default();
|
||||
));
|
||||
|
||||
if field_meta.direct {
|
||||
declare_values.extend(quote!(
|
||||
// We will synthesize an empty text node when processing a direct
|
||||
// element. Without this, we can miscategorize an empty tag as
|
||||
// a missing tag
|
||||
let mut seen_direct = false;
|
||||
));
|
||||
}
|
||||
|
||||
let deserialize_with = field_meta
|
||||
.deserialize_with
|
||||
.map(|with| {
|
||||
|
@ -630,10 +645,21 @@ fn named_field<'a>(
|
|||
} else if field_meta.direct {
|
||||
direct.extend(quote!(
|
||||
Node::Text(text) => {
|
||||
seen_direct = true;
|
||||
let mut nested = deserializer.for_node(Node::Text(text));
|
||||
<#no_lifetime_type>::deserialize(&mut #val_name, #field_str, &mut nested)?;
|
||||
}
|
||||
));
|
||||
// We can only enter this FromXml impl if the caller found the opening
|
||||
// tag, so if we don't see the text node before the closing tag that is
|
||||
// implied by terminating the loop, we need to populate the
|
||||
// direct field with the implied empty text node.
|
||||
after_loop.extend(quote!(
|
||||
if !seen_direct {
|
||||
let mut nested = deserializer.for_node(Node::Text("".into()));
|
||||
<#no_lifetime_type>::deserialize(&mut #val_name, #field_str, &mut nested)?;
|
||||
}
|
||||
));
|
||||
} else {
|
||||
tokens.r#match.extend(quote!(
|
||||
__Elements::#enum_name => match <#no_lifetime_type as FromXml>::KIND {
|
||||
|
|
|
@ -270,10 +270,10 @@ impl<'xml> FromXml<'xml> for String {
|
|||
return Err(Error::DuplicateValue(field));
|
||||
}
|
||||
|
||||
match deserializer.take_str()? {
|
||||
Some(value) => *into = Some(value.into_owned()),
|
||||
None => return Ok(()),
|
||||
}
|
||||
*into = Some(match deserializer.take_str()? {
|
||||
Some(value) => value.into_owned(),
|
||||
None => String::new(),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -300,12 +300,11 @@ impl<'xml, 'a> FromXml<'xml> for Cow<'a, str> {
|
|||
return Err(Error::DuplicateValue(field));
|
||||
}
|
||||
|
||||
let value = match deserializer.take_str()? {
|
||||
Some(value) => value,
|
||||
None => return Ok(()),
|
||||
};
|
||||
into.inner = Some(match deserializer.take_str()? {
|
||||
Some(value) => value.into_owned().into(),
|
||||
None => "".into(),
|
||||
});
|
||||
|
||||
into.inner = Some(value.into_owned().into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use similar_asserts::assert_eq;
|
||||
|
||||
use instant_xml::{from_str, Error, FromXml};
|
||||
|
@ -33,3 +35,70 @@ fn direct_namespaces() {
|
|||
Err::<StructDirectNamespace, _>(Error::MissingValue("StructDirectNamespace::flag"))
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, FromXml)]
|
||||
struct DirectString {
|
||||
s: String,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_string() {
|
||||
assert_eq!(
|
||||
from_str("<DirectString><s>hello</s></DirectString>"),
|
||||
Ok(DirectString {
|
||||
s: "hello".to_string()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, FromXml)]
|
||||
struct DirectStr<'a> {
|
||||
s: Cow<'a, str>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_empty_str() {
|
||||
assert_eq!(
|
||||
from_str("<DirectStr><s></s></DirectStr>"),
|
||||
Ok(DirectStr { s: "".into() })
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_missing_string() {
|
||||
assert_eq!(
|
||||
from_str("<DirectString></DirectString>"),
|
||||
Err::<DirectString, _>(Error::MissingValue("DirectString::s"))
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, FromXml)]
|
||||
struct ArtUri {
|
||||
#[xml(direct)]
|
||||
uri: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, FromXml)]
|
||||
struct Container {
|
||||
art: Option<ArtUri>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn container_empty_string() {
|
||||
assert_eq!(
|
||||
from_str("<Container><ArtUri></ArtUri></Container>"),
|
||||
Ok(Container {
|
||||
art: Some(ArtUri {
|
||||
uri: "".to_string()
|
||||
})
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("<Container><ArtUri/></Container>"),
|
||||
Ok(Container {
|
||||
art: Some(ArtUri {
|
||||
uri: "".to_string()
|
||||
})
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue