use proc_macro2::TokenStream;
use quote::quote;
use syn::{GenericParam, Generics, Ident};
pub fn extract_type_param_idents(params: &syn::punctuated::Punctuated<GenericParam, syn::token::Comma>) -> Vec<TokenStream> {
params
.iter()
.map(|param| match param {
GenericParam::Type(type_param) => {
let ident = &type_param.ident;
quote! { #ident }
}
GenericParam::Lifetime(lifetime_param) => {
let lifetime = &lifetime_param.lifetime;
quote! { #lifetime }
}
GenericParam::Const(const_param) => {
let ident = &const_param.ident;
quote! { #ident }
}
})
.collect()
}
pub fn impl_generics_with_f(user_generics: &Generics, module_name: &Ident) -> (Generics, Vec<TokenStream>) {
let mut impl_generics = user_generics.clone();
let f_param: GenericParam = syn::parse_quote!(F: #module_name::Fields);
let mut insertion_point = impl_generics.params.len();
for (i, param) in impl_generics.params.iter().enumerate() {
if !matches!(param, GenericParam::Lifetime(_)) {
insertion_point = i;
break;
}
}
impl_generics.params.insert(insertion_point, f_param);
let user_type_args = extract_type_param_idents(&user_generics.params);
(impl_generics, user_type_args)
}
pub fn remainder_type_args(generics: &Generics, user_type_args: &[TokenStream]) -> TokenStream {
if generics.params.is_empty() {
quote! { <F, F2> }
} else {
let (lifetime_args, other_args): (Vec<_>, Vec<_>) = user_type_args
.iter()
.zip(generics.params.iter())
.partition(|(_, param)| matches!(param, GenericParam::Lifetime(_)));
let lifetime_tokens: Vec<_> = lifetime_args.into_iter().map(|(tok, _)| tok).collect();
let other_tokens: Vec<_> = other_args.into_iter().map(|(tok, _)| tok).collect();
quote! { <#(#lifetime_tokens,)* F, F2, #(#other_tokens),*> }
}
}