use proc_macro2::{Ident, Span, TokenStream};
use syn::{GenericParam, Generics, Lifetime, LifetimeDef, TypeGenerics};
pub fn map_type_params<F, R>(generics: &Generics, mapper: F) -> Vec<R>
where
F: FnMut(&Ident) -> R,
{
generics
.params
.iter()
.filter_map(|param| match param {
GenericParam::Type(param) => Some(¶m.ident),
_ => None,
})
.map(mapper)
.collect()
}
pub fn map_lifetimes<F, R>(generics: &Generics, mapper: F) -> Vec<R>
where
F: FnMut(&Lifetime) -> R,
{
generics
.params
.iter()
.filter_map(|param| match param {
GenericParam::Lifetime(def) => Some(&def.lifetime),
_ => None,
})
.map(mapper)
.collect()
}
pub fn split_for_impl<'a>(
generics: &'a Generics,
extra_lifetimes: &[&str],
) -> (TokenStream, TypeGenerics<'a>, TokenStream) {
let (_, ty_generics, where_clause) = generics.split_for_impl();
let ty_generics = ty_generics.clone();
let where_clause = where_clause
.map(|clause| quote! { #clause, })
.unwrap_or(quote! { where });
let mut generics = generics.clone();
extra_lifetimes
.into_iter()
.map(|lifetime| {
GenericParam::from(LifetimeDef::new(Lifetime::new(lifetime, Span::call_site())))
})
.for_each(|lifetime| generics.params.insert(0, lifetime));
let (impl_generics, ..) = generics.split_for_impl();
(quote! { #impl_generics }, ty_generics, where_clause)
}