reflect/
ty.rs

1use crate::{
2    generics, Data, Function, GenericConstraint, GenericParam, Generics, Ident, Lifetime, Path,
3    Print, Signature, TypeParamBound,
4};
5use proc_macro2::TokenStream;
6use quote::{quote, ToTokens};
7use ref_cast::RefCast;
8use syn::TypePath;
9
10#[derive(Debug, Clone)]
11#[repr(C)]
12pub struct Type(pub(crate) TypeNode);
13
14#[derive(Debug, Clone)]
15pub(crate) enum TypeNode {
16    Infer,
17    Tuple(Vec<Type>),
18    PrimitiveStr,
19    Reference {
20        lifetime: Option<Lifetime>,
21        inner: Box<TypeNode>,
22    },
23    ReferenceMut {
24        lifetime: Option<Lifetime>,
25        inner: Box<TypeNode>,
26    },
27    Dereference(Box<TypeNode>),
28    TraitObject(Vec<TypeParamBound>),
29    DataStructure {
30        name: Ident,
31        generics: Generics,
32        data: Data<Type>,
33    },
34    Path(Path),
35}
36
37impl Type {
38    pub fn unit() -> Self {
39        Type(TypeNode::Tuple(Vec::new()))
40    }
41
42    pub fn tuple(types: &[Self]) -> Self {
43        Type(TypeNode::Tuple(Vec::from(types)))
44    }
45
46    pub fn primitive_str() -> Self {
47        Type(TypeNode::PrimitiveStr)
48    }
49
50    pub fn reference(&self) -> Self {
51        Type(TypeNode::Reference {
52            lifetime: None,
53            inner: Box::new(self.0.clone()),
54        })
55    }
56
57    pub fn reference_mut(&self) -> Self {
58        Type(TypeNode::ReferenceMut {
59            lifetime: None,
60            inner: Box::new(self.0.clone()),
61        })
62    }
63
64    pub fn dereference(&self) -> Self {
65        match &self.0 {
66            TypeNode::Reference { inner, .. } => Type((**inner).clone()),
67            TypeNode::ReferenceMut { inner, .. } => Type((**inner).clone()),
68            other => Type(TypeNode::Dereference(Box::new(other.clone()))),
69        }
70    }
71
72    pub fn get_function(&self, name: &str, sig: Signature) -> Function {
73        Function {
74            parent: Some(self.clone()),
75            name: name.to_owned(),
76            sig,
77        }
78    }
79
80    pub fn data(&self) -> Data<Self> {
81        match &self.0 {
82            TypeNode::DataStructure { data, .. } => data.clone().map(|field| field.element),
83            TypeNode::Reference { lifetime, inner } => {
84                Type((**inner).clone()).data().map(|field| {
85                    Type(TypeNode::Reference {
86                        lifetime: lifetime.clone(),
87                        inner: Box::new(field.element.0),
88                    })
89                })
90            }
91            TypeNode::ReferenceMut { lifetime, inner } => {
92                Type((**inner).clone()).data().map(|field| {
93                    Type(TypeNode::ReferenceMut {
94                        lifetime: lifetime.clone(),
95                        inner: Box::new(field.element.0),
96                    })
97                })
98            }
99            _ => panic!("Type::data"),
100        }
101    }
102
103    /// Returns a Type from a Tuple
104    pub fn get_tuple_type(&self, index: usize) -> Self {
105        match &self.0 {
106            TypeNode::Tuple(types) => types[index].clone(),
107            _ => panic!("Type::get_tuple_type: Not a Tuple"),
108        }
109    }
110
111    pub(crate) fn syn_to_type(ty: syn::Type) -> Self {
112        match ty {
113            syn::Type::Path(TypePath {
114                // FIXME: add qself to Path
115                qself: None,
116                path,
117            }) => Type(TypeNode::Path(Path::syn_to_path(path))),
118
119            syn::Type::Reference(reference) => {
120                let inner = Box::new(Type::syn_to_type(*reference.elem).0);
121                let lifetime = reference.lifetime.map(|lifetime| Lifetime {
122                    ident: Ident::from(lifetime.ident),
123                });
124                if reference.mutability.is_some() {
125                    Type(TypeNode::ReferenceMut { lifetime, inner })
126                } else {
127                    Type(TypeNode::Reference { lifetime, inner })
128                }
129            }
130            // FIXME: TraitObject
131            syn::Type::TraitObject(type_trait_object) => Type(TypeNode::TraitObject(
132                generics::syn_to_type_param_bounds(type_trait_object.bounds),
133            )),
134
135            syn::Type::Tuple(type_tuple) => {
136                if type_tuple.elems.is_empty() {
137                    Type::unit()
138                } else if type_tuple.elems.len() == 1 && !type_tuple.elems.trailing_punct() {
139                    // It is not a tuple. The parentheses were just used to
140                    // disambiguate the type.
141                    Self::syn_to_type(type_tuple.elems.into_iter().next().unwrap())
142                } else {
143                    Type(TypeNode::Tuple(
144                        type_tuple
145                            .elems
146                            .into_iter()
147                            .map(Self::syn_to_type)
148                            .collect(),
149                    ))
150                }
151            }
152            _ => unimplemented!("Type::syn_to_type"),
153        }
154    }
155
156    pub(crate) fn name_and_generics(
157        &self,
158    ) -> (TokenStream, Vec<GenericParam>, Vec<GenericConstraint>) {
159        self.0.name_and_generics()
160    }
161}
162
163impl TypeNode {
164    pub(crate) fn get_name(&self) -> String {
165        match self {
166            // FIXME: Add more TypeNode branches
167            TypeNode::Tuple(types) => {
168                let types = types.iter().map(Print::ref_cast);
169                quote!((#(#types),*)).to_string()
170            }
171            TypeNode::PrimitiveStr => String::from("str"),
172            TypeNode::DataStructure { name, .. } => name.to_string(),
173            TypeNode::Reference { inner, .. } => (**inner).get_name(),
174            TypeNode::ReferenceMut { inner, .. } => (**inner).get_name(),
175            TypeNode::Path(path) => {
176                let mut tokens = TokenStream::new();
177                Print::ref_cast(path).to_tokens(&mut tokens);
178                tokens.to_string()
179            }
180            _ => panic!("Type::get_name"),
181        }
182    }
183
184    pub(crate) fn name_and_generics(
185        &self,
186    ) -> (TokenStream, Vec<GenericParam>, Vec<GenericConstraint>) {
187        use super::TypeNode::*;
188        match self {
189            Infer => panic!("Type::name_and_generics: Infer"),
190
191            Tuple(types) => {
192                let types = types.iter().map(Print::ref_cast);
193                (quote!((#(#types),*)), Vec::new(), Vec::new())
194            }
195
196            PrimitiveStr => (quote!(str), Vec::new(), Vec::new()),
197
198            Reference { lifetime, inner } => {
199                let lifetime = lifetime.as_ref().map(Print::ref_cast);
200                let (name, params, constraints) = inner.name_and_generics();
201                (quote!(& #lifetime #name), params, constraints)
202            }
203
204            ReferenceMut { lifetime, inner } => {
205                let lifetime = lifetime.as_ref().map(Print::ref_cast);
206                let (name, params, constraints) = inner.name_and_generics();
207                (quote!(&mut #lifetime #name), params, constraints)
208            }
209
210            Dereference(_dereference) => panic!("Type::name_and_generics: Dereference"),
211
212            TraitObject(type_param_bound) => {
213                if type_param_bound.len() != 1 {
214                    panic!("Type::name_and_generics: TraitObject has more than one bound");
215                }
216                let type_param_bound = Print::ref_cast(&type_param_bound[0]);
217                (quote!(dyn #type_param_bound), Vec::new(), Vec::new())
218            }
219
220            DataStructure {
221                name,
222                generics:
223                    Generics {
224                        params,
225                        constraints,
226                    },
227                ..
228            } => (quote!(#name), params.clone(), constraints.clone()),
229
230            Path(path) => {
231                // FIXME: separate generics from path if possible
232                let path = Print::ref_cast(path);
233                (quote!(path), Vec::new(), Vec::new())
234            }
235        }
236    }
237}