use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, parse2};
pub(crate) fn expand(input: TokenStream) -> syn::Result<TokenStream> {
let input = parse2::<DeriveInput>(input)?;
let name = &input.ident;
let Data::Struct(data) = input.data else {
return Err(syn::Error::new_spanned(
name,
"Merge can only be derived for structs",
));
};
let Fields::Named(fields) = data.fields else {
return Err(syn::Error::new_spanned(name, "Merge requires named fields"));
};
let field_assignments: Vec<TokenStream> = fields
.named
.iter()
.filter_map(|field| {
let field_ident = field.ident.as_ref()?;
Some(quote! {
if let ::std::option::Option::Some(value) = self.#field_ident {
target.#field_ident = value;
}
})
})
.collect();
Ok(quote! {
impl #name {
pub fn merge_into(self, target: &mut Self) {
#(#field_assignments)*
}
}
})
}