Skip to main content

moverox_codegen/
generics.rs

1use std::collections::HashSet;
2
3use quote::quote;
4use unsynn::{Ident, ToTokens as _, TokenStream};
5
6use crate::Result;
7
8pub(super) trait GenericsExt {
9    fn to_rust(&self) -> TokenStream;
10
11    /// Generics declaration for the enum/struct definition.
12    fn type_generics(
13        &self,
14        thecrate: &TokenStream,
15        otw_types: HashSet<Ident>,
16    ) -> Result<TokenStream>;
17
18    fn phantoms(&self) -> impl Iterator<Item = &Ident>;
19}
20
21impl GenericsExt for move_syn::Generics {
22    fn to_rust(&self) -> TokenStream {
23        let idents = self.generics().map(|g| &g.ident);
24        quote! {
25            <#(#idents),*>
26        }
27    }
28
29    fn type_generics(
30        &self,
31        thecrate: &TokenStream,
32        mut otw_types: HashSet<Ident>,
33    ) -> Result<TokenStream> {
34        let idents: Vec<_> = self
35            .generics()
36            .map(|g| &g.ident)
37            .map(|ident| {
38                if otw_types.remove(ident) {
39                    quote!(#ident = #thecrate::Otw)
40                } else {
41                    ident.to_token_stream()
42                }
43            })
44            .collect();
45
46        if !otw_types.is_empty() {
47            let excess = otw_types
48                .into_iter()
49                .map(|ident| ident.to_string())
50                .reduce(|a, b| a + ", " + &b)
51                .unwrap_or_default();
52            return Err(format!("Not a type parameter of this datatype: {excess}").into());
53        }
54
55        Ok(quote! {
56            <#(#idents),*>
57        })
58    }
59
60    fn phantoms(&self) -> impl Iterator<Item = &Ident> {
61        self.generics()
62            .filter(|d| d.phantom.is_some())
63            .map(|d| &d.ident)
64    }
65}