codama_syn_helpers/extensions/
generics.rs

1use 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}