newnum_proc_macros 0.13.1

Procedural macros reexported by the deprecated `newnum` crate
Documentation
use proc_macro2::{Literal, Span, TokenStream};
use quote::{format_ident, quote, ToTokens};
use syn::{Data, Error, Fields, Type};

pub fn derive_map_fields(
    input: &syn::DeriveInput,
    trait_ident: &str,
    mut map: impl FnMut(&TokenStream, &Type) -> TokenStream,
) -> proc_macro2::TokenStream {
    match &input.data {
        Data::Struct(data) => {
            let members = data.fields.members();
            let member_values = data.fields.iter().enumerate().map(|(i, field)| {
                let member = if let Some(ident) = &field.ident {
                    quote! { self.#ident }
                } else {
                    let i = Literal::usize_unsuffixed(i);
                    quote! { self.#i }
                };

                map(&member, &field.ty)
            });

            quote! {
                Self {#(
                    #members: #member_values,
                )*}
            }
        }
        Data::Enum(data) => {
            let variant_idents = data
                .variants
                .iter()
                .map(|variant| &variant.ident)
                .collect::<Vec<_>>();

            let variant_fields = data.variants.iter().map(|variant| match &variant.fields {
                Fields::Named(fields) => {
                    let field_idents = fields.named.iter().map(|f| &f.ident);

                    quote! { { #(#field_idents), * } }
                }
                Fields::Unnamed(fields) => {
                    let field_idents = fields
                        .unnamed
                        .iter()
                        .enumerate()
                        .map(|(i, _)| format_ident!("field_{i}"));

                    quote! { (#(#field_idents), *) }
                }
                Fields::Unit => quote! {},
            });

            let variant_members = data
                .variants
                .iter()
                .map(|variant| variant.fields.members().collect::<Vec<_>>());

            let variant_member_values = data.variants.iter().map(|variant| match &variant.fields {
                Fields::Named(fields) => fields
                    .named
                    .iter()
                    .map(|field| map(&field.ident.to_token_stream(), &field.ty))
                    .collect::<Vec<_>>(),
                Fields::Unnamed(fields) => fields
                    .unnamed
                    .iter()
                    .enumerate()
                    .map(|(i, field)| map(&format_ident!("field_{i}").to_token_stream(), &field.ty))
                    .collect::<Vec<_>>(),
                Fields::Unit => Vec::new(),
            });

            quote! {
                match self {#(
                    Self::#variant_idents #variant_fields => Self::#variant_idents {#(
                        #variant_members: #variant_member_values,
                    )*},
                )*}
            }
        }
        Data::Union(_) => Error::new(
            Span::call_site(),
            format!("`{trait_ident}` cannot be derived for unions"),
        )
        .to_compile_error()
        .into(),
    }
}