xml: Add serialization

This commit is contained in:
Lennart
2024-12-23 10:46:33 +01:00
parent d9f7d1da2f
commit b5e0f68239
9 changed files with 141 additions and 33 deletions

View File

@@ -127,7 +127,7 @@ impl Enum {
quote! {
impl #impl_generics ::rustical_xml::XmlDeserialize for #name #type_generics #where_clause {
fn deserialize<R: std::io::BufRead>(
fn deserialize<R: ::std::io::BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &quick_xml::events::BytesStart,
empty: bool
@@ -191,4 +191,32 @@ impl Enum {
generics: input.generics.to_owned(),
}
}
pub fn impl_se(&self) -> proc_macro2::TokenStream {
let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl();
let ident = &self.ident;
// TODO: Implement attributes
quote! {
impl #impl_generics ::rustical_xml::XmlSerialize for #ident #type_generics #where_clause {
fn serialize<W: ::std::io::Write>(
&self,
tag: Option<&[u8]>,
writer: &mut ::quick_xml::Writer<W>
) -> ::std::io::Result<()> {
use ::quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
let tag_str = tag.map(String::from_utf8_lossy);
if let Some(tag) = &tag_str {
writer.write_event(Event::Start(BytesStart::new(tag.to_owned())))?;
}
if let Some(tag) = &tag_str {
writer.write_event(Event::End(BytesEnd::new(tag.to_owned())))?;
}
Ok(())
}
}
}
}
}

View File

@@ -82,7 +82,7 @@ impl NamedStruct {
quote! {
impl #impl_generics ::rustical_xml::XmlDeserialize for #ident #type_generics #where_clause {
fn deserialize<R: BufRead>(
fn deserialize<R: ::std::io::BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &quick_xml::events::BytesStart,
empty: bool
@@ -162,4 +162,34 @@ impl NamedStruct {
}
}
}
pub fn impl_se(&self) -> proc_macro2::TokenStream {
let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl();
let ident = &self.ident;
let tag_writers = self.fields.iter().map(Field::tag_writer);
// TODO: Implement attributes
quote! {
impl #impl_generics ::rustical_xml::XmlSerialize for #ident #type_generics #where_clause {
fn serialize<W: ::std::io::Write>(
&self,
tag: Option<&[u8]>,
writer: &mut ::quick_xml::Writer<W>
) -> ::std::io::Result<()> {
use ::quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
let tag_str = tag.map(String::from_utf8_lossy);
if let Some(tag) = &tag_str {
writer.write_event(Event::Start(BytesStart::new(tag.to_owned())))?;
}
#(#tag_writers);*
if let Some(tag) = &tag_str {
writer.write_event(Event::End(BytesEnd::new(tag.to_owned())))?;
}
Ok(())
}
}
}
}
}

View File

@@ -218,4 +218,23 @@ impl Field {
}
})
}
pub fn tag_writer(&self) -> Option<proc_macro2::TokenStream> {
let field_ident = self.field_ident();
let field_name = self.xml_name();
match self.attrs.xml_ty {
FieldType::Attr => None,
FieldType::Text => Some(quote! {
writer.write_event(Event::Text(BytesText::new(&self.#field_ident)))?;
}),
FieldType::Tag => Some(quote! {
self.#field_ident.serialize(Some(#field_name), writer)?;
}),
FieldType::Untagged => Some(quote! {
// TODO: untag!
self.#field_ident.serialize(None, writer)?;
}),
}
}
}

View File

@@ -16,6 +16,18 @@ pub fn derive_xml_deserialize(input: proc_macro::TokenStream) -> proc_macro::Tok
.into()
}
#[proc_macro_derive(XmlSerialize, attributes(xml))]
pub fn derive_xml_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
match &input.data {
syn::Data::Enum(e) => Enum::parse(&input, e).impl_se(),
syn::Data::Struct(s) => NamedStruct::parse(&input, s).impl_se(),
syn::Data::Union(_) => panic!("Union not supported"),
}
.into()
}
#[proc_macro_derive(XmlRoot, attributes(xml))]
pub fn derive_xml_root(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);