codama_syn_helpers/extensions/
generics.rs1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::Generics;
4
5pub trait GenericsExtension {
6 fn get_self(&self) -> &Generics;
7
8 fn param_idents(&self) -> TokenStream {
9 let this = self.get_self();
10 let idents = this
11 .params
12 .iter()
13 .map(|param| match param {
14 syn::GenericParam::Type(type_param) => {
15 let ident = &type_param.ident;
16 quote! { #ident }
17 }
18 syn::GenericParam::Lifetime(lifetime) => {
19 let lifetime = &lifetime.lifetime;
20 quote! { #lifetime }
21 }
22 syn::GenericParam::Const(const_param) => {
23 let ident = &const_param.ident;
24 quote! { #ident }
25 }
26 })
27 .collect::<Vec<_>>();
28 match idents.is_empty() {
29 true => quote! {},
30 false => quote! { <#(#idents),*> },
31 }
32 }
33
34 fn block_wrappers(&self) -> (TokenStream, TokenStream) {
35 let this = self.get_self();
36 let declarations = &this.params;
37 let declarations = match &this.params.is_empty() {
38 true => quote! {},
39 false => quote! { <#declarations> },
40 };
41 let usages = self.param_idents();
42 let where_clause = &this.where_clause;
43 (quote! { #declarations }, quote! { #usages #where_clause })
44 }
45}
46
47impl GenericsExtension for Generics {
48 fn get_self(&self) -> &Generics {
49 self
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use quote::quote;
57
58 #[test]
59 fn param_idents() {
60 let r#struct: syn::ItemStruct = syn::parse_quote! { struct Foo(u32); };
61 assert_eq!(
62 r#struct.generics.param_idents().to_string(),
63 quote! {}.to_string()
64 );
65
66 let r#struct: syn::ItemStruct =
67 syn::parse_quote! { struct Foo<'a, T: Clone, U: PartialEq> where U: Eq (T); };
68 assert_eq!(
69 r#struct.generics.param_idents().to_string(),
70 quote! { <'a, T, U> }.to_string()
71 );
72 }
73
74 #[test]
75 fn block_wrappers() {
76 let r#struct: syn::ItemStruct = syn::parse_quote! { struct Foo(u32); };
77 let (pre, post) = r#struct.generics.block_wrappers();
78 assert_eq!(
79 quote! { impl #pre Bar for Foo #post {} }.to_string(),
80 quote! { impl Bar for Foo {} }.to_string()
81 );
82
83 let r#struct: syn::ItemStruct =
84 syn::parse_quote! { struct Foo<'a, T: Clone, U: PartialEq> where U: Eq (T); };
85 let (pre, post) = r#struct.generics.block_wrappers();
86 assert_eq!(
87 quote! { impl #pre Bar for Foo #post {} }.to_string(),
88 quote! { impl<'a, T: Clone, U: PartialEq> Bar for Foo<'a, T, U> where U: Eq (T) {} }
89 .to_string()
90 );
91 }
92}