1//! Types for working with generics
2
3use std::iter::Iterator;
4use std::slice::Iter;
5
6use 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.
14pub 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
36impl 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
66impl 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)]
78pub enum GenericParam<T = syn::TypeParam, L = syn::LifetimeParam, C = syn::ConstParam> {
79 Type(T),
80 Lifetime(L),
81 Const(C),
82}
83
84impl<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
92impl<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
104impl<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)]
137pub struct Generics<P, W = syn::WhereClause> {
138 pub params: Vec<P>,
139 pub where_clause: Option<W>,
140}
141
142impl<P, W> Generics<P, W> {
143 pub fn type_params(&self) -> TypeParams<'_, P> {
144 TypeParams(self.params.iter())
145 }
146}
147
148impl<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
161pub struct TypeParams<'a, P: 'a>(Iter<'a, P>);
162
163impl<'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)]
179mod 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