use std::collections::HashSet;
use proc_macro2::Span as Span2;
use syn::{
visit::{visit_item_trait, Visit},
Block, Ident, ItemTrait, Lifetime,
};
const PROXY_TY_PARAM_NAME: &str = "__AutoImplProxyT";
const PROXY_LT_PARAM_NAME: &str = "'__auto_impl_proxy_lifetime";
pub(crate) fn find_suitable_param_names(trait_def: &ItemTrait) -> (Ident, Lifetime) {
struct IdentCollector<'ast> {
ty_names: HashSet<&'ast Ident>,
lt_names: HashSet<&'ast Ident>,
}
impl<'ast> Visit<'ast> for IdentCollector<'ast> {
fn visit_ident(&mut self, i: &'ast Ident) {
self.ty_names.insert(i);
}
fn visit_lifetime(&mut self, lt: &'ast Lifetime) {
self.lt_names.insert(<.ident);
}
fn visit_block(&mut self, _: &'ast Block) {}
}
let mut visitor = IdentCollector {
ty_names: HashSet::new(),
lt_names: HashSet::new(),
};
visit_item_trait(&mut visitor, trait_def);
fn char_to_ident(c: u8) -> Ident {
let arr = [c];
let s = ::std::str::from_utf8(&arr).unwrap();
Ident::new(s, param_span())
}
let ty_name = (b'T'..=b'Z')
.chain(b'A'..=b'S')
.map(char_to_ident)
.find(|i| !visitor.ty_names.contains(i))
.unwrap_or_else(|| Ident::new(PROXY_TY_PARAM_NAME, param_span()));
let lt_name = (b'a'..=b'z')
.map(char_to_ident)
.find(|i| !visitor.lt_names.contains(i))
.unwrap_or_else(|| Ident::new(PROXY_LT_PARAM_NAME, param_span()));
let lt = Lifetime {
apostrophe: param_span(),
ident: lt_name,
};
(ty_name, lt)
}
fn param_span() -> Span2 {
Span2::call_site()
}