procmeta-core 0.3.5

proc-macro helper
Documentation
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{Data, DeriveInput, Fields, LitInt};

pub fn expand(input: DeriveInput) -> TokenStream {
    let ty = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let mut result_token = quote!();
    match &input.data {
        Data::Struct(data) => match &data.fields {
            syn::Fields::Named(named) => {
                let mut let_token = quote!();
                let mut inner_token = quote!();
                for field in named.named.iter() {
                    let field_ident = &field.ident;
                    let_token = quote! {
                        #let_token
                        let #field_ident = self.#field_ident.get_token_stream();
                    };
                    inner_token = quote! {
                        #inner_token
                        #field_ident: ##field_ident,
                    };
                }
                result_token = quote! {
                    #let_token
                    quote!(#ty {
                        #inner_token
                    })
                };
            }
            syn::Fields::Unnamed(unamed) => {
                let mut let_token = quote!();
                let mut inner_token = quote!();
                for (index, _field) in unamed.unnamed.iter().enumerate() {
                    let field_ident = format_ident!("field_{}", index);
                    let index = LitInt::new(&index.to_string(), Span::call_site());
                    let value_token = quote!(self. #index.get_token_stream());
                    let_token = quote! {
                        #let_token
                        let #field_ident = #value_token;
                    };
                    inner_token = quote! {
                        #inner_token
                        ##field_ident,
                    };
                }
                result_token = quote! {
                    #let_token
                    quote!(#ty (
                        #inner_token
                    ))
                };
            }
            syn::Fields::Unit => {
                result_token = quote! {
                    quote!(#ty)
                };
            }
        },
        Data::Enum(enumer) => {
            for variant in &enumer.variants {
                let variant_token;
                let variant_ident = &variant.ident;
                let mut pat = quote!();
                match &variant.fields {
                    Fields::Named(named) => {
                        let mut let_token = quote!();
                        let mut inner_token = quote!();
                        for field in named.named.iter() {
                            let field_ident = &field.ident;
                            pat = quote! {#pat #field_ident,};
                            let_token = quote! {
                                #let_token
                                let #field_ident = #field_ident.get_token_stream();
                            };
                            inner_token = quote! {
                                #inner_token
                                #field_ident: ##field_ident,
                            };
                        }
                        pat = quote! {{#pat}};

                        variant_token = quote! {
                            #let_token
                            quote!(#ty :: #variant_ident {
                                #inner_token
                            })
                        };
                    }
                    Fields::Unnamed(unamed) => {
                        let mut let_token = quote!();
                        let mut inner_token = quote!();
                        for (index, _field) in unamed.unnamed.iter().enumerate() {
                            let field_ident = format_ident!("field_{}", index);
                            pat = quote! {#pat #field_ident,};
                            let value_token = quote!(#field_ident.get_token_stream());
                            let_token = quote! {
                                #let_token
                                let #field_ident = #value_token;
                            };
                            inner_token = quote! {
                                #inner_token
                                ##field_ident,
                            };
                        }
                        pat = quote! {(#pat)};

                        variant_token = quote! {
                            #let_token
                            quote!(#ty :: #variant_ident (
                                #inner_token
                            ))
                        };
                    }
                    Fields::Unit => {
                        pat = quote!();
                        variant_token = quote! {
                            quote!(#ty :: #variant_ident)
                        };
                    }
                }
                result_token = quote! {
                    #result_token
                    #ty ::#variant_ident #pat => {
                        #variant_token
                    }
                }
            }
            result_token = quote! {
                match self {
                    #result_token
                }
            };
        }
        Data::Union(_) => unimplemented!(),
    }
    quote! {
        impl #impl_generics GetTokenStream for #ty #ty_generics #where_clause {

            fn get_token_stream(self) -> TokenStream {
                #result_token
            }

            fn get_self_ty() -> TokenStream {
                quote!(#ty)
            }
        }
    }
}