use proc_macro2::TokenStream;
use quote::quote;
use syn::{Attribute, GenericParam, Ident, ItemTraitAlias, WherePredicate};
use crate::{
parse::TraitAliases,
special::{predicate_type, type_parameter},
};
pub fn trait_aliases(input: &TraitAliases) -> TokenStream {
let aliases = input.items.iter().map(trait_alias);
quote! {
#(#aliases)*
}
}
pub const DOC: &str = stringify!(doc);
pub fn is_doc_attribute(attribute: &Attribute) -> bool {
attribute.meta.path().is_ident(DOC)
}
pub fn blanket_impl_doc(name: &Ident) -> String {
format!("Blanket implementation of [`{name}`] for all types satisfying its bounds.")
}
pub fn trait_alias(alias: &ItemTraitAlias) -> TokenStream {
let (docs, attributes): (Vec<_>, Vec<_>) =
alias.attrs.iter().cloned().partition(is_doc_attribute);
let visibility = &alias.vis;
let name = &alias.ident;
let generics = &alias.generics;
let bounds = &alias.bounds;
let (_, type_generics, where_clause) = generics.split_for_impl();
let mut derived = generics.clone();
derived.params.push(GenericParam::Type(type_parameter()));
derived
.make_where_clause()
.predicates
.push(WherePredicate::Type(predicate_type(bounds.clone())));
let (impl_generics, _, where_derived) = derived.split_for_impl();
let blanket_impl = blanket_impl_doc(name);
quote! {
#(#docs)*
#(#attributes)*
#visibility trait #name #generics: #bounds #where_clause {}
#[doc = #blanket_impl]
#(#attributes)*
impl #impl_generics #name #type_generics for __T #where_derived {}
}
}