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. |
21 | fn as_type_param(&self) -> Option<&Self::TypeParam> { |
22 | None |
23 | } |
24 | |
25 | /// If this GenericParam is a lifetime, get the underlying value. |
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. |
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 | |
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 | |
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 | |
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 | |
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> { |
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> { |
93 | fn from_generic_param(param: &syn::GenericParam) -> Result<Self> { |
94 | Ok(match *param { |
95 | syn::GenericParam::Type(ref ty: &TypeParam) => { |
96 | GenericParam::Type(FromTypeParam::from_type_param(ty)?) |
97 | } |
98 | syn::GenericParam::Lifetime(ref val: &LifetimeParam) => GenericParam::Lifetime(val.clone()), |
99 | syn::GenericParam::Const(ref val: &ConstParam) => 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 | |
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 | |
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 | |
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> { |
143 | pub fn type_params(&self) -> TypeParams<'_, P> { |
144 | TypeParams(self.params.iter()) |
145 | } |
146 | } |
147 | |
148 | impl<P: FromGenericParam> FromGenerics for Generics<P> { |
149 | fn from_generics(generics: &syn::Generics) -> Result<Self> { |
150 | Ok(Generics { |
151 | params: genericsimpl Iterator |
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: 'a>(Iter<'a, P>); |
162 | |
163 | impl<'a, P: GenericParamExt> Iterator for TypeParams<'a, P> { |
164 | type Item = &'a <P as GenericParamExt>::TypeParam; |
165 | |
166 | fn next(&mut self) -> Option<Self::Item> { |
167 | let next: Option<&P> = self.0.next(); |
168 | match next { |
169 | None => None, |
170 | Some(v: &P) => match v.as_type_param() { |
171 | Some(val: & ::TypeParam ) => 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] |
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 |