derive_where/
lib.rs

1#![deny(unsafe_code)]
2#![cfg_attr(
3	feature = "nightly",
4	feature(allow_internal_unstable),
5	allow(internal_features)
6)]
7#![allow(clippy::tabs_in_doc_comments)]
8#![warn(clippy::cargo, clippy::missing_docs_in_private_items)]
9#![cfg_attr(feature = "nightly", allow(clippy::implied_bounds_in_impls))]
10#![cfg_attr(doc, allow(unknown_lints), warn(rustdoc::all))]
11
12//! # Description
13//!
14//! Attribute proc-macro to simplify deriving standard and other traits with
15//! custom generic type bounds.
16//!
17//! # Usage
18//!
19//! The [`derive_where`](macro@derive_where) attribute can be used just like
20//! std's `#[derive(...)]` statements:
21//!
22//! ```
23//! # use std::marker::PhantomData;
24//! # use derive_where::derive_where;
25//! #[derive_where(Clone, Debug)]
26//! struct Example<T>(PhantomData<T>);
27//! ```
28//!
29//! This will generate trait implementations for `Example` for any `T`,
30//! as opposed to std's derives, which would only implement these traits with
31//! `T: Trait` bound to the corresponding trait.
32//!
33//! Multiple [`derive_where`](macro@derive_where) attributes can be added to an
34//! item, but only the first one must use any path qualifications.
35//!
36//! ```
37//! # use std::marker::PhantomData;
38//! #[derive_where::derive_where(Clone, Debug)]
39//! #[derive_where(Eq, PartialEq)]
40//! struct Example1<T>(PhantomData<T>);
41//! ```
42//!
43//! If using a different package name, you must specify this:
44//!
45//! ```
46//! # extern crate derive_where as derive_where_;
47//! # use std::marker::PhantomData;
48//! # use derive_where::derive_where;
49//! #[derive_where(crate = derive_where_)]
50//! #[derive_where(Clone, Debug)]
51//! struct Example<T>(PhantomData<T>);
52//! ```
53//!
54//! In addition, the following convenience options are available:
55//!
56//! ## Generic type bounds
57//!
58//! Separated from the list of traits with a semicolon, types to bind to can be
59//! specified. This example will restrict the implementation for `Example` to
60//! `T: Clone`:
61//!
62//! ```
63//! # use std::marker::PhantomData;
64//! # use derive_where::derive_where;
65//! #[derive_where(Clone, Debug; T)]
66//! struct Example<T, U>(T, PhantomData<U>);
67//! ```
68//!
69//! It is also possible to specify the bounds to be applied. This will
70//! bind implementation for `Example` to `T: Super`:
71//!
72//! ```
73//! # use std::fmt::Debug;
74//! # use std::marker::PhantomData;
75//! # use derive_where::derive_where;
76//! trait Super: Clone + Debug {}
77//!
78//! #[derive_where(Clone, Debug; T: Super)]
79//! struct Example<T>(PhantomData<T>);
80//! ```
81//!
82//! But more complex trait bounds are possible as well.
83//! The example below will restrict the [`Clone`] implementation for `Example`
84//! to `T::Type: Clone`:
85//!
86//! ```
87//! # use std::marker::PhantomData;
88//! # use derive_where::derive_where;
89//! trait Trait {
90//! 	type Type;
91//! }
92//!
93//! struct Impl;
94//!
95//! impl Trait for Impl {
96//! 	type Type = i32;
97//! }
98//!
99//! #[derive_where(Clone, Debug; T::Type)]
100//! struct Example<T: Trait>(T::Type);
101//! ```
102//!
103//! Any combination of options listed here can be used to satisfy a
104//! specific constrain. It is also possible to use multiple separate
105//! constrain specifications when required:
106//!
107//! ```
108//! # use std::marker::PhantomData;
109//! # use derive_where::derive_where;
110//! #[derive_where(Clone, Debug; T)]
111//! #[derive_where(Eq, PartialEq; U)]
112//! struct Example<T, U>(PhantomData<T>, PhantomData<U>);
113//! ```
114//!
115//! ## Enum default
116//!
117//! Since Rust 1.62 deriving [`Default`] on an enum is possible with the
118//! `#[default]` attribute. Derive-where allows this with a
119//! `#[derive_where(default)]` attribute:
120//!
121//! ```
122//! # use std::marker::PhantomData;
123//! # use derive_where::derive_where;
124//! #[derive_where(Clone, Default)]
125//! enum Example<T> {
126//! 	#[derive_where(default)]
127//! 	A(PhantomData<T>),
128//! }
129//! ```
130//!
131//! ## Skipping fields
132//!
133//! With a `skip` or `skip_inner` attribute fields can be skipped for traits
134//! that allow it, which are: [`Debug`], [`Hash`], [`Ord`], [`PartialOrd`],
135//! [`PartialEq`], [`Zeroize`] and [`ZeroizeOnDrop`].
136//!
137//! ```
138//! # use std::marker::PhantomData;
139//! # use derive_where::derive_where;
140//! #[derive_where(Debug, PartialEq; T)]
141//! struct Example<T>(#[derive_where(skip)] T);
142//!
143//! assert_eq!(format!("{:?}", Example(42)), "Example");
144//! assert_eq!(Example(42), Example(0));
145//! ```
146//!
147//! It is also possible to skip all fields in an item or variant if desired:
148//!
149//! ```
150//! # use std::marker::PhantomData;
151//! # use derive_where::derive_where;
152//! #[derive_where(Debug, PartialEq)]
153//! #[derive_where(skip_inner)]
154//! struct StructExample<T>(T);
155//!
156//! assert_eq!(format!("{:?}", StructExample(42)), "StructExample");
157//! assert_eq!(StructExample(42), StructExample(0));
158//!
159//! #[derive_where(Debug, PartialEq)]
160//! enum EnumExample<T> {
161//! 	#[derive_where(skip_inner)]
162//! 	A(T),
163//! }
164//!
165//! assert_eq!(format!("{:?}", EnumExample::A(42)), "A");
166//! assert_eq!(EnumExample::A(42), EnumExample::A(0));
167//! ```
168//!
169//! Selective skipping of fields for certain traits is also an option, both in
170//! `skip` and `skip_inner`. To prevent breaking invariants defined for these
171//! traits, some of them can only be skipped in groups. The following groups are
172//! available:
173//! - [`Clone`]: Uses [`Default`] instead of [`Clone`].
174//! - [`Debug`]
175//! - `EqHashOrd`: Skips [`Eq`], [`Hash`], [`Ord`], [`PartialOrd`] and
176//!   [`PartialEq`].
177//! - [`Hash`]
178//! - `Zeroize`: Skips [`Zeroize`] and [`ZeroizeOnDrop`].
179//!
180//! ```
181//! # use std::marker::PhantomData;
182//! # use derive_where::derive_where;
183//! #[derive_where(Debug, PartialEq)]
184//! #[derive_where(skip_inner(Debug))]
185//! struct Example<T>(i32, PhantomData<T>);
186//!
187//! assert_eq!(format!("{:?}", Example(42, PhantomData::<()>)), "Example");
188//! assert_ne!(
189//! 	Example(42, PhantomData::<()>),
190//! 	Example(0, PhantomData::<()>)
191//! );
192//! ```
193//!
194//! ## Incomparable variants/items
195//!
196//! Similar to the `skip` attribute, `incomparable` can be used to skip variants
197//! or items in [`PartialEq`] and [`PartialOrd`] trait implementations, meaning
198//! they will always yield `false` for `eq` and `None` for `partial_cmp`. This
199//! results in all comparisons but `!=`, i.e. `==`, `<`, `<=`, `>=` and `>`,
200//! with the marked variant or struct evaluating to `false`.
201//!
202//! ```
203//! # use derive_where::derive_where;
204//! #[derive(Debug)]
205//! #[derive_where(PartialEq, PartialOrd)]
206//! enum EnumExample {
207//! 	#[derive_where(incomparable)]
208//! 	Incomparable,
209//! 	Comparable,
210//! }
211//! assert_eq!(EnumExample::Comparable, EnumExample::Comparable);
212//! assert_ne!(EnumExample::Incomparable, EnumExample::Incomparable);
213//! assert!(!(EnumExample::Comparable >= EnumExample::Incomparable));
214//! assert!(!(EnumExample::Comparable <= EnumExample::Incomparable));
215//! assert!(!(EnumExample::Incomparable >= EnumExample::Incomparable));
216//! assert!(!(EnumExample::Incomparable <= EnumExample::Incomparable));
217//!
218//! #[derive(Debug)]
219//! #[derive_where(PartialEq, PartialOrd)]
220//! #[derive_where(incomparable)]
221//! struct StructExample;
222//!
223//! assert_ne!(StructExample, StructExample);
224//! assert!(!(StructExample >= StructExample));
225//! assert!(!(StructExample <= StructExample));
226//! ```
227//!
228//! Note that it is not possible to use `incomparable` with [`Eq`] or [`Ord`] as
229//! that would break their invariants.
230//!
231//! ## Serde `Deserialize` and `Serialize`
232//!
233//! Deriving [`Deserialize`] and [`Serialize`] works as expected. While
234//! derive-where does not offer any attribute options, regular `serde`
235//! attributes can be used. Derive-where will respect
236//! [`#[serde(crate = "...")]`](https://serde.rs/container-attrs.html#crate).
237//!
238//! ## `Zeroize` options
239//!
240//! `Zeroize` has two options:
241//! - `crate`: an item-level option which specifies a path to the [`zeroize`]
242//!   crate in case of a re-export or rename.
243//! - `fqs`: a field-level option which will use fully-qualified-syntax instead
244//!   of calling the [`zeroize`][method@zeroize] method on `self` directly. This
245//!   is to avoid ambiguity between another method also called `zeroize`.
246//!
247//! ```
248//! # #[cfg(feature = "zeroize")]
249//! # {
250//! # use std::marker::PhantomData;
251//! # use derive_where::derive_where;
252//! # use zeroize_::Zeroize;
253//! #[derive_where(Zeroize(crate = zeroize_))]
254//! struct Example(#[derive_where(Zeroize(fqs))] i32);
255//!
256//! impl Example {
257//! 	// If we didn't specify the `fqs` option, this would lead to a compile
258//! 	// error because of method ambiguity.
259//! 	fn zeroize(&mut self) {
260//! 		self.0 = 1;
261//! 	}
262//! }
263//!
264//! let mut test = Example(42);
265//!
266//! // Will call the struct method.
267//! test.zeroize();
268//! assert_eq!(test.0, 1);
269//!
270//! // WIll call the `Zeroize::zeroize` method.
271//! Zeroize::zeroize(&mut test);
272//! assert_eq!(test.0, 0);
273//! # }
274//! ```
275//!
276//! ## `ZeroizeOnDrop` options
277//!
278//! If the `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`]
279//! and can be implemented without [`Zeroize`], otherwise it only implements
280//! [`Drop`] and requires [`Zeroize`] to be implemented.
281//!
282//! [`ZeroizeOnDrop`] has two options:
283//! - `crate`: an item-level option which specifies a path to the [`zeroize`]
284//!   crate in case of a re-export or rename.
285//! - `no_drop`: an item-level option which will not implement [`Drop`] but
286//!   instead only assert that every field implements [`ZeroizeOnDrop`].
287//!   Requires the `zeroize-on-drop` feature.
288//!
289//! ```
290//! # #[cfg(feature = "zeroize-on-drop")]
291//! # {
292//! # use std::marker::PhantomData;
293//! # use derive_where::derive_where;
294//! #[derive_where(ZeroizeOnDrop(crate = zeroize_))]
295//! struct Example(i32);
296//!
297//! assert!(core::mem::needs_drop::<Example>());
298//! # }
299//! ```
300//!
301//! ## Supported traits
302//!
303//! The following traits can be derived with derive-where:
304//! - [`Clone`]
305//! - [`Copy`]
306//! - [`Debug`]
307//! - [`Default`]
308//! - [`Deserialize`]: Only available with the `serde` crate feature.
309//! - [`Eq`]
310//! - [`Hash`]
311//! - [`Ord`]
312//! - [`PartialEq`]
313//! - [`PartialOrd`]
314//! - [`Serialize`]: Only available with the `serde` crate feature.
315//! - [`Zeroize`]: Only available with the `zeroize` crate feature.
316//! - [`ZeroizeOnDrop`]: Only available with the `zeroize` crate feature. If the
317//!   `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`],
318//!   otherwise it only implements [`Drop`].
319//!
320//! ## Supported items
321//!
322//! Structs, tuple structs, unions and enums are supported. Derive-where tries
323//! its best to discourage usage that could be covered by std's `derive`. For
324//! example unit structs and enums only containing unit variants aren't
325//! supported.
326//!
327//! Unions only support [`Clone`] and [`Copy`].
328//!
329//! [`PartialOrd`] and [`Ord`] need to determine the discriminant type to
330//! function correctly. To protect against a potential future change to the
331//! default discriminant type, some compile-time validation is inserted to
332//! ascertain that the type remains `isize`.
333//!
334//! ## `no_std` support
335//!
336//! `no_std` support is provided by default.
337//!
338//! # Crate features
339//!
340//! - `nightly`: Implements [`Ord`] and [`PartialOrd`] with the help of
341//!   [`core::intrinsics::discriminant_value`], which is what Rust does by
342//!   default too. This requires a nightly version of the Rust compiler.
343//! - `safe`: `safe`: Uses only safe ways to access the discriminant of the enum
344//!   for [`Ord`] and [`PartialOrd`]. It also replaces all cases of
345//!   [`core::hint::unreachable_unchecked`] in [`Ord`], [`PartialEq`] and
346//!   [`PartialOrd`], which is what std uses, with [`unreachable`].
347//! - `zeroize`: Allows deriving [`Zeroize`] and [`zeroize`][method@zeroize] on
348//!   [`Drop`].
349//! - `zeroize-on-drop`: Allows deriving [`Zeroize`] and [`ZeroizeOnDrop`] and
350//!   requires [`zeroize`] v1.5.
351//!
352//! # MSRV
353//!
354//! The current MSRV is 1.57 and is being checked by the CI. A change will be
355//! accompanied by a minor version bump. If MSRV is important to you, use
356//! `derive-where = "~1.x"` to pin a specific minor version to your crate.
357//!
358//! # Alternatives
359//!
360//! - [derivative](https://crates.io/crates/derivative) [![Crates.io](https://img.shields.io/crates/v/derivative.svg)](https://crates.io/crates/derivative)
361//!   is a great alternative with many options. Notably it doesn't support
362//!   `no_std` and requires an extra `#[derive(Derivative)]` to use.
363//! - [derive_bounded](https://crates.io/crates/derive_bounded) [![Crates.io](https://img.shields.io/crates/v/derive_bounded.svg)](https://crates.io/crates/derive_bounded)
364//!   is a new alternative still in development.
365//!
366//! # Changelog
367//!
368//! See the [CHANGELOG] file for details.
369//!
370//! # License
371//!
372//! Licensed under either of
373//!
374//! - Apache License, Version 2.0 ([LICENSE-APACHE] or <http://www.apache.org/licenses/LICENSE-2.0>)
375//! - MIT license ([LICENSE-MIT] or <http://opensource.org/licenses/MIT>)
376//!
377//! at your option.
378//!
379//! ## Contribution
380//!
381//! Unless you explicitly state otherwise, any contribution intentionally
382//! submitted for inclusion in the work by you, as defined in the Apache-2.0
383//! license, shall be dual licensed as above, without any additional terms or
384//! conditions.
385//!
386//! [CHANGELOG]: https://github.com/ModProg/derive-where/blob/main/CHANGELOG.md
387//! [LICENSE-MIT]: https://github.com/ModProg/derive-where/blob/main/LICENSE-MIT
388//! [LICENSE-APACHE]: https://github.com/ModProg/derive-where/blob/main/LICENSE-APACHE
389//! [`Debug`]: core::fmt::Debug
390//! [`Default`]: core::default::Default
391//! [`Deserialize`]: https://docs.rs/serde/latest/serde/derive.Deserialize.html
392//! [`Eq`]: core::cmp::Eq
393//! [`Hash`]: core::hash::Hash
394//! [`Ord`]: core::cmp::Ord
395//! [`PartialEq`]: core::cmp::PartialEq
396//! [`PartialOrd`]: core::cmp::PartialOrd
397//! [`Serialize`]: https://docs.rs/serde/latest/serde/derive.Serialize.html
398//! [`zeroize`]: https://docs.rs/zeroize
399//! [`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
400//! [`ZeroizeOnDrop`]: https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html
401//! [method@zeroize]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html#tymethod.zeroize
402
403mod attr;
404mod data;
405mod error;
406mod input;
407mod item;
408#[cfg(test)]
409mod test;
410mod trait_;
411mod util;
412
413use std::{borrow::Cow, iter};
414
415use input::SplitGenerics;
416use proc_macro2::TokenStream;
417use quote::{quote, quote_spanned, ToTokens};
418use syn::{
419	spanned::Spanned, Attribute, DataEnum, DataStruct, DataUnion, DeriveInput, Fields, FieldsNamed,
420	FieldsUnnamed, Meta, Path, Result, Variant,
421};
422use util::MetaListExt;
423
424#[cfg(feature = "zeroize")]
425use self::attr::ZeroizeFqs;
426#[cfg(not(feature = "nightly"))]
427use self::item::Discriminant;
428use self::{
429	attr::{Default, DeriveWhere, FieldAttr, Incomparable, ItemAttr, Skip, SkipGroup, VariantAttr},
430	data::{Data, DataType, Field, SimpleType},
431	error::Error,
432	input::Input,
433	item::Item,
434	trait_::{DeriveTrait, Trait, TraitImpl},
435	util::Either,
436};
437
438/// Name of the `derive_where` attribute proc-macro.
439const DERIVE_WHERE: &str = "derive_where";
440/// Name of the `DeriveWhere` derive proc-macro.
441const DERIVE_WHERE_FORWARD: &str = "DeriveWhere";
442/// Name of the `derive_where_visited` proc-macro.
443const DERIVE_WHERE_VISITED: &str = "derive_where_visited";
444
445/// Item-level options:
446/// - `#[derive_where(crate = path)]`: Specify path to the `derive_where` crate.
447/// - `#[derive_where(Clone, ..; T, ..)]`: Specify traits to implement and
448///   optionally bounds.
449///   - `#[derive_where(Zeroize(crate = path))]`: Specify path to [`Zeroize`]
450///     trait.
451///   - `#[derive_where(ZeroizeOnDrop(crate = path))]`: Specify path to
452///     [`ZeroizeOnDrop`] trait.
453///   - `#[derive_where(ZeroizeOnDrop(no_drop))]`: no [`Drop`] implementation.
454/// - `#[derive_where(skip_inner(EqHashOrd, ..))]`: Skip all fields in the item.
455///   Optionally specify trait groups to constrain skipping fields. Only works
456///   for structs, for enums use this on the variant-level.
457///
458/// Variant-level options:
459/// - `#[derive_where(default)]`: Uses this variant as the default for the
460///   [`Default`](trait@core::default::Default) implementation.
461/// - `#[derive_where(skip_inner(EqHashOrd, ..))]`: Skip all fields in this
462///   variant. Optionally specify trait groups to constrain skipping fields.
463///
464/// Field-level options:
465/// - `#[derive_where(skip(EqHashOrd, ...))]`: Skip field. Optionally specify
466///   trait groups to constrain skipping field.
467/// - `#[derive_where(Zeroize(fqs))]`: Use fully-qualified-syntax when
468///   implementing [`Zeroize`].
469///
470/// See the [crate] level description for more details.
471///
472/// [`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
473/// [`ZeroizeOnDrop`]: https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html
474#[proc_macro_attribute]
475pub fn derive_where(
476	attr: proc_macro::TokenStream,
477	original_input: proc_macro::TokenStream,
478) -> proc_macro::TokenStream {
479	let attr = TokenStream::from(attr);
480	let mut original_input = TokenStream::from(original_input);
481	let mut input = quote_spanned! { attr.span()=> #[derive_where(#attr)] };
482	input.extend(original_input.clone());
483
484	match syn::parse2::<DeriveInput>(input) {
485		Ok(input) => match derive_where_internal(input.clone()) {
486			Ok(item) => item.into(),
487			Err(error) => {
488				let mut clean_input =
489					input_without_derive_where_attributes(input).into_token_stream();
490				clean_input.extend(error.into_compile_error());
491				clean_input.into()
492			}
493		},
494		Err(error) => {
495			original_input.extend(error.into_compile_error());
496			original_input.into()
497		}
498	}
499}
500
501/// Convenient way to deal with [`Result`] for [`derive_where()`].
502fn derive_where_internal(mut item: DeriveInput) -> Result<TokenStream> {
503	let mut crate_ = None;
504
505	// Search for `crate` option.
506	for attr in &item.attrs {
507		if attr.path().is_ident(DERIVE_WHERE) {
508			if let Meta::List(list) = &attr.meta {
509				if let Ok(nested) = list.parse_non_empty_nested_metas() {
510					if nested.len() == 1 {
511						let meta = nested.into_iter().next().expect("unexpected empty list");
512
513						if meta.path().is_ident("crate") {
514							let (path, span) = attr::parse_crate(meta)?;
515
516							match crate_ {
517								Some(_) => return Err(Error::option_duplicate(span, "crate")),
518								None => crate_ = Some(path),
519							}
520						}
521					}
522				}
523			}
524		}
525	}
526
527	// Build [`Path`] to crate.
528	let crate_ = crate_.unwrap_or_else(|| util::path_from_strs(&[DERIVE_WHERE]));
529
530	// Build `derive_where_visited` path.
531	let derive_where_visited =
532		util::path_from_root_and_strs(crate_.clone(), &[DERIVE_WHERE_VISITED]);
533
534	// Check if we already parsed this item before.
535	for attr in &item.attrs {
536		if attr.path() == &derive_where_visited {
537			return Err(Error::visited(attr.span()));
538		}
539	}
540
541	// Mark this as visited to prevent duplicate `derive_where` attributes.
542	item.attrs
543		.push(syn::parse_quote! { #[#derive_where_visited] });
544
545	// Build `DeriveWhere` path.
546	let derive_where = util::path_from_root_and_strs(crate_, &[DERIVE_WHERE_FORWARD]);
547
548	// Let the `derive` proc-macro parse this.
549	let mut output = quote! { #[derive(#derive_where)] };
550	output.extend(item.into_token_stream());
551	Ok(output)
552}
553
554/// Internally we re-direct the attribute macro to the derive macro. Unlike the
555/// attribute macro, the derive macro supports helper attributes and evaluates
556/// `cfg`s.
557#[doc(hidden)]
558#[cfg_attr(
559	not(feature = "serde"),
560	proc_macro_derive(DeriveWhere, attributes(derive_where))
561)]
562#[cfg_attr(
563	feature = "serde",
564	proc_macro_derive(DeriveWhere, attributes(derive_where, serde))
565)]
566#[cfg_attr(feature = "nightly", allow_internal_unstable(core_intrinsics))]
567pub fn derive_where_actual(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
568	let input = TokenStream::from(input);
569	let full_item = match syn::parse2::<DeriveInput>(input) {
570		Ok(item) => item,
571		Err(error) => {
572			return error.into_compile_error().into();
573		}
574	};
575
576	let span = {
577		let clean_item = DeriveInput {
578			attrs: Vec::new(),
579			vis: full_item.vis.clone(),
580			ident: full_item.ident.clone(),
581			generics: full_item.generics.clone(),
582			data: full_item.data.clone(),
583		};
584
585		clean_item.span()
586	};
587
588	match Input::from_input(span, &full_item) {
589		Ok(Input {
590			crate_,
591			derive_wheres,
592			generics,
593			item,
594		}) => derive_wheres
595			.iter()
596			.flat_map(|derive_where| iter::repeat(derive_where).zip(&derive_where.traits))
597			.map(|(derive_where, trait_)| {
598				generate_impl(
599					crate_.as_ref(),
600					&full_item,
601					derive_where,
602					trait_,
603					&item,
604					&generics,
605				)
606			})
607			.collect::<TokenStream>()
608			.into(),
609		Err(error) => error.into_compile_error().into(),
610	}
611}
612
613/// Marker attribute signifying that this item was already processed by a
614/// `derive_where` attribute before. This should prevent users to wrongly use a
615/// qualified path for a `derive_where` attribute except the first one.
616///
617/// MSRV: This currently prevents an MSRV down to 1.34, as proc-macro derives
618/// are not allowed to come before a proc-macro attribute. But the logic of this
619/// proc-macro attribute is circumvented if it isn't inserted at the end, after
620/// the proc-macro derive.
621#[doc(hidden)]
622#[proc_macro_attribute]
623pub fn derive_where_visited(
624	_attr: proc_macro::TokenStream,
625	input: proc_macro::TokenStream,
626) -> proc_macro::TokenStream {
627	// No-op, just here to mark the item as visited.
628	input
629}
630
631/// Generate implementation for a [`Trait`].
632fn generate_impl(
633	crate_: Option<&Path>,
634	full_item: &DeriveInput,
635	derive_where: &DeriveWhere,
636	trait_: &DeriveTrait,
637	item: &Item,
638	generics: &SplitGenerics,
639) -> TokenStream {
640	let SplitGenerics {
641		imp,
642		ty,
643		where_clause,
644	} = generics;
645	let mut where_clause = where_clause.map(Cow::Borrowed);
646	derive_where.where_clause(&mut where_clause, trait_, item);
647
648	let body = generate_body(derive_where, trait_, item, generics);
649
650	let ident = item.ident();
651	let mut output = trait_.impl_item(crate_, full_item, imp, ident, ty, &where_clause, body);
652
653	if let Some((path, body)) = trait_.additional_impl() {
654		output.extend(quote! {
655			#[automatically_derived]
656			impl #imp #path for #ident #ty
657			#where_clause
658			{
659				#body
660			}
661		})
662	}
663
664	output
665}
666
667/// Generate implementation method body for a [`Trait`].
668fn generate_body(
669	derive_where: &DeriveWhere,
670	trait_: &DeriveTrait,
671	item: &Item,
672	generics: &SplitGenerics<'_>,
673) -> TokenStream {
674	match &item {
675		Item::Item(data) => {
676			let body = trait_.build_body(derive_where, data);
677			trait_.build_signature(derive_where, item, generics, &body)
678		}
679		Item::Enum { variants, .. } => {
680			let body: TokenStream = variants
681				.iter()
682				.map(|data| trait_.build_body(derive_where, data))
683				.collect();
684
685			trait_.build_signature(derive_where, item, generics, &body)
686		}
687	}
688}
689
690/// Removes `derive_where` attributes from the item and all fields and variants.
691///
692/// This is necessary because Rust currently does not support helper attributes
693/// for attribute proc-macros and therefore doesn't automatically remove them.
694fn input_without_derive_where_attributes(mut input: DeriveInput) -> DeriveInput {
695	use syn::Data;
696
697	let DeriveInput { data, attrs, .. } = &mut input;
698
699	/// Remove all `derive_where` attributes.
700	fn remove_derive_where(attrs: &mut Vec<Attribute>) {
701		attrs.retain(|attr| !attr.path().is_ident(DERIVE_WHERE))
702	}
703
704	/// Remove all `derive_where` attributes from [`FieldsNamed`].
705	fn remove_derive_where_from_fields_named(fields: &mut FieldsNamed) {
706		let FieldsNamed { named, .. } = fields;
707		named
708			.iter_mut()
709			.for_each(|field| remove_derive_where(&mut field.attrs))
710	}
711
712	/// Remove all `derive_where` attributes from [`Fields`].
713	fn remove_derive_where_from_fields(fields: &mut Fields) {
714		match fields {
715			Fields::Named(fields) => remove_derive_where_from_fields_named(fields),
716			Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed
717				.iter_mut()
718				.for_each(|field| remove_derive_where(&mut field.attrs)),
719			Fields::Unit => (),
720		}
721	}
722
723	// Remove `derive_where` attributes from the item.
724	remove_derive_where(attrs);
725
726	// Remove `derive_where` attributes from variants or fields.
727	match data {
728		Data::Struct(DataStruct { fields, .. }) => remove_derive_where_from_fields(fields),
729		Data::Enum(DataEnum { variants, .. }) => {
730			variants
731				.iter_mut()
732				.for_each(|Variant { attrs, fields, .. }| {
733					remove_derive_where(attrs);
734					remove_derive_where_from_fields(fields)
735				})
736		}
737		Data::Union(DataUnion { fields, .. }) => remove_derive_where_from_fields_named(fields),
738	}
739
740	input
741}
742
743/// This is used by the Serde implementation to remove the duplicate item.
744#[cfg(feature = "serde")]
745#[doc(hidden)]
746#[proc_macro_attribute]
747pub fn derive_where_serde(
748	_: proc_macro::TokenStream,
749	_: proc_macro::TokenStream,
750) -> proc_macro::TokenStream {
751	proc_macro::TokenStream::new()
752}