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

View File

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

View File

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

View File

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