Serialize empty elements more efficiently

This commit is contained in:
Dirkjan Ochtman 2022-11-29 09:31:10 +01:00
parent 89832babe9
commit 12402fb381
4 changed files with 19 additions and 11 deletions

View File

@ -177,26 +177,31 @@ fn serialize_struct(
data: &syn::DataStruct,
meta: ContainerMeta,
) -> proc_macro2::TokenStream {
let tag = meta.tag();
let mut body = TokenStream::new();
let mut attributes = TokenStream::new();
match &data.fields {
syn::Fields::Named(fields) => {
body.extend(quote!(serializer.end_start()?;));
for field in &fields.named {
if let Err(err) = named_field(field, &mut body, &mut attributes, &meta) {
return err.to_compile_error();
}
}
body.extend(quote!(serializer.write_close(prefix, #tag)?;));
}
syn::Fields::Unnamed(fields) => {
body.extend(quote!(serializer.end_start()?;));
for (index, field) in fields.unnamed.iter().enumerate() {
if let Err(err) = unnamed_field(field, index, &mut body) {
return err.to_compile_error();
}
}
body.extend(quote!(serializer.write_close(prefix, #tag)?;));
}
syn::Fields::Unit => {}
};
syn::Fields::Unit => body.extend(quote!(serializer.end_empty()?;)),
}
let default_namespace = meta.default_namespace();
let cx_len = meta.ns.prefixes.len();
@ -221,7 +226,6 @@ fn serialize_struct(
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let tag = meta.tag();
let ident = &input.ident;
quote!(
impl #impl_generics ToXml for #ident #ty_generics #where_clause {
fn serialize<W: ::core::fmt::Write + ?::core::marker::Sized>(
@ -239,14 +243,9 @@ fn serialize_struct(
// Finalize start element
#attributes
serializer.end_start()?;
#body
// Close tag
serializer.write_close(prefix, #tag)?;
serializer.pop(old);
Ok(())
}

View File

@ -111,6 +111,16 @@ impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
Ok(())
}
pub fn end_empty(&mut self) -> Result<(), Error> {
if self.state != State::Attribute {
return Err(Error::UnexpectedState("invalid state for element end"));
}
self.output.write_str(" />")?;
self.state = State::Element;
Ok(())
}
pub fn write_close(&mut self, prefix: Option<&str>, name: &str) -> Result<(), Error> {
if self.state != State::Element {
return Err(Error::UnexpectedState("invalid state for close element"));

View File

@ -7,6 +7,5 @@ struct Unit;
#[test]
fn unit() {
assert_eq!(to_string(&Unit).unwrap(), "<Unit></Unit>");
//assert_eq!(Unit::from_xml("<Unit/>").unwrap(), Unit);
assert_eq!(to_string(&Unit).unwrap(), "<Unit />");
}

View File

@ -33,7 +33,7 @@ struct Foo;
#[test]
fn string_element() {
let v = StringElement("f42".to_owned(), Foo);
let xml = r#"<StringElement>f42<Foo></Foo></StringElement>"#;
let xml = r#"<StringElement>f42<Foo /></StringElement>"#;
assert_eq!(xml, to_string(&v).unwrap());
assert_eq!(v, from_str(xml).unwrap());
}