extern crate proc_macro;
use proc_macro::TokenStream;
use quote::format_ident;
use quote::quote;
use syn::parse_macro_input;
use syn::Fields::Named;
use syn::ItemStruct;

#[proc_macro_derive(Prj)]
pub fn prj_macro(input: TokenStream) -> TokenStream {
    let struct_item = parse_macro_input!(input as ItemStruct);
    let stru_name = struct_item.ident;

    match struct_item.fields {
        Named(fields) => {
            let idents = fields
                .named
                .iter()
                .filter(|x| {
                    if let syn::Visibility::Public(_) = x.vis {
                        true
                    } else {
                        false
                    }
                })
                .map(|x| x.ident.as_ref().unwrap());
            let idents_type = fields.named.iter().map(|x| &x.ty);
            let func_name = idents.clone().map(|x| format_ident!("change_{}", &x));
            quote!(
                impl #stru_name{
                    #(pub fn #func_name (mut self,value:#idents_type) -> Self{
                        self.#idents = value;
                        self
                    })*
                }
            )
            .into()
        }
        _ => quote!(
            struct A {}
        )
        .into(),
    }
}
