1 | //! Attribute parsing for variants. |
2 | |
3 | use syn::{spanned::Spanned, Attribute, Fields, Meta, Result, Variant}; |
4 | |
5 | use crate::{util::MetaListExt, Default, DeriveWhere, Error, Incomparable, Skip, DERIVE_WHERE}; |
6 | |
7 | /// Attributes on variant. |
8 | #[derive (Default)] |
9 | pub struct VariantAttr { |
10 | /// Default variant. |
11 | pub default: Default, |
12 | /// [`Trait`](crate::Trait)s to skip all fields for. |
13 | pub skip_inner: Skip, |
14 | /// Comparing variant will yield `false` for [`PartialEq`] and [`None`] for |
15 | /// [`PartialOrd`]. |
16 | pub incomparable: Incomparable, |
17 | } |
18 | |
19 | impl VariantAttr { |
20 | /// Create [`VariantAttr`] from [`Attribute`]s. |
21 | pub fn from_attrs( |
22 | attrs: &[Attribute], |
23 | derive_wheres: &[DeriveWhere], |
24 | variant: &Variant, |
25 | ) -> Result<Self> { |
26 | let mut self_ = VariantAttr::default(); |
27 | |
28 | for attr in attrs { |
29 | if attr.path().is_ident(DERIVE_WHERE) { |
30 | self_.add_meta(&attr.meta, derive_wheres, variant)? |
31 | } |
32 | } |
33 | |
34 | Ok(self_) |
35 | } |
36 | |
37 | /// Add [`Meta`] to [`VariantAttr`]. |
38 | fn add_meta( |
39 | &mut self, |
40 | meta: &Meta, |
41 | derive_wheres: &[DeriveWhere], |
42 | variant: &Variant, |
43 | ) -> Result<()> { |
44 | debug_assert!(meta.path().is_ident(DERIVE_WHERE)); |
45 | |
46 | if let Meta::List(list) = meta { |
47 | let nested = list.parse_non_empty_nested_metas()?; |
48 | |
49 | if nested.is_empty() { |
50 | return Err(Error::empty(list.span())); |
51 | } |
52 | |
53 | for meta in &nested { |
54 | if meta.path().is_ident(Skip::SKIP_INNER) { |
55 | // Don't allow `skip_inner` on empty variants. |
56 | match &variant.fields { |
57 | Fields::Named(fields) if fields.named.is_empty() => { |
58 | return Err(Error::option_skip_empty(variant.span())) |
59 | } |
60 | Fields::Unnamed(fields) if fields.unnamed.is_empty() => { |
61 | return Err(Error::option_skip_empty(variant.span())) |
62 | } |
63 | Fields::Unit => return Err(Error::option_skip_empty(variant.span())), |
64 | _ => self.skip_inner.add_attribute(derive_wheres, None, meta)?, |
65 | } |
66 | } else if meta.path().is_ident(Default::DEFAULT) { |
67 | self.default.add_attribute(meta, derive_wheres)?; |
68 | } else if meta.path().is_ident(Incomparable::INCOMPARABLE) { |
69 | self.incomparable.add_attribute(meta, derive_wheres)?; |
70 | } else { |
71 | return Err(Error::option(meta.path().span())); |
72 | } |
73 | } |
74 | |
75 | Ok(()) |
76 | } else { |
77 | Err(Error::option_syntax(meta.span())) |
78 | } |
79 | } |
80 | } |
81 | |