1 | //! Types holding data of items. |
2 | |
3 | mod field; |
4 | mod fields; |
5 | |
6 | use proc_macro2::Span; |
7 | use syn::{Expr, FieldsNamed, Ident, Pat, PatPath, Path, Result, Variant}; |
8 | |
9 | pub use self::{ |
10 | field::{Field, Member}, |
11 | fields::Fields, |
12 | }; |
13 | use crate::{util, Default, DeriveWhere, Either, Error, Incomparable, Skip, Trait, VariantAttr}; |
14 | |
15 | /// Holds all relevant data of a struct, union or variant. |
16 | #[cfg_attr (test, derive(Debug))] |
17 | pub struct Data<'a> { |
18 | /// [`Skip`] attribute of this struct, union or variant. |
19 | skip_inner: Skip, |
20 | /// [`Incomparable`] attribute of this struct, union or variant. |
21 | pub incomparable: Incomparable, |
22 | /// [`struct@Ident`] of this struct, union or variant, used for implementing |
23 | /// [`Debug`](std::fmt::Debug). |
24 | pub ident: &'a Ident, |
25 | /// [`Path`] of this struct, union or variant, used to construct new |
26 | /// instances of that item, for example when implementing [`Clone`]. |
27 | pub path: Path, |
28 | /// [Type](DataType) of this struct, union or variant. |
29 | pub type_: DataType<'a>, |
30 | /// Discriminant of this variant. |
31 | pub discriminant: Option<&'a Expr>, |
32 | } |
33 | |
34 | /// Type of this data. |
35 | #[cfg_attr (test, derive(Debug))] |
36 | pub enum DataType<'a> { |
37 | /// Struct. |
38 | Struct(Fields<'a>), |
39 | /// Tuple. |
40 | Tuple(Fields<'a>), |
41 | /// Union. |
42 | Union(Fields<'a>), |
43 | /// Variant. |
44 | Variant { |
45 | /// [`struct@Default`] attribute of this variant. |
46 | default: Default, |
47 | /// [Type](VariantType) of this variant. |
48 | type_: VariantType<'a>, |
49 | }, |
50 | /// Unit. |
51 | Unit(Pat), |
52 | } |
53 | |
54 | /// Type of [`Data`]. |
55 | #[cfg_attr (test, derive(Debug))] |
56 | pub enum VariantType<'a> { |
57 | /// Struct variant. |
58 | Struct(Fields<'a>), |
59 | /// Tuple variant. |
60 | Tuple(Fields<'a>), |
61 | /// Unit variant. |
62 | Unit(Pat), |
63 | } |
64 | |
65 | /// Type to enable simplified matching. |
66 | pub enum SimpleType<'a> { |
67 | /// Struct, struct variant. |
68 | Struct(&'a Fields<'a>), |
69 | /// Tuple struct or tuple variant. |
70 | Tuple(&'a Fields<'a>), |
71 | /// Union. |
72 | Union(&'a Fields<'a>), |
73 | /// Unit variant. |
74 | Unit(&'a Pat), |
75 | } |
76 | |
77 | impl<'a> Data<'a> { |
78 | /// Create [`Data`]s from [`syn::Fields`] of a struct. |
79 | pub fn from_struct( |
80 | span: Span, |
81 | derive_wheres: &[DeriveWhere], |
82 | skip_inner: Skip, |
83 | incomparable: Incomparable, |
84 | ident: &'a Ident, |
85 | fields: &'a syn::Fields, |
86 | ) -> Result<Self> { |
87 | let path = util::path_from_idents(&[ident]); |
88 | |
89 | match fields { |
90 | syn::Fields::Named(fields) => { |
91 | if fields.named.is_empty() && incomparable.0.is_none() { |
92 | Err(Error::item_empty(span)) |
93 | } else { |
94 | let fields = |
95 | Fields::from_named(derive_wheres, &skip_inner, path.clone(), fields)?; |
96 | |
97 | Ok(Self { |
98 | skip_inner, |
99 | incomparable, |
100 | ident, |
101 | path, |
102 | type_: DataType::Struct(fields), |
103 | discriminant: None, |
104 | }) |
105 | } |
106 | } |
107 | syn::Fields::Unnamed(fields) => { |
108 | if fields.unnamed.is_empty() && incomparable.0.is_none() { |
109 | Err(Error::item_empty(span)) |
110 | } else { |
111 | let fields = |
112 | Fields::from_unnamed(derive_wheres, &skip_inner, path.clone(), fields)?; |
113 | |
114 | Ok(Self { |
115 | skip_inner, |
116 | incomparable, |
117 | ident, |
118 | path, |
119 | type_: DataType::Tuple(fields), |
120 | discriminant: None, |
121 | }) |
122 | } |
123 | } |
124 | syn::Fields::Unit if incomparable.0.is_some() => Ok(Self { |
125 | skip_inner, |
126 | incomparable, |
127 | ident, |
128 | path: path.clone(), |
129 | type_: DataType::Unit(Pat::Path(PatPath { |
130 | attrs: Vec::new(), |
131 | qself: None, |
132 | path, |
133 | })), |
134 | discriminant: None, |
135 | }), |
136 | syn::Fields::Unit => Err(Error::item_empty(span)), |
137 | } |
138 | } |
139 | |
140 | /// Create [`Data`]s from [`FieldsNamed`] of an union. |
141 | pub fn from_union( |
142 | span: Span, |
143 | derive_wheres: &[DeriveWhere], |
144 | skip_inner: Skip, |
145 | incomparable: Incomparable, |
146 | ident: &'a Ident, |
147 | fields: &'a FieldsNamed, |
148 | ) -> Result<Self> { |
149 | if fields.named.is_empty() && incomparable.0.is_none() { |
150 | Err(Error::item_empty(span)) |
151 | } else { |
152 | let path = util::path_from_idents(&[ident]); |
153 | let fields = Fields::from_named(derive_wheres, &skip_inner, path.clone(), fields)?; |
154 | |
155 | Ok(Self { |
156 | skip_inner, |
157 | incomparable, |
158 | ident, |
159 | path, |
160 | type_: DataType::Union(fields), |
161 | discriminant: None, |
162 | }) |
163 | } |
164 | } |
165 | |
166 | /// Create [`Data`]s from [`syn::Fields`] of a variant. |
167 | pub fn from_variant( |
168 | item_ident: &'a Ident, |
169 | derive_wheres: &[DeriveWhere], |
170 | variant: &'a Variant, |
171 | ) -> Result<Self> { |
172 | // Parse `Attribute`s on variant. |
173 | let VariantAttr { |
174 | default, |
175 | skip_inner, |
176 | incomparable, |
177 | } = VariantAttr::from_attrs(&variant.attrs, derive_wheres, variant)?; |
178 | |
179 | let path = util::path_from_idents(&[item_ident, &variant.ident]); |
180 | |
181 | match &variant.fields { |
182 | syn::Fields::Named(fields) => { |
183 | let fields = Fields::from_named(derive_wheres, &skip_inner, path.clone(), fields)?; |
184 | |
185 | Ok(Self { |
186 | skip_inner, |
187 | incomparable, |
188 | ident: &variant.ident, |
189 | path, |
190 | type_: DataType::Variant { |
191 | default, |
192 | type_: VariantType::Struct(fields), |
193 | }, |
194 | discriminant: variant.discriminant.as_ref().map(|(_, expr)| expr), |
195 | }) |
196 | } |
197 | syn::Fields::Unnamed(fields) => { |
198 | let fields = |
199 | Fields::from_unnamed(derive_wheres, &skip_inner, path.clone(), fields)?; |
200 | |
201 | Ok(Self { |
202 | skip_inner, |
203 | incomparable, |
204 | ident: &variant.ident, |
205 | path, |
206 | type_: DataType::Variant { |
207 | default, |
208 | type_: VariantType::Tuple(fields), |
209 | }, |
210 | discriminant: variant.discriminant.as_ref().map(|(_, expr)| expr), |
211 | }) |
212 | } |
213 | syn::Fields::Unit => { |
214 | let pattern = Pat::Path(PatPath { |
215 | attrs: Vec::new(), |
216 | qself: None, |
217 | path: path.clone(), |
218 | }); |
219 | |
220 | Ok(Self { |
221 | skip_inner, |
222 | incomparable, |
223 | ident: &variant.ident, |
224 | path, |
225 | type_: DataType::Variant { |
226 | default, |
227 | type_: VariantType::Unit(pattern), |
228 | }, |
229 | discriminant: variant.discriminant.as_ref().map(|(_, expr)| expr), |
230 | }) |
231 | } |
232 | } |
233 | } |
234 | |
235 | /// Returns the [`Fields`] of this [`Data`]. If [`Data`] is a unit variant |
236 | /// or struct returns [`Pat`] instead. |
237 | pub fn fields(&self) -> Either<&Fields, &Pat> { |
238 | match &self.type_ { |
239 | DataType::Struct(fields) |
240 | | DataType::Tuple(fields) |
241 | | DataType::Union(fields) |
242 | | DataType::Variant { |
243 | type_: VariantType::Struct(fields), |
244 | .. |
245 | } |
246 | | DataType::Variant { |
247 | type_: VariantType::Tuple(fields), |
248 | .. |
249 | } => Either::Left(fields), |
250 | DataType::Unit(pattern) |
251 | | DataType::Variant { |
252 | type_: VariantType::Unit(pattern), |
253 | .. |
254 | } => Either::Right(pattern), |
255 | } |
256 | } |
257 | |
258 | /// Returns the destructuring `self` pattern of this [`Data`]. |
259 | pub fn self_pattern(&self) -> &Pat { |
260 | match self.fields() { |
261 | Either::Left(fields) => &fields.self_pattern, |
262 | Either::Right(pattern) => pattern, |
263 | } |
264 | } |
265 | |
266 | /// Returns `true` if this variant is marked as the [`struct@Default`]. If |
267 | /// not a variant, always returns `true`. |
268 | pub fn is_default(&self) -> bool { |
269 | match self.type_ { |
270 | DataType::Variant { default, .. } => default.0.is_some(), |
271 | _ => true, |
272 | } |
273 | } |
274 | |
275 | /// Returns `true` if this item or variant is marked as [`Incomparable`]. |
276 | pub fn is_incomparable(&self) -> bool { |
277 | self.incomparable.0.is_some() |
278 | } |
279 | |
280 | /// Returns [`Some`] if this variant has a [`struct@Default`]. If |
281 | /// not a variant, always returns [`None`]. |
282 | pub fn default_span(&self) -> Option<Span> { |
283 | match &self.type_ { |
284 | DataType::Variant { default, .. } => default.0, |
285 | _ => None, |
286 | } |
287 | } |
288 | |
289 | /// Returns `true` if this [`Data`] has no [`Fields`]. |
290 | pub fn is_empty(&self, trait_: Trait) -> bool { |
291 | self.iter_fields(trait_).count() == 0 |
292 | } |
293 | |
294 | /// Returns `true` if a field is skipped with that [`Trait`]. |
295 | pub fn any_skip_trait(&self, trait_: Trait) -> bool { |
296 | self.skip_inner.trait_skipped(trait_) |
297 | || match self.fields() { |
298 | Either::Left(fields) => fields.any_skip_trait(trait_), |
299 | Either::Right(_) => false, |
300 | } |
301 | } |
302 | |
303 | /// Returns `true` if all fields are skipped with that [`Trait`]. |
304 | fn skip(&self, trait_: Trait) -> bool { |
305 | self.skip_inner.trait_skipped(trait_) |
306 | || match self.fields() { |
307 | Either::Left(fields) => fields.skip(trait_), |
308 | Either::Right(_) => false, |
309 | } |
310 | } |
311 | |
312 | /// Return a [`SimpleType`]. |
313 | pub fn simple_type(&self) -> SimpleType { |
314 | match &self.type_ { |
315 | DataType::Struct(fields) |
316 | | DataType::Variant { |
317 | type_: VariantType::Struct(fields), |
318 | .. |
319 | } => SimpleType::Struct(fields), |
320 | DataType::Tuple(fields) |
321 | | DataType::Variant { |
322 | type_: VariantType::Tuple(fields), |
323 | .. |
324 | } => SimpleType::Tuple(fields), |
325 | DataType::Unit(pattern) |
326 | | DataType::Variant { |
327 | type_: VariantType::Unit(pattern), |
328 | .. |
329 | } => SimpleType::Unit(pattern), |
330 | DataType::Union(fields) => SimpleType::Union(fields), |
331 | } |
332 | } |
333 | |
334 | /// Returns an [`Iterator`] over [`Field`]s. |
335 | pub fn iter_fields( |
336 | &self, |
337 | trait_: Trait, |
338 | ) -> impl '_ + Iterator<Item = &'_ Field> + DoubleEndedIterator { |
339 | if self.skip(trait_) { |
340 | [].iter() |
341 | } else { |
342 | match self.fields() { |
343 | Either::Left(fields) => fields.fields.iter(), |
344 | Either::Right(_) => [].iter(), |
345 | } |
346 | } |
347 | .filter(move |field| !field.skip(trait_)) |
348 | } |
349 | |
350 | /// Returns an [`Iterator`] over [`Member`]s. |
351 | pub fn iter_field_ident(&self, trait_: Trait) -> impl '_ + Iterator<Item = &'_ Member> { |
352 | self.iter_fields(trait_).map(|field| &field.member) |
353 | } |
354 | |
355 | /// Returns an [`Iterator`] over [`struct@Ident`]s used as temporary |
356 | /// variables for destructuring `self`. |
357 | pub fn iter_self_ident( |
358 | &self, |
359 | trait_: Trait, |
360 | ) -> impl Iterator<Item = &'_ Ident> + DoubleEndedIterator { |
361 | self.iter_fields(trait_).map(|field| &field.self_ident) |
362 | } |
363 | |
364 | /// Returns an [`Iterator`] over [`struct@Ident`]s used as temporary |
365 | /// variables for destructuring `other`. |
366 | pub fn iter_other_ident( |
367 | &self, |
368 | trait_: Trait, |
369 | ) -> impl Iterator<Item = &'_ Ident> + DoubleEndedIterator { |
370 | self.iter_fields(trait_).map(|field| &field.other_ident) |
371 | } |
372 | } |
373 | |