Implement serialization for structs with named fields

This commit is contained in:
Bartlomiej Choinski 2022-06-08 13:36:58 +02:00 committed by Dirkjan Ochtman
parent 67c61e24dd
commit 99a7d561e0
3 changed files with 51 additions and 6 deletions

View File

@ -10,5 +10,6 @@ proc-macro = true
[dependencies] [dependencies]
heck = "0.4" heck = "0.4"
proc-macro2 = "1.0.39"
quote = "1.0.18" quote = "1.0.18"
syn = { version = "1.0.86", features = ["full"] } syn = { version = "1.0.86", features = ["full"] }

View File

@ -6,15 +6,38 @@ use syn::parse_macro_input;
#[proc_macro_derive(ToXml)] #[proc_macro_derive(ToXml)]
pub fn to_xml(input: TokenStream) -> TokenStream { pub fn to_xml(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as syn::ItemStruct); let ast = parse_macro_input!(input as syn::DeriveInput);
let ident = &ast.ident; let ident = &ast.ident;
let name = ident.to_string(); let root_name = ident.to_string();
let mut output: proc_macro2::TokenStream =
TokenStream::from(quote!("<".to_owned() + #root_name + ">")).into();
match &ast.data {
syn::Data::Struct(ref data) => {
match data.fields {
syn::Fields::Named(ref fields) => {
fields
.named
.iter()
.for_each(|field| {
let field_name = field.ident.as_ref().unwrap().to_string();
let field_value = field.ident.as_ref().unwrap();
output.extend(quote!(+ "<" + #field_name + ">" + self.#field_value.to_string().as_str() + "</" + #field_name + ">"));
});
}
syn::Fields::Unnamed(_) => todo!(),
syn::Fields::Unit => {}
};
}
_ => todo!(),
};
output.extend(quote!(+ "</" + #root_name + ">"));
TokenStream::from(quote!( TokenStream::from(quote!(
impl ToXml for #ident { impl ToXml for #ident {
fn write_xml<W: ::std::fmt::Write>(&self, write: &mut W) -> Result<(), instant_xml::Error> { fn write_xml<W: ::std::fmt::Write>(&self, write: &mut W) -> Result<(), instant_xml::Error> {
write.write_str("<")?; write.write_str(&(#output))?;
write.write_fmt(format_args!("{}", #name))?;
write.write_str("/>")?;
Ok(()) Ok(())
} }
} }

View File

@ -3,8 +3,29 @@ use instant_xml::{FromXml, ToXml};
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)] #[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
struct Unit; struct Unit;
#[derive(Debug, Eq, PartialEq, ToXml)]
struct StructWithNamedFields {
flag: bool,
string: String,
number: i32,
}
#[test] #[test]
fn unit() { fn unit() {
assert_eq!(Unit.to_xml().unwrap(), "<Unit/>"); assert_eq!(Unit.to_xml().unwrap(), "<Unit></Unit>");
assert_eq!(Unit::from_xml("<Unit/>").unwrap(), Unit); assert_eq!(Unit::from_xml("<Unit/>").unwrap(), Unit);
} }
#[test]
fn struct_with_named_fields() {
assert_eq!(
StructWithNamedFields {
flag: true,
string: "test".to_string(),
number: 1,
}
.to_xml()
.unwrap(),
"<StructWithNamedFields><flag>true</flag><string>test</string><number>1</number></StructWithNamedFields>"
);
}