Skip to content

Commit 44f41d7

Browse files
committed
Re-use #[serde(crate = "...")]
1 parent 649699d commit 44f41d7

File tree

16 files changed

+184
-90
lines changed

16 files changed

+184
-90
lines changed

src/attr/item.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,20 @@ impl ItemAttr {
7070
else {
7171
self_
7272
.derive_wheres
73-
.push(DeriveWhere::from_attr(span, data, attr)?);
73+
.push(DeriveWhere::from_attr(attrs, span, data, attr)?);
7474
}
7575
}
7676
_ => self_
7777
.derive_wheres
78-
.push(DeriveWhere::from_attr(span, data, attr)?),
78+
.push(DeriveWhere::from_attr(attrs, span, data, attr)?),
7979
}
8080
}
8181
// Anything list that isn't using `,` as separator, is because we expect
8282
// `A, B; C`.
8383
else {
8484
self_
8585
.derive_wheres
86-
.push(DeriveWhere::from_attr(span, data, attr)?)
86+
.push(DeriveWhere::from_attr(attrs, span, data, attr)?)
8787
}
8888
} else {
8989
return Err(Error::option_syntax(attr.meta.span()));
@@ -167,7 +167,7 @@ pub struct DeriveWhere {
167167

168168
impl DeriveWhere {
169169
/// Create [`DeriveWhere`] from [`Attribute`].
170-
fn from_attr(span: Span, data: &Data, attr: &Attribute) -> Result<Self> {
170+
fn from_attr(attrs: &[Attribute], span: Span, data: &Data, attr: &Attribute) -> Result<Self> {
171171
attr.parse_args_with(|input: ParseStream| {
172172
// Parse the attribute input, this should either be:
173173
// - Comma separated traits.
@@ -184,7 +184,7 @@ impl DeriveWhere {
184184
// Start with parsing a trait.
185185
// Not checking for duplicates here, we do that after merging `derive_where`s
186186
// with the same bounds.
187-
let (span, trait_) = DeriveTrait::from_stream(span, data, input)?;
187+
let (span, trait_) = DeriveTrait::from_stream(attrs, span, data, input)?;
188188
spans.push(span);
189189
traits.push(trait_);
190190

src/error.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl Error {
7474
}
7575

7676
/// Unsupported option in attribute.
77-
#[cfg(any(feature = "serde", feature = "zeroize"))]
77+
#[cfg(feature = "zeroize")]
7878
pub fn option_trait(span: Span, attribute: &str) -> syn::Error {
7979
syn::Error::new(span, format!("`{}` doesn't support this option", attribute))
8080
}
@@ -167,7 +167,8 @@ impl Error {
167167
)
168168
}
169169

170-
/// Invalid value for the `derive_where` or `Zeroize` `crate` option.
170+
/// Invalid value for the `derive_where`, `serde` or `Zeroize` `crate`
171+
/// option.
171172
pub fn path(span: Span, parse_error: syn::Error) -> syn::Error {
172173
syn::Error::new(span, format!("expected path, {}", parse_error))
173174
}

src/trait_.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ use syn::{
2929
parse::{Parse, ParseStream},
3030
punctuated::Punctuated,
3131
spanned::Spanned,
32-
DeriveInput, Ident, ImplGenerics, Meta, Path, Result, Token, TraitBound, TraitBoundModifier,
33-
TypeGenerics, TypeParamBound, WhereClause,
32+
Attribute, DeriveInput, Ident, ImplGenerics, Meta, Path, Result, Token, TraitBound,
33+
TraitBoundModifier, TypeGenerics, TypeParamBound, WhereClause,
3434
};
3535

3636
use crate::{util::MetaListExt, Data, DeriveWhere, Error, Item, SplitGenerics};
@@ -148,10 +148,11 @@ impl Trait {
148148
/// Re-direct to [`TraitImpl::parse_derive_trait()`].
149149
pub fn parse_derive_trait(
150150
&self,
151+
attrs: &[Attribute],
151152
span: Span,
152-
list: Punctuated<Meta, Token![,]>,
153+
list: Option<Punctuated<Meta, Token![,]>>,
153154
) -> Result<DeriveTrait> {
154-
trait_dispatch!(self, parse_derive_trait(span, list))
155+
trait_dispatch!(self, parse_derive_trait(attrs, span, list))
155156
}
156157

157158
/// Re-direct to [`TraitImpl::supports_union()`].
@@ -256,7 +257,12 @@ impl DeriveTrait {
256257
}
257258

258259
/// Create [`DeriveTrait`] from [`ParseStream`].
259-
pub fn from_stream(span: Span, data: &syn::Data, input: ParseStream) -> Result<(Span, Self)> {
260+
pub fn from_stream(
261+
attrs: &[Attribute],
262+
span: Span,
263+
data: &syn::Data,
264+
input: ParseStream,
265+
) -> Result<(Span, Self)> {
260266
match Meta::parse(input) {
261267
Ok(meta) => {
262268
let trait_ = Trait::from_path(meta.path())?;
@@ -269,12 +275,18 @@ impl DeriveTrait {
269275
}
270276

271277
match &meta {
272-
Meta::Path(path) => Ok((path.span(), trait_.default_derive_trait())),
278+
Meta::Path(path) => Ok((
279+
path.span(),
280+
trait_.parse_derive_trait(attrs, meta.span(), None)?,
281+
)),
273282
Meta::List(list) => {
274283
let nested = list.parse_non_empty_nested_metas()?;
275284

276285
// This will return an error if no options are supported.
277-
Ok((list.span(), trait_.parse_derive_trait(meta.span(), nested)?))
286+
Ok((
287+
list.span(),
288+
trait_.parse_derive_trait(attrs, meta.span(), Some(nested))?,
289+
))
278290
}
279291
Meta::NameValue(name_value) => Err(Error::option_syntax(name_value.span())),
280292
}
@@ -299,11 +311,19 @@ pub trait TraitImpl: Deref<Target = Trait> {
299311
Self: Sized;
300312

301313
/// Parse a `derive_where` trait with it's options.
302-
fn parse_derive_trait(span: Span, _list: Punctuated<Meta, Token![,]>) -> Result<DeriveTrait>
314+
fn parse_derive_trait(
315+
_attrs: &[Attribute],
316+
span: Span,
317+
list: Option<Punctuated<Meta, Token![,]>>,
318+
) -> Result<DeriveTrait>
303319
where
304320
Self: Sized,
305321
{
306-
Err(Error::options(span, Self::as_str()))
322+
if list.is_some() {
323+
Err(Error::options(span, Self::as_str()))
324+
} else {
325+
Ok(Self::default_derive_trait())
326+
}
307327
}
308328

309329
/// Returns `true` if [`Trait`] supports unions.

src/trait_/deserialize.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{borrow::Cow, ops::Deref};
55
use proc_macro2::{Span, TokenStream};
66
use quote::quote;
77
use syn::{
8-
punctuated::Punctuated, DeriveInput, Ident, ImplGenerics, Meta, Path, Result, TypeGenerics,
9-
WhereClause,
8+
punctuated::Punctuated, Attribute, DeriveInput, Ident, ImplGenerics, Meta, Path, Result,
9+
TypeGenerics, WhereClause,
1010
};
1111

1212
use super::serde;
@@ -34,12 +34,16 @@ impl TraitImpl for Deserialize {
3434
DeriveTrait::Deserialize(Self { crate_: None })
3535
}
3636

37-
fn parse_derive_trait(span: Span, list: Punctuated<Meta, syn::Token![,]>) -> Result<DeriveTrait>
37+
fn parse_derive_trait(
38+
attrs: &[Attribute],
39+
span: Span,
40+
list: Option<Punctuated<Meta, syn::Token![,]>>,
41+
) -> Result<DeriveTrait>
3842
where
3943
Self: Sized,
4044
{
4145
Ok(DeriveTrait::Deserialize(Self {
42-
crate_: serde::parse_derive_trait(Trait::Deserialize, span, list)?,
46+
crate_: serde::parse_derive_trait(Trait::Deserialize, attrs, span, list)?,
4347
}))
4448
}
4549

src/trait_/serde.rs

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,58 +4,68 @@
44
55
use proc_macro2::Span;
66
use syn::{
7-
punctuated::Punctuated, spanned::Spanned, Expr, ExprLit, ExprPath, Lit, Meta, Path, Token,
7+
punctuated::Punctuated, spanned::Spanned, Attribute, Expr, ExprLit, Lit, Meta, Path, Token,
88
};
99

10-
use crate::{util, Error, Result, Trait};
10+
use crate::{Error, Result, Trait};
1111

1212
/// Parses
1313
pub fn parse_derive_trait(
1414
trait_: Trait,
15-
_span: Span,
16-
list: Punctuated<Meta, Token![,]>,
15+
attrs: &[Attribute],
16+
span: Span,
17+
list: Option<Punctuated<Meta, Token![,]>>,
1718
) -> Result<Option<Path>> {
18-
// This is already checked in `DeriveTrait::from_stream`.
19-
debug_assert!(!list.is_empty());
19+
if list.is_some() {
20+
return Err(Error::options(span, trait_.as_str()));
21+
}
2022

2123
let mut crate_ = None;
2224

23-
for meta in list {
24-
match &meta {
25-
Meta::Path(path) => {
26-
return Err(Error::option_trait(path.span(), trait_.as_str()));
27-
}
28-
Meta::NameValue(name_value) => {
29-
if name_value.path.is_ident("crate") {
30-
// Check for duplicate `crate` option.
31-
if crate_.is_none() {
32-
let path = match &name_value.value {
33-
Expr::Lit(ExprLit {
34-
lit: Lit::Str(lit_str),
35-
..
36-
}) => match lit_str.parse::<Path>() {
37-
Ok(path) => path,
38-
Err(error) => return Err(Error::path(lit_str.span(), error)),
39-
},
40-
Expr::Path(ExprPath { path, .. }) => path.clone(),
41-
_ => return Err(Error::option_syntax(name_value.value.span())),
42-
};
43-
44-
if path == util::path_from_strs(&["serde"]) {
45-
return Err(Error::path_unnecessary(path.span(), "::serde"));
46-
}
25+
for attr in attrs {
26+
if !attr.path().is_ident("serde") {
27+
continue;
28+
}
29+
30+
if let Meta::List(list) = &attr.meta {
31+
if let Ok(nested) =
32+
list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
33+
{
34+
if nested.len() != 1 {
35+
continue;
36+
}
37+
38+
let meta = &nested[0];
4739

48-
crate_ = Some(path);
49-
} else {
50-
return Err(Error::option_duplicate(name_value.span(), "crate"));
40+
if !meta.path().is_ident("crate") {
41+
continue;
42+
}
43+
44+
match &meta {
45+
Meta::NameValue(name_value) => {
46+
// Check for duplicate `crate` option.
47+
if crate_.is_none() {
48+
let path = match &name_value.value {
49+
Expr::Lit(ExprLit {
50+
lit: Lit::Str(lit_str),
51+
..
52+
}) => match lit_str.parse::<Path>() {
53+
Ok(path) => path,
54+
Err(error) => return Err(Error::path(lit_str.span(), error)),
55+
},
56+
_ => return Err(Error::option_syntax(name_value.value.span())),
57+
};
58+
59+
crate_ = Some(path);
60+
} else {
61+
return Err(Error::option_duplicate(name_value.span(), "crate"));
62+
}
63+
}
64+
_ => {
65+
return Err(Error::option_syntax(meta.span()));
5166
}
52-
} else {
53-
return Err(Error::option_trait(name_value.path.span(), trait_.as_str()));
5467
}
5568
}
56-
_ => {
57-
return Err(Error::option_syntax(meta.span()));
58-
}
5969
}
6070
}
6171

src/trait_/serialize.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{borrow::Cow, ops::Deref};
55
use proc_macro2::{Span, TokenStream};
66
use quote::quote;
77
use syn::{
8-
punctuated::Punctuated, DeriveInput, Ident, ImplGenerics, Meta, Path, Result, TypeGenerics,
9-
WhereClause,
8+
punctuated::Punctuated, Attribute, DeriveInput, Ident, ImplGenerics, Meta, Path, Result,
9+
TypeGenerics, WhereClause,
1010
};
1111

1212
use super::serde;
@@ -34,12 +34,16 @@ impl TraitImpl for Serialize {
3434
DeriveTrait::Serialize(Self { crate_: None })
3535
}
3636

37-
fn parse_derive_trait(span: Span, list: Punctuated<Meta, syn::Token![,]>) -> Result<DeriveTrait>
37+
fn parse_derive_trait(
38+
attrs: &[Attribute],
39+
span: Span,
40+
list: Option<Punctuated<Meta, syn::Token![,]>>,
41+
) -> Result<DeriveTrait>
3842
where
3943
Self: Sized,
4044
{
4145
Ok(DeriveTrait::Serialize(Self {
42-
crate_: serde::parse_derive_trait(Trait::Serialize, span, list)?,
46+
crate_: serde::parse_derive_trait(Trait::Serialize, attrs, span, list)?,
4347
}))
4448
}
4549

src/trait_/zeroize.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::ops::Deref;
55
use proc_macro2::{Span, TokenStream};
66
use quote::quote;
77
use syn::{
8-
punctuated::Punctuated, spanned::Spanned, Expr, ExprLit, ExprPath, Lit, Meta, Path, Result,
9-
Token,
8+
punctuated::Punctuated, spanned::Spanned, Attribute, Expr, ExprLit, ExprPath, Lit, Meta, Path,
9+
Result, Token,
1010
};
1111

1212
use crate::{
@@ -29,9 +29,16 @@ impl TraitImpl for Zeroize {
2929
DeriveTrait::Zeroize(Self { crate_: None })
3030
}
3131

32-
fn parse_derive_trait(_span: Span, list: Punctuated<Meta, Token![,]>) -> Result<DeriveTrait> {
33-
// This is already checked in `DeriveTrait::from_stream`.
34-
debug_assert!(!list.is_empty());
32+
fn parse_derive_trait(
33+
_: &[Attribute],
34+
_span: Span,
35+
list: Option<Punctuated<Meta, Token![,]>>,
36+
) -> Result<DeriveTrait> {
37+
let list = if let Some(list) = list {
38+
list
39+
} else {
40+
return Ok(Self::default_derive_trait());
41+
};
3542

3643
let mut crate_ = None;
3744

src/trait_/zeroize_on_drop.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{borrow::Cow, iter, ops::Deref};
55
use proc_macro2::{Span, TokenStream};
66
use quote::quote;
77
use syn::{
8-
punctuated::Punctuated, spanned::Spanned, DeriveInput, Expr, ExprLit, ExprPath, Ident,
9-
ImplGenerics, Lit, Meta, Path, Result, Token, TypeGenerics, WhereClause,
8+
punctuated::Punctuated, spanned::Spanned, Attribute, DeriveInput, Expr, ExprLit, ExprPath,
9+
Ident, ImplGenerics, Lit, Meta, Path, Result, Token, TypeGenerics, WhereClause,
1010
};
1111

1212
use crate::{util, DeriveTrait, DeriveWhere, Error, Item, SplitGenerics, Trait, TraitImpl};
@@ -34,9 +34,16 @@ impl TraitImpl for ZeroizeOnDrop {
3434
})
3535
}
3636

37-
fn parse_derive_trait(_span: Span, list: Punctuated<Meta, Token![,]>) -> Result<DeriveTrait> {
38-
// This is already checked in `DeriveTrait::from_stream`.
39-
debug_assert!(!list.is_empty());
37+
fn parse_derive_trait(
38+
_: &[Attribute],
39+
_: Span,
40+
list: Option<Punctuated<Meta, Token![,]>>,
41+
) -> Result<DeriveTrait> {
42+
let list = if let Some(list) = list {
43+
list
44+
} else {
45+
return Ok(Self::default_derive_trait());
46+
};
4047

4148
let mut crate_ = None;
4249
#[cfg_attr(not(feature = "zeroize-on-drop"), allow(unused_mut))]

test-crates/crate_/src/lib.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,14 @@ use core::marker::PhantomData;
55
use derive_where_::derive_where;
66

77
#[derive_where(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
8-
#[cfg_attr(
9-
feature = "serde",
10-
derive_where(Deserialize(crate = serde_), Serialize(crate = serde_))
11-
)]
8+
#[cfg_attr(feature = "serde", derive_where(Deserialize, Serialize))]
129
#[cfg_attr(feature = "serde", serde(crate = "serde_"))]
1310
#[cfg_attr(feature = "zeroize", derive_where(Zeroize(crate = zeroize_)))]
1411
#[derive_where(crate = derive_where_)]
1512
pub struct Test<T>(PhantomData<T>);
1613

1714
#[derive_where(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
18-
#[cfg_attr(
19-
feature = "serde",
20-
derive_where(Deserialize(crate = "serde_"), Serialize(crate = "serde_"))
21-
)]
15+
#[cfg_attr(feature = "serde", derive_where(Deserialize, Serialize))]
2216
#[cfg_attr(feature = "serde", serde(crate = "serde_"))]
2317
#[cfg_attr(feature = "zeroize", derive_where(Zeroize(crate = "zeroize_")))]
2418
#[derive_where(crate = "derive_where_")]

0 commit comments

Comments
 (0)