freezable-macros 0.2.0

Support proc macro for the freezable package
Documentation
use quote::format_ident;
use proc_macro::TokenStream;
use quote::quote;
use syn::Fields::Named;
use syn::Fields::Unnamed;
use syn::Data::Struct;
use syn::DeriveInput;
use syn::parse_macro_input;

pub fn freezable_impl(_args: TokenStream, input: TokenStream) -> TokenStream {
    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = parse_macro_input!(input as DeriveInput);
    let where_clause = &generics.where_clause;

    match data {
        Struct(my_struct) => {
            match my_struct.fields {
                Named(fields) => {
                    let mut field_inits: Vec<proc_macro2::TokenStream> = vec![];
                    let field_stream: Vec<proc_macro2::TokenStream> = fields.named.into_iter().map(|field| {
                        let name = field.ident.as_ref().expect("Field is unnamed");
                        let func_name = format_ident!("_default_{}_{}", ident.to_string().to_lowercase(), name);
                        let field_type = &field.ty;
                        let field_func = quote! {
                            fn #func_name() -> #field_type { #ident::default().#name }
                        };
                        field_inits.push(field_func);
                        let func_name_str = format!("{func_name}");
                        let literal_func_name = syn::LitStr::new(&func_name_str, func_name.span());
                        quote!{
                            #[serde(default = #literal_func_name)]
                            #field
                        }
                    }).collect();
                    quote!{
                        #[derive(freezable_trait::_serde::Serialize, freezable_trait::_serde::Deserialize)]
                        #[serde(crate = "freezable_trait::_serde")]
                        struct #generics #ident #generics #where_clause {
                            #(#field_stream),*
                        }
                        #(#field_inits)*
                    }
                },
                Unnamed(_fields) => panic!("Fields should be named"),
                _unit => panic!("Should not be unit struct"),
            }
        }
        _ => panic!("Must be a struct.")
    }.into()
}