1//! Attribute parsing for variants.
2
3use syn::{spanned::Spanned, Attribute, Fields, Meta, Result, Variant};
4
5use crate::{util::MetaListExt, Default, DeriveWhere, Error, Incomparable, Skip, DERIVE_WHERE};
6
7/// Attributes on variant.
8#[derive(Default)]
9pub 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
19impl 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