moxy-derive 0.0.4

derive macros for moxy crate
Documentation
use proc_macro2::TokenStream;
use quote::quote;

use crate::{
    Render,
    core::{Attrs, Field},
    params,
};

#[derive(Clone, Default)]
pub struct EnumSyntax;

impl Render for EnumSyntax {
    type Args = params::EnumParams;

    fn render(&self, args: Self::Args) -> syn::Result<TokenStream> {
        let ident = &args.input.ident;
        let (impl_generics, type_generics, where_generics) = args.input.generics.split_for_impl();
        let default_variants: Vec<_> = args
            .data
            .variants
            .iter()
            .filter(|v| {
                Attrs::parse(&v.attrs)
                    .map(|a| a.exists("default"))
                    .unwrap_or(false)
            })
            .collect();

        if default_variants.is_empty() {
            return Err(syn::Error::new_spanned(
                &args.input.ident,
                "no variant marked with #[moxy(default)]",
            ));
        }

        if default_variants.len() > 1 {
            return Err(syn::Error::new_spanned(
                &default_variants[1].ident,
                "multiple variants marked with #[moxy(default)]",
            ));
        }

        let variant = default_variants[0];
        let variant_ident = &variant.ident;
        let body = match &variant.fields {
            syn::Fields::Unit => {
                quote! { Self::#variant_ident }
            }
            syn::Fields::Unnamed(_) => {
                let fields: Vec<_> = variant
                    .fields
                    .iter()
                    .enumerate()
                    .map(|(i, f)| Field::parse(i, f))
                    .collect::<syn::Result<Vec<_>>>()?;
                let defaults: Vec<_> = fields
                    .iter()
                    .map(|field| {
                        if let Some(value) = field.default_value() {
                            quote!(#value.into())
                        } else {
                            quote!(::std::default::Default::default())
                        }
                    })
                    .collect();

                quote! { Self::#variant_ident(#(#defaults),*) }
            }
            syn::Fields::Named(_) => {
                let fields: Vec<_> = variant
                    .fields
                    .iter()
                    .enumerate()
                    .map(|(i, f)| Field::parse(i, f))
                    .collect::<syn::Result<Vec<_>>>()?;
                let defaults: Vec<_> = fields
                    .iter()
                    .map(|field| {
                        let fname = field.name();

                        if let Some(value) = field.default_value() {
                            quote!(#fname: #value.into())
                        } else {
                            quote!(#fname: ::std::default::Default::default())
                        }
                    })
                    .collect();

                quote! { Self::#variant_ident { #(#defaults),* } }
            }
        };

        Ok(quote! {
            impl #impl_generics ::std::default::Default for #ident #type_generics #where_generics {
                fn default() -> Self {
                    #body
                }
            }
        })
    }
}