1 //! Types for working with generics
2 
3 use std::iter::Iterator;
4 use std::slice::Iter;
5 
6 use crate::{FromGenericParam, FromGenerics, FromTypeParam, Result};
7 
8 /// Extension trait for `GenericParam` to support getting values by variant.
9 ///
10 /// # Usage
11 /// `darling::ast::Generics` needs a way to test its params array in order to iterate over type params.
12 /// Rather than require callers to use `darling::ast::GenericParam` in all cases, this trait makes that
13 /// polymorphic.
14 pub trait GenericParamExt {
15     /// The type this GenericParam uses to represent type params and their bounds
16     type TypeParam;
17     type LifetimeParam;
18     type ConstParam;
19 
20     /// If this GenericParam is a type param, get the underlying value.
as_type_param(&self) -> Option<&Self::TypeParam>21     fn as_type_param(&self) -> Option<&Self::TypeParam> {
22         None
23     }
24 
25     /// If this GenericParam is a lifetime, get the underlying value.
as_lifetime_param(&self) -> Option<&Self::LifetimeParam>26     fn as_lifetime_param(&self) -> Option<&Self::LifetimeParam> {
27         None
28     }
29 
30     /// If this GenericParam is a const param, get the underlying value.
as_const_param(&self) -> Option<&Self::ConstParam>31     fn as_const_param(&self) -> Option<&Self::ConstParam> {
32         None
33     }
34 }
35 
36 impl GenericParamExt for syn::GenericParam {
37     type TypeParam = syn::TypeParam;
38     type LifetimeParam = syn::LifetimeParam;
39     type ConstParam = syn::ConstParam;
40 
as_type_param(&self) -> Option<&Self::TypeParam>41     fn as_type_param(&self) -> Option<&Self::TypeParam> {
42         if let syn::GenericParam::Type(ref val) = *self {
43             Some(val)
44         } else {
45             None
46         }
47     }
48 
as_lifetime_param(&self) -> Option<&Self::LifetimeParam>49     fn as_lifetime_param(&self) -> Option<&Self::LifetimeParam> {
50         if let syn::GenericParam::Lifetime(ref val) = *self {
51             Some(val)
52         } else {
53             None
54         }
55     }
56 
as_const_param(&self) -> Option<&Self::ConstParam>57     fn as_const_param(&self) -> Option<&Self::ConstParam> {
58         if let syn::GenericParam::Const(ref val) = *self {
59             Some(val)
60         } else {
61             None
62         }
63     }
64 }
65 
66 impl GenericParamExt for syn::TypeParam {
67     type TypeParam = syn::TypeParam;
68     type LifetimeParam = ();
69     type ConstParam = ();
70 
as_type_param(&self) -> Option<&Self::TypeParam>71     fn as_type_param(&self) -> Option<&Self::TypeParam> {
72         Some(self)
73     }
74 }
75 
76 /// A mirror of `syn::GenericParam` which is generic over all its contents.
77 #[derive(Debug, Clone, PartialEq, Eq)]
78 pub enum GenericParam<T = syn::TypeParam, L = syn::LifetimeParam, C = syn::ConstParam> {
79     Type(T),
80     Lifetime(L),
81     Const(C),
82 }
83 
84 impl<T: FromTypeParam> FromTypeParam for GenericParam<T> {
from_type_param(type_param: &syn::TypeParam) -> Result<Self>85     fn from_type_param(type_param: &syn::TypeParam) -> Result<Self> {
86         Ok(GenericParam::Type(FromTypeParam::from_type_param(
87             type_param,
88         )?))
89     }
90 }
91 
92 impl<T: FromTypeParam> FromGenericParam for GenericParam<T> {
from_generic_param(param: &syn::GenericParam) -> Result<Self>93     fn from_generic_param(param: &syn::GenericParam) -> Result<Self> {
94         Ok(match *param {
95             syn::GenericParam::Type(ref ty) => {
96                 GenericParam::Type(FromTypeParam::from_type_param(ty)?)
97             }
98             syn::GenericParam::Lifetime(ref val) => GenericParam::Lifetime(val.clone()),
99             syn::GenericParam::Const(ref val) => GenericParam::Const(val.clone()),
100         })
101     }
102 }
103 
104 impl<T, L, C> GenericParamExt for GenericParam<T, L, C> {
105     type TypeParam = T;
106     type LifetimeParam = L;
107     type ConstParam = C;
108 
as_type_param(&self) -> Option<&T>109     fn as_type_param(&self) -> Option<&T> {
110         if let GenericParam::Type(ref val) = *self {
111             Some(val)
112         } else {
113             None
114         }
115     }
116 
as_lifetime_param(&self) -> Option<&L>117     fn as_lifetime_param(&self) -> Option<&L> {
118         if let GenericParam::Lifetime(ref val) = *self {
119             Some(val)
120         } else {
121             None
122         }
123     }
124 
as_const_param(&self) -> Option<&C>125     fn as_const_param(&self) -> Option<&C> {
126         if let GenericParam::Const(ref val) = *self {
127             Some(val)
128         } else {
129             None
130         }
131     }
132 }
133 
134 /// A mirror of the `syn::Generics` type which can contain arbitrary representations
135 /// of params and where clauses.
136 #[derive(Debug, Clone, PartialEq, Eq)]
137 pub struct Generics<P, W = syn::WhereClause> {
138     pub params: Vec<P>,
139     pub where_clause: Option<W>,
140 }
141 
142 impl<P, W> Generics<P, W> {
type_params(&self) -> TypeParams<'_, P>143     pub fn type_params(&self) -> TypeParams<'_, P> {
144         TypeParams(self.params.iter())
145     }
146 }
147 
148 impl<P: FromGenericParam> FromGenerics for Generics<P> {
from_generics(generics: &syn::Generics) -> Result<Self>149     fn from_generics(generics: &syn::Generics) -> Result<Self> {
150         Ok(Generics {
151             params: generics
152                 .params
153                 .iter()
154                 .map(FromGenericParam::from_generic_param)
155                 .collect::<Result<Vec<P>>>()?,
156             where_clause: generics.where_clause.clone(),
157         })
158     }
159 }
160 
161 pub struct TypeParams<'a, P>(Iter<'a, P>);
162 
163 impl<'a, P: GenericParamExt> Iterator for TypeParams<'a, P> {
164     type Item = &'a <P as GenericParamExt>::TypeParam;
165 
next(&mut self) -> Option<Self::Item>166     fn next(&mut self) -> Option<Self::Item> {
167         let next = self.0.next();
168         match next {
169             None => None,
170             Some(v) => match v.as_type_param() {
171                 Some(val) => Some(val),
172                 None => self.next(),
173             },
174         }
175     }
176 }
177 
178 #[cfg(test)]
179 mod tests {
180     use syn::parse_quote;
181 
182     use super::{GenericParam, Generics};
183     use crate::FromGenerics;
184 
185     #[test]
generics()186     fn generics() {
187         let g: syn::Generics = parse_quote!(<T>);
188         let deified: Generics<GenericParam<syn::Ident>> = FromGenerics::from_generics(&g).unwrap();
189         assert!(deified.params.len() == 1);
190         assert!(deified.where_clause.is_none());
191     }
192 }
193