ouroboros_macro/
utils.rs
1use heck::ToSnakeCase;
2use proc_macro2::{Group, Ident, TokenStream, TokenTree};
3use quote::{format_ident, quote};
4use syn::{GenericParam, Generics, Visibility};
5
6pub fn make_generic_consumers(generics: &Generics) -> impl Iterator<Item = (TokenStream, Ident)> {
8 generics
9 .params
10 .clone()
11 .into_iter()
12 .map(|param| match param {
13 GenericParam::Type(ty) => {
14 let ident = &ty.ident;
15 (
16 quote! { #ident },
17 format_ident!(
18 "_consume_template_type_{}",
19 ident.to_string().to_snake_case()
20 ),
21 )
22 }
23 GenericParam::Lifetime(lt) => {
24 let lifetime = <.lifetime;
25 let ident = &lifetime.ident;
26 (
27 quote! { &#lifetime () },
28 format_ident!("_consume_template_lifetime_{}", ident),
29 )
30 }
31 GenericParam::Const(ct) => {
33 let ident = ct.ident;
34 (
35 quote! { () },
36 format_ident!(
37 "_comsume_template_const_parameter_{}",
38 ident.to_string().to_snake_case()
39 ),
40 )
41 },
42 })
43}
44
45pub fn make_generic_arguments(generics: Vec<&GenericParam>) -> Vec<TokenStream> {
47 let mut arguments = Vec::new();
48 for generic in generics {
49 match generic {
50 GenericParam::Type(typ) => {
51 let ident = &typ.ident;
52 arguments.push(quote! { #ident });
53 }
54 GenericParam::Lifetime(lt) => {
55 let lifetime = <.lifetime;
56 arguments.push(quote! { #lifetime });
57 }
58 GenericParam::Const(ct) => {
59 let ident = &ct.ident;
60 arguments.push(quote! { #ident });
61 },
62 }
63 }
64 arguments
65}
66
67pub fn uses_this_lifetime(input: TokenStream) -> bool {
68 for token in input.into_iter() {
69 match token {
70 TokenTree::Ident(ident) => {
71 if ident == "this" {
72 return true;
73 }
74 }
75 TokenTree::Group(group) => {
76 if uses_this_lifetime(group.stream()) {
77 return true;
78 }
79 }
80 _ => (),
81 }
82 }
83 false
84}
85
86pub fn replace_this_with_lifetime(input: TokenStream, lifetime: Ident) -> TokenStream {
87 input
88 .into_iter()
89 .map(|token| match &token {
90 TokenTree::Ident(ident) => {
91 if ident == "this" {
92 TokenTree::Ident(lifetime.clone())
93 } else {
94 token
95 }
96 }
97 TokenTree::Group(group) => TokenTree::Group(Group::new(
98 group.delimiter(),
99 replace_this_with_lifetime(group.stream(), lifetime.clone()),
100 )),
101 _ => token,
102 })
103 .collect()
104}
105
106pub fn submodule_contents_visibility(original_visibility: &Visibility) -> Visibility {
107 match original_visibility {
108 Visibility::Inherited => syn::parse_quote! { pub(super) },
110 Visibility::Restricted(ref restricted) => {
112 let is_first_component_super = restricted
113 .path
114 .segments
115 .first()
116 .map(|segm| segm.ident == "super")
117 .unwrap_or(false);
118 if restricted.path.leading_colon.is_none() && is_first_component_super {
119 let mut new_visibility = restricted.clone();
120 new_visibility.in_token = Some(
121 restricted
122 .in_token
123 .unwrap_or_else(|| syn::parse_quote! { in }),
124 );
125 new_visibility.path.segments = std::iter::once(syn::parse_quote! { super })
126 .chain(restricted.path.segments.iter().cloned())
127 .collect();
128 Visibility::Restricted(new_visibility)
129 } else {
130 original_visibility.clone()
131 }
132 }
133 _ => original_visibility.clone(),
135 }
136}
137
138pub fn to_class_case(s: &str) -> String {
141 s.split('_')
142 .flat_map(|word| {
143 let mut chars = word.chars();
144 let first = chars.next();
145 first
147 .into_iter()
148 .flat_map(|c| c.to_uppercase())
149 .chain(chars.flat_map(|c| c.to_lowercase()))
150 })
151 .collect()
152}