bon_macros/normalization/
generics_namespace.rs
1use crate::util::prelude::*;
2use proc_macro2::TokenTree;
3use std::collections::BTreeSet;
4use syn::visit::Visit;
5
6#[derive(Debug, Default, Clone)]
7pub(crate) struct GenericsNamespace {
8 pub(crate) idents: BTreeSet<String>,
10
11 pub(crate) lifetimes: BTreeSet<String>,
13}
14
15impl Visit<'_> for GenericsNamespace {
16 fn visit_ident(&mut self, ident: &syn::Ident) {
17 self.idents.insert(ident.to_string());
18 }
19
20 fn visit_meta_list(&mut self, meta_list: &syn::MetaList) {
21 syn::visit::visit_meta_list(self, meta_list);
22 self.visit_token_stream(meta_list.tokens.clone());
23 }
24
25 fn visit_lifetime(&mut self, lifetime: &syn::Lifetime) {
26 self.lifetimes.insert(lifetime.ident.to_string());
27 }
28
29 fn visit_item(&mut self, _item: &syn::Item) {
30 }
32}
33
34impl GenericsNamespace {
35 pub(crate) fn unique_ident(&self, name: String) -> syn::Ident {
36 let name = Self::unique_name(&self.idents, name);
37 syn::Ident::new(&name, Span::call_site())
38 }
39
40 pub(crate) fn unique_lifetime(&self, name: String) -> String {
41 Self::unique_name(&self.lifetimes, name)
42 }
43
44 fn unique_name(taken: &BTreeSet<String>, mut ident: String) -> String {
46 while taken.contains(&ident) {
47 ident.push('_');
48 }
49 ident
50 }
51
52 pub(crate) fn visit_token_stream(&mut self, token_stream: TokenStream) {
53 let mut tokens = token_stream.into_iter().peekable();
54 while let Some(tt) = tokens.next() {
55 match tt {
56 TokenTree::Group(group) => {
57 self.visit_token_stream(group.stream());
58 }
59 TokenTree::Ident(ident) => {
60 self.visit_ident(&ident);
61 }
62 TokenTree::Punct(punct) => {
63 if punct.as_char() != '\'' {
64 continue;
65 }
66 if let Some(TokenTree::Ident(ident)) = tokens.peek() {
67 self.lifetimes.insert(ident.to_string());
68 tokens.next();
69 }
70 }
71 TokenTree::Literal(_) => {}
72 }
73 }
74 }
75}