Skip to content

Commit 0c78d9d

Browse files
committed
Code improvements around enum parsing
1 parent b3b9f06 commit 0c78d9d

File tree

4 files changed

+52
-66
lines changed

4 files changed

+52
-66
lines changed

src/attr/default.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Attribute parsing for the `default` option.
22
3+
use proc_macro2::Span;
34
use syn::{spanned::Spanned, Meta, Result};
45

56
use crate::{DeriveWhere, Error, Trait};
@@ -8,23 +9,18 @@ use crate::{DeriveWhere, Error, Trait};
89
/// [`Default`](std::default::Default).
910
#[derive(Clone, Copy, Default)]
1011
#[cfg_attr(test, derive(Debug))]
11-
pub struct Default(pub bool);
12+
pub struct Default(pub Option<Span>);
1213

1314
impl Default {
1415
/// Token used for the `default` option.
1516
pub const DEFAULT: &'static str = "default";
1617

1718
/// Adds a [`Meta`] to this [`Default`](self).
18-
pub fn add_attribute(
19-
&mut self,
20-
meta: &Meta,
21-
derive_wheres: &[DeriveWhere],
22-
accumulated_defaults: &mut Default,
23-
) -> Result<()> {
19+
pub fn add_attribute(&mut self, meta: &Meta, derive_wheres: &[DeriveWhere]) -> Result<()> {
2420
debug_assert!(meta.path().is_ident(Self::DEFAULT));
2521

2622
if let Meta::Path(path) = meta {
27-
if self.0 {
23+
if self.0.is_some() {
2824
Err(Error::option_duplicate(path.span(), Self::DEFAULT))
2925
} else {
3026
let mut impl_default = false;
@@ -37,13 +33,8 @@ impl Default {
3733
}
3834

3935
if impl_default {
40-
if accumulated_defaults.0 {
41-
Err(Error::default_duplicate(path.span()))
42-
} else {
43-
accumulated_defaults.0 = true;
44-
self.0 = true;
45-
Ok(())
46-
}
36+
self.0 = Some(path.span());
37+
Ok(())
4738
} else {
4839
Err(Error::default(path.span()))
4940
}

src/attr/variant.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,14 @@ impl VariantAttr {
1818
pub fn from_attrs(
1919
attrs: &[Attribute],
2020
derive_wheres: &[DeriveWhere],
21-
accumulated_defaults: &mut Default,
2221
variant: &Variant,
2322
) -> Result<Self> {
2423
let mut self_ = VariantAttr::default();
2524

2625
for attr in attrs {
2726
if attr.path.is_ident(DERIVE_WHERE) {
2827
match attr.parse_meta() {
29-
Ok(meta) => {
30-
self_.add_meta(&meta, derive_wheres, accumulated_defaults, variant)?
31-
}
28+
Ok(meta) => self_.add_meta(&meta, derive_wheres, variant)?,
3229
Err(error) => return Err(Error::attribute_syntax(attr.span(), error)),
3330
}
3431
}
@@ -42,7 +39,6 @@ impl VariantAttr {
4239
&mut self,
4340
meta: &Meta,
4441
derive_wheres: &[DeriveWhere],
45-
accumulated_defaults: &mut Default,
4642
variant: &Variant,
4743
) -> Result<()> {
4844
debug_assert!(meta.path().is_ident(DERIVE_WHERE));
@@ -70,11 +66,7 @@ impl VariantAttr {
7066
_ => self.skip_inner.add_attribute(derive_wheres, None, meta)?,
7167
}
7268
} else if meta.path().is_ident(Default::DEFAULT) {
73-
self.default.add_attribute(
74-
meta,
75-
derive_wheres,
76-
accumulated_defaults,
77-
)?;
69+
self.default.add_attribute(meta, derive_wheres)?;
7870
} else {
7971
return Err(Error::option(meta.path().span()));
8072
}

src/data.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ mod field;
44
mod fields;
55

66
use proc_macro2::Span;
7-
use syn::{FieldsNamed, Ident, Pat, PatPath, Path, Result};
7+
use syn::{FieldsNamed, Ident, Pat, PatPath, Path, Result, Variant};
88

99
pub use self::{
1010
field::{Field, Member},
1111
fields::Fields,
1212
};
13-
use crate::{util, Default, DeriveWhere, Either, Error, Skip, Trait};
13+
use crate::{util, Default, DeriveWhere, Either, Error, Skip, Trait, VariantAttr};
1414

1515
/// Holds all relevant data of a struct, union or variant.
1616
#[cfg_attr(test, derive(Debug))]
@@ -141,20 +141,23 @@ impl<'a> Data<'a> {
141141
pub fn from_variant(
142142
item_ident: &'a Ident,
143143
derive_wheres: &[DeriveWhere],
144-
skip_inner: Skip,
145-
default: Default,
146-
variant_ident: &'a Ident,
147-
fields: &'a syn::Fields,
144+
variant: &'a Variant,
148145
) -> Result<Self> {
149-
let path = util::path_from_idents(&[item_ident, variant_ident]);
146+
// Parse `Attribute`s on variant.
147+
let VariantAttr {
148+
default,
149+
skip_inner,
150+
} = VariantAttr::from_attrs(&variant.attrs, derive_wheres, variant)?;
150151

151-
match fields {
152+
let path = util::path_from_idents(&[item_ident, &variant.ident]);
153+
154+
match &variant.fields {
152155
syn::Fields::Named(fields) => {
153156
let fields = Fields::from_named(derive_wheres, &skip_inner, path.clone(), fields)?;
154157

155158
Ok(Self {
156159
skip_inner,
157-
ident: variant_ident,
160+
ident: &variant.ident,
158161
path,
159162
type_: DataType::Variant {
160163
default,
@@ -168,7 +171,7 @@ impl<'a> Data<'a> {
168171

169172
Ok(Self {
170173
skip_inner,
171-
ident: variant_ident,
174+
ident: &variant.ident,
172175
path,
173176
type_: DataType::Variant {
174177
default,
@@ -185,7 +188,7 @@ impl<'a> Data<'a> {
185188

186189
Ok(Self {
187190
skip_inner,
188-
ident: variant_ident,
191+
ident: &variant.ident,
189192
path,
190193
type_: DataType::Variant {
191194
default,
@@ -239,11 +242,20 @@ impl<'a> Data<'a> {
239242
/// not a variant, always returns `true`.
240243
pub fn is_default(&self) -> bool {
241244
match self.type_ {
242-
DataType::Variant { default, .. } => default.0,
245+
DataType::Variant { default, .. } => default.0.is_some(),
243246
_ => true,
244247
}
245248
}
246249

250+
/// Returns [`Some`] if this variant has a [`struct@Default`]. If
251+
/// not a variant, always returns [`None`].
252+
pub fn default_span(&self) -> Option<Span> {
253+
match &self.type_ {
254+
DataType::Variant { default, .. } => default.0,
255+
_ => None,
256+
}
257+
}
258+
247259
/// Returns `true` if this [`Data`] has no [`Fields`].
248260
pub fn is_empty(&self, trait_: &Trait) -> bool {
249261
self.iter_fields(trait_).count() == 0

src/input.rs

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use syn::{DeriveInput, GenericParam, Generics, Result};
55

66
#[cfg(feature = "zeroize")]
77
use crate::DeriveTrait;
8-
use crate::{Data, Default, DeriveWhere, Either, Error, Item, ItemAttr, Trait, VariantAttr};
8+
use crate::{Data, DeriveWhere, Either, Error, Item, ItemAttr, Trait};
99

1010
/// Parsed input.
1111
pub struct Input<'a> {
@@ -42,32 +42,10 @@ impl<'a> Input<'a> {
4242
.map(Item::Item)?
4343
}
4444
syn::Data::Enum(data) => {
45-
let mut accumulated_defaults = Default::default();
46-
4745
let variants = data
4846
.variants
4947
.iter()
50-
.map(|variant| {
51-
// Parse `Attribute`s on variant.
52-
let VariantAttr {
53-
default,
54-
skip_inner,
55-
} = VariantAttr::from_attrs(
56-
&variant.attrs,
57-
&derive_wheres,
58-
&mut accumulated_defaults,
59-
variant,
60-
)?;
61-
62-
Data::from_variant(
63-
ident,
64-
&derive_wheres,
65-
skip_inner,
66-
default,
67-
&variant.ident,
68-
&variant.fields,
69-
)
70-
})
48+
.map(|variant| Data::from_variant(ident, &derive_wheres, variant))
7149
.collect::<Result<Vec<Data>>>()?;
7250

7351
// Empty enums aren't allowed.
@@ -78,9 +56,23 @@ impl<'a> Input<'a> {
7856
return Err(Error::item_empty(span));
7957
}
8058

59+
// Find if a default option is specified on a variant.
60+
let mut found_default = false;
61+
62+
// While searching for a default option, check for duplicates.
63+
for variant in &variants {
64+
if let Some(span) = variant.default_span() {
65+
if found_default {
66+
return Err(Error::default_duplicate(span));
67+
} else {
68+
found_default = true;
69+
}
70+
}
71+
}
72+
8173
// Make sure a variant has the `option` attribute if `Default` is being
8274
// implemented.
83-
if !accumulated_defaults.0
75+
if !found_default
8476
&& derive_wheres
8577
.iter()
8678
.any(|derive_where| derive_where.trait_(&Trait::Default).is_some())
@@ -99,10 +91,9 @@ impl<'a> Input<'a> {
9991
// Don't allow no use-case compared to std `derive`.
10092
let mut found_use_case = false;
10193
// Any generics used.
102-
found_use_case |= generics
103-
.params
104-
.iter()
105-
.any(|generic_param| match generic_param {
94+
found_use_case |= generics.params.iter().any(|generic_param|
95+
// MSRV: `matches!` was added in 1.42.0.
96+
match generic_param {
10697
GenericParam::Type(_) => true,
10798
GenericParam::Lifetime(_) | GenericParam::Const(_) => false,
10899
});

0 commit comments

Comments
 (0)