use proc_macro2::TokenStream;
pub fn expand_derive_construct(input: &mut syn::DeriveInput) -> syn::Result<TokenStream> {
let name = &input.ident;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let fields = match &input.data {
syn::Data::Struct(data) => match &data.fields {
syn::Fields::Named(fields) => fields.named.iter().map(|field| {
let ident = field.ident.as_ref().unwrap();
let ty = &field.ty;
let attrs = &field.attrs;
(ident, ty, attrs)
}),
_ => return Err(syn::Error::new_spanned(input, "Only Structs with named fields are supported")),
},
_ => return Err(syn::Error::new_spanned(input, "Only Structs are supported")),
};
let field_len = fields.len();
let mut input_arguments = Vec::with_capacity(field_len);
let mut struct_fields = Vec::with_capacity(field_len);
fields.for_each(|(ident, ty, attrs)| {
let ident = ident.clone();
let ty = ty.clone();
let attrs = attrs.clone();
let except = attrs.iter().any(|attr| {
if let syn::Meta::Path(path) = &attr.meta {
if path.is_ident("except") {
return true;
}
}
false
});
if !except {
input_arguments.push(quote!(#ident: #ty));
struct_fields.push(quote!(#ident))
}
});
let construct = if input_arguments.len() == field_len {
quote! {
impl #impl_generics #name #ty_generics #where_clause {
pub fn construct(#(#input_arguments),*) -> Self {
Self {
#(#struct_fields),*
}
}
}
}
} else {
quote! {
impl #impl_generics #name #ty_generics #where_clause {
pub fn construct(#(#input_arguments),*) -> Self {
Self {
#(#struct_fields),*
,..Default::default()
}
}
}
}
};
Ok(construct)
}