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 semi-colon, 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//! - [`Debug`]
174//! - `EqHashOrd`: Skips [`Eq`], [`Hash`], [`Ord`], [`PartialOrd`] and
175//!   [`PartialEq`].
176//! - [`Hash`]
177//! - `Zeroize`: Skips [`Zeroize`] and [`ZeroizeOnDrop`].
178//!
179//! ```
180//! # use std::marker::PhantomData;
181//! # use derive_where::derive_where;
182//! #[derive_where(Debug, PartialEq)]
183//! #[derive_where(skip_inner(Debug))]
184//! struct Example<T>(i32, PhantomData<T>);
185//!
186//! assert_eq!(format!("{:?}", Example(42, PhantomData::<()>)), "Example");
187//! assert_ne!(
188//! 	Example(42, PhantomData::<()>),
189//! 	Example(0, PhantomData::<()>)
190//! );
191//! ```
192//!
193//! ## Incomparable variants/items
194//!
195//! Similar to the `skip` attribute, `incomparable` can be used to skip variants
196//! or items in [`PartialEq`] and [`PartialOrd`] trait implementations, meaning
197//! they will always yield `false` for `eq` and `None` for `partial_cmp`. This
198//! results in all comparisons but `!=`, i.e. `==`, `<`, `<=`, `>=` and `>`,
199//! with the marked variant or struct evaluating to `false`.
200//!
201//! ```
202//! # use derive_where::derive_where;
203//! #[derive(Debug)]
204//! #[derive_where(PartialEq, PartialOrd)]
205//! enum EnumExample {
206//! 	#[derive_where(incomparable)]
207//! 	Incomparable,
208//! 	Comparable,
209//! }
210//! assert_eq!(EnumExample::Comparable, EnumExample::Comparable);
211//! assert_ne!(EnumExample::Incomparable, EnumExample::Incomparable);
212//! assert!(!(EnumExample::Comparable >= EnumExample::Incomparable));
213//! assert!(!(EnumExample::Comparable <= EnumExample::Incomparable));
214//! assert!(!(EnumExample::Incomparable >= EnumExample::Incomparable));
215//! assert!(!(EnumExample::Incomparable <= EnumExample::Incomparable));
216//!
217//! #[derive(Debug)]
218//! #[derive_where(PartialEq, PartialOrd)]
219//! #[derive_where(incomparable)]
220//! struct StructExample;
221//!
222//! assert_ne!(StructExample, StructExample);
223//! assert!(!(StructExample >= StructExample));
224//! assert!(!(StructExample <= StructExample));
225//! ```
226//!
227//! Note that it is not possible to use `incomparable` with [`Eq`] or [`Ord`] as
228//! that would break their invariants.
229//!
230//! ## `Zeroize` options
231//!
232//! `Zeroize` has two options:
233//! - `crate`: an item-level option which specifies a path to the [`zeroize`]
234//!   crate in case of a re-export or rename.
235//! - `fqs`: a field-level option which will use fully-qualified-syntax instead
236//!   of calling the [`zeroize`][method@zeroize] method on `self` directly. This
237//!   is to avoid ambiguity between another method also called `zeroize`.
238//!
239//! ```
240//! # #[cfg(feature = "zeroize")]
241//! # {
242//! # use std::marker::PhantomData;
243//! # use derive_where::derive_where;
244//! # use zeroize_::Zeroize;
245//! #[derive_where(Zeroize(crate = zeroize_))]
246//! struct Example(#[derive_where(Zeroize(fqs))] i32);
247//!
248//! impl Example {
249//! 	// If we didn't specify the `fqs` option, this would lead to a compile
250//! 	// error because of method ambiguity.
251//! 	fn zeroize(&mut self) {
252//! 		self.0 = 1;
253//! 	}
254//! }
255//!
256//! let mut test = Example(42);
257//!
258//! // Will call the struct method.
259//! test.zeroize();
260//! assert_eq!(test.0, 1);
261//!
262//! // WIll call the `Zeroize::zeroize` method.
263//! Zeroize::zeroize(&mut test);
264//! assert_eq!(test.0, 0);
265//! # }
266//! ```
267//!
268//! ## `ZeroizeOnDrop` options
269//!
270//! If the `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`]
271//! and can be implemented without [`Zeroize`], otherwise it only implements
272//! [`Drop`] and requires [`Zeroize`] to be implemented.
273//!
274//! [`ZeroizeOnDrop`] has one option:
275//! - `crate`: an item-level option which specifies a path to the [`zeroize`]
276//!   crate in case of a re-export or rename.
277//!
278//! ```
279//! # #[cfg(feature = "zeroize-on-drop")]
280//! # {
281//! # use std::marker::PhantomData;
282//! # use derive_where::derive_where;
283//! #[derive_where(ZeroizeOnDrop(crate = zeroize_))]
284//! struct Example(i32);
285//!
286//! assert!(core::mem::needs_drop::<Example>());
287//! # }
288//! ```
289//!
290//! ## Supported traits
291//!
292//! The following traits can be derived with derive-where:
293//! - [`Clone`]
294//! - [`Copy`]
295//! - [`Debug`]
296//! - [`Default`]
297//! - [`Eq`]
298//! - [`Hash`]
299//! - [`Ord`]
300//! - [`PartialEq`]
301//! - [`PartialOrd`]
302//! - [`Zeroize`]: Only available with the `zeroize` crate feature.
303//! - [`ZeroizeOnDrop`]: Only available with the `zeroize` crate feature. If the
304//!   `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`],
305//!   otherwise it only implements [`Drop`].
306//!
307//! ## Supported items
308//!
309//! Structs, tuple structs, unions and enums are supported. Derive-where tries
310//! it's best to discourage usage that could be covered by std's `derive`. For
311//! example unit structs and enums only containing unit variants aren't
312//! supported.
313//!
314//! Unions only support [`Clone`] and [`Copy`].
315//!
316//! [`PartialOrd`] and [`Ord`] need to determine the discriminant type to
317//! function correctly. To protect against a potential future change to the
318//! default discriminant type, some compile-time validation is inserted to
319//! ascertain that the type remains `isize`.
320//!
321//! ## `no_std` support
322//!
323//! `no_std` support is provided by default.
324//!
325//! # Crate features
326//!
327//! - `nightly`: Implements [`Ord`] and [`PartialOrd`] with the help of
328//!   [`core::intrinsics::discriminant_value`], which is what Rust does by
329//!   default too. This requires a nightly version of the Rust compiler.
330//! - `safe`: `safe`: Uses only safe ways to access the discriminant of the enum
331//!   for [`Ord`] and [`PartialOrd`]. It also replaces all cases of
332//!   [`core::hint::unreachable_unchecked`] in [`Ord`], [`PartialEq`] and
333//!   [`PartialOrd`], which is what std uses, with [`unreachable`].
334//! - `zeroize`: Allows deriving [`Zeroize`] and [`zeroize`][method@zeroize] on
335//!   [`Drop`].
336//! - `zeroize-on-drop`: Allows deriving [`Zeroize`] and [`ZeroizeOnDrop`] and
337//!   requires [`zeroize`] v1.5.
338//!
339//! # MSRV
340//!
341//! The current MSRV is 1.57 and is being checked by the CI. A change will be
342//! accompanied by a minor version bump. If MSRV is important to you, use
343//! `derive-where = "~1.x"` to pin a specific minor version to your crate.
344//!
345//! # Alternatives
346//!
347//! - [derivative](https://crates.io/crates/derivative) [![Crates.io](https://img.shields.io/crates/v/derivative.svg)](https://crates.io/crates/derivative)
348//!   is a great alternative with many options. Notably it doesn't support
349//!   `no_std` and requires an extra `#[derive(Derivative)]` to use.
350//! - [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)
351//!   is a new alternative still in development.
352//!
353//! # Changelog
354//!
355//! See the [CHANGELOG] file for details.
356//!
357//! # License
358//!
359//! Licensed under either of
360//!
361//! - Apache License, Version 2.0 ([LICENSE-APACHE] or <http://www.apache.org/licenses/LICENSE-2.0>)
362//! - MIT license ([LICENSE-MIT] or <http://opensource.org/licenses/MIT>)
363//!
364//! at your option.
365//!
366//! ## Contribution
367//!
368//! Unless you explicitly state otherwise, any contribution intentionally
369//! submitted for inclusion in the work by you, as defined in the Apache-2.0
370//! license, shall be dual licensed as above, without any additional terms or
371//! conditions.
372//!
373//! [CHANGELOG]: https://github.com/ModProg/derive-where/blob/main/CHANGELOG.md
374//! [LICENSE-MIT]: https://github.com/ModProg/derive-where/blob/main/LICENSE-MIT
375//! [LICENSE-APACHE]: https://github.com/ModProg/derive-where/blob/main/LICENSE-APACHE
376//! [`Debug`]: core::fmt::Debug
377//! [`Default`]: core::default::Default
378//! [`Eq`]: core::cmp::Eq
379//! [`Hash`]: core::hash::Hash
380//! [`Ord`]: core::cmp::Ord
381//! [`PartialEq`]: core::cmp::PartialEq
382//! [`PartialOrd`]: core::cmp::PartialOrd
383//! [`zeroize`]: https://docs.rs/zeroize
384//! [`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
385//! [`ZeroizeOnDrop`]: https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html
386//! [method@zeroize]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html#tymethod.zeroize
387
388mod attr;
389mod data;
390mod error;
391mod input;
392mod item;
393#[cfg(test)]
394mod test;
395mod trait_;
396mod util;
397
398use std::{borrow::Cow, iter};
399
400use input::SplitGenerics;
401use proc_macro2::TokenStream;
402use quote::{quote, quote_spanned, ToTokens};
403use syn::{
404	spanned::Spanned, Attribute, DataEnum, DataStruct, DataUnion, DeriveInput, Expr, ExprLit,
405	ExprPath, Fields, FieldsNamed, FieldsUnnamed, Lit, Meta, Path, Result, Variant,
406};
407use util::MetaListExt;
408
409#[cfg(feature = "zeroize")]
410use self::attr::ZeroizeFqs;
411use self::{
412	attr::{
413		Default, DeriveTrait, DeriveWhere, FieldAttr, Incomparable, ItemAttr, Skip, SkipGroup,
414		VariantAttr,
415	},
416	data::{Data, DataType, Field, SimpleType},
417	error::Error,
418	input::Input,
419	item::{Discriminant, Item},
420	trait_::{Trait, TraitImpl},
421	util::Either,
422};
423
424/// Name of the `derive_where` attribute proc-macro.
425const DERIVE_WHERE: &str = "derive_where";
426/// Name of the `DeriveWhere` derive proc-macro.
427const DERIVE_WHERE_FORWARD: &str = "DeriveWhere";
428/// Name of the `derive_where_visited` proc-macro.
429const DERIVE_WHERE_VISITED: &str = "derive_where_visited";
430
431/// Item-level options:
432/// - `#[derive_where(crate = path)]`: Specify path to the `derive_where` crate.
433/// - `#[derive_where(Clone, ..; T, ..)]`: Specify traits to implement and
434///   optionally bounds.
435///   - `#[derive_where(Zeroize(crate = path))]`: Specify path to [`Zeroize`]
436///     trait.
437///   - `#[derive_where(ZeroizeOnDrop(crate = path))]`: Specify path to
438///     [`ZeroizeOnDrop`] trait.
439/// - `#[derive_where(skip_inner(EqHashOrd, ..))]`: Skip all fields in the item.
440///   Optionally specify trait groups to constrain skipping fields. Only works
441///   for structs, for enums use this on the variant-level.
442///
443/// Variant-level options:
444/// - `#[derive_where(default)]`: Uses this variant as the default for the
445///   [`Default`](trait@core::default::Default) implementation.
446/// - `#[derive_where(skip_inner(EqHashOrd, ..))]`: Skip all fields in this
447///   variant. Optionally specify trait groups to constrain skipping fields.
448///
449/// Field-level options:
450/// - `#[derive_where(skip(EqHashOrd, ...))]`: Skip field. Optionally specify
451///   trait groups to constrain skipping field.
452/// - `#[derive_where(Zeroize(fqs))]`: Use fully-qualified-syntax when
453///   implementing [`Zeroize`].
454///
455/// See the [crate] level description for more details.
456///
457/// [`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
458/// [`ZeroizeOnDrop`]: https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html
459#[proc_macro_attribute]
460pub fn derive_where(
461	attr: proc_macro::TokenStream,
462	original_input: proc_macro::TokenStream,
463) -> proc_macro::TokenStream {
464	let attr = TokenStream::from(attr);
465	let mut original_input = TokenStream::from(original_input);
466	let mut input = quote_spanned! { attr.span()=> #[derive_where(#attr)] };
467	input.extend(original_input.clone());
468
469	match syn::parse2::<DeriveInput>(input) {
470		Ok(input) => match derive_where_internal(input.clone()) {
471			Ok(item) => item.into(),
472			Err(error) => {
473				let mut clean_input =
474					input_without_derive_where_attributes(input).into_token_stream();
475				clean_input.extend(error.into_compile_error());
476				clean_input.into()
477			}
478		},
479		Err(error) => {
480			original_input.extend(error.into_compile_error());
481			original_input.into()
482		}
483	}
484}
485
486/// Convenient way to deal with [`Result`] for [`derive_where()`].
487fn derive_where_internal(mut item: DeriveInput) -> Result<TokenStream> {
488	let mut crate_ = None;
489
490	// Search for `crate` option.
491	for attr in &item.attrs {
492		if attr.path().is_ident(DERIVE_WHERE) {
493			if let Meta::List(list) = &attr.meta {
494				if let Ok(nested) = list.parse_non_empty_nested_metas() {
495					if nested.len() == 1 {
496						let meta = nested.into_iter().next().expect("unexpected empty list");
497
498						if meta.path().is_ident("crate") {
499							if let Meta::NameValue(name_value) = meta {
500								let path = match &name_value.value {
501									Expr::Lit(ExprLit {
502										lit: Lit::Str(lit_str),
503										..
504									}) => match lit_str.parse::<Path>() {
505										Ok(path) => path,
506										Err(error) => {
507											return Err(Error::path(lit_str.span(), error))
508										}
509									},
510									Expr::Path(ExprPath { path, .. }) => path.clone(),
511									_ => return Err(Error::option_syntax(name_value.value.span())),
512								};
513
514								if path == util::path_from_strs(&[DERIVE_WHERE]) {
515									return Err(Error::path_unnecessary(
516										path.span(),
517										&format!("::{}", DERIVE_WHERE),
518									));
519								}
520
521								match crate_ {
522									Some(_) => {
523										return Err(Error::option_duplicate(
524											name_value.span(),
525											"crate",
526										))
527									}
528									None => crate_ = Some(path),
529								}
530							} else {
531								return Err(Error::option_syntax(meta.span()));
532							}
533						}
534					}
535				}
536			}
537		}
538	}
539
540	// Build [`Path`] to crate.
541	let crate_ = crate_.unwrap_or_else(|| util::path_from_strs(&[DERIVE_WHERE]));
542
543	// Build `derive_where_visited` path.
544	let derive_where_visited =
545		util::path_from_root_and_strs(crate_.clone(), &[DERIVE_WHERE_VISITED]);
546
547	// Check if we already parsed this item before.
548	for attr in &item.attrs {
549		if attr.path() == &derive_where_visited {
550			return Err(Error::visited(attr.span()));
551		}
552	}
553
554	// Mark this as visited to prevent duplicate `derive_where` attributes.
555	item.attrs
556		.push(syn::parse_quote! { #[#derive_where_visited] });
557
558	// Build `DeriveWhere` path.
559	let derive_where = util::path_from_root_and_strs(crate_, &[DERIVE_WHERE_FORWARD]);
560
561	// Let the `derive` proc-macro parse this.
562	let mut output = quote! { #[derive(#derive_where)] };
563	output.extend(item.into_token_stream());
564	Ok(output)
565}
566
567#[doc(hidden)]
568#[proc_macro_derive(DeriveWhere, attributes(derive_where))]
569#[cfg_attr(feature = "nightly", allow_internal_unstable(core_intrinsics))]
570pub fn derive_where_actual(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
571	let input = TokenStream::from(input);
572	let item = match syn::parse2::<DeriveInput>(input) {
573		Ok(item) => item,
574		Err(error) => {
575			return error.into_compile_error().into();
576		}
577	};
578
579	let span = {
580		let clean_item = DeriveInput {
581			attrs: Vec::new(),
582			vis: item.vis.clone(),
583			ident: item.ident.clone(),
584			generics: item.generics.clone(),
585			data: item.data.clone(),
586		};
587
588		clean_item.span()
589	};
590
591	match { Input::from_input(span, &item) } {
592		Ok(Input {
593			derive_wheres,
594			generics,
595			item,
596		}) => derive_wheres
597			.iter()
598			.flat_map(|derive_where| iter::repeat(derive_where).zip(&derive_where.traits))
599			.map(|(derive_where, trait_)| generate_impl(derive_where, trait_, &item, &generics))
600			.collect::<TokenStream>()
601			.into(),
602		Err(error) => error.into_compile_error().into(),
603	}
604}
605
606/// Marker attribute signifying that this item was already processed by a
607/// `derive_where` attribute before. This should prevent users to wrongly use a
608/// qualified path for a `derive_where` attribute except the first one.
609///
610/// MSRV: This currently prevents an MSRV down to 1.34, as proc-macro derives
611/// are not allowed to come before a proc-macro attribute. But the logic of this
612/// proc-macro attribute is circumvented if it isn't inserted at the end, after
613/// the proc-macro derive.
614#[doc(hidden)]
615#[proc_macro_attribute]
616pub fn derive_where_visited(
617	_attr: proc_macro::TokenStream,
618	input: proc_macro::TokenStream,
619) -> proc_macro::TokenStream {
620	// No-op, just here to mark the item as visited.
621	input
622}
623
624/// Generate implementation for a [`Trait`].
625fn generate_impl(
626	derive_where: &DeriveWhere,
627	trait_: &DeriveTrait,
628	item: &Item,
629	generics: &SplitGenerics,
630) -> TokenStream {
631	let SplitGenerics {
632		imp,
633		ty,
634		where_clause,
635	} = generics;
636	let mut where_clause = where_clause.map(Cow::Borrowed);
637	derive_where.where_clause(&mut where_clause, trait_, item);
638
639	let body = generate_body(derive_where, &derive_where.traits, trait_, item, generics);
640
641	let ident = item.ident();
642	let path = trait_.impl_path(trait_);
643	let mut output = quote! {
644		#[automatically_derived]
645		impl #imp #path for #ident #ty
646		#where_clause
647		{
648			#body
649		}
650	};
651
652	if let Some((path, body)) = trait_.additional_impl(trait_) {
653		output.extend(quote! {
654			#[automatically_derived]
655			impl #imp #path for #ident #ty
656			#where_clause
657			{
658				#body
659			}
660		})
661	}
662
663	output
664}
665
666/// Generate implementation method body for a [`Trait`].
667fn generate_body(
668	derive_where: &DeriveWhere,
669	traits: &[DeriveTrait],
670	trait_: &DeriveTrait,
671	item: &Item,
672	generics: &SplitGenerics<'_>,
673) -> TokenStream {
674	let any_bound = !derive_where.generics.is_empty();
675
676	match &item {
677		Item::Item(data) => {
678			let body = trait_.build_body(any_bound, traits, trait_, data);
679			trait_.build_signature(any_bound, item, generics, traits, trait_, &body)
680		}
681		Item::Enum { variants, .. } => {
682			let body: TokenStream = variants
683				.iter()
684				.map(|data| trait_.build_body(any_bound, traits, trait_, data))
685				.collect();
686
687			trait_.build_signature(any_bound, item, generics, traits, trait_, &body)
688		}
689	}
690}
691
692/// Removes `derive_where` attributes from the item and all fields and variants.
693///
694/// This is necessary because Rust currently does not support helper attributes
695/// for attribute proc-macros and therefore doesn't automatically remove them.
696fn input_without_derive_where_attributes(mut input: DeriveInput) -> DeriveInput {
697	use syn::Data;
698
699	let DeriveInput { data, attrs, .. } = &mut input;
700
701	/// Remove all `derive_where` attributes.
702	fn remove_derive_where(attrs: &mut Vec<Attribute>) {
703		attrs.retain(|attr| !attr.path().is_ident(DERIVE_WHERE))
704	}
705
706	/// Remove all `derive_where` attributes from [`FieldsNamed`].
707	fn remove_derive_where_from_fields_named(fields: &mut FieldsNamed) {
708		let FieldsNamed { named, .. } = fields;
709		named
710			.iter_mut()
711			.for_each(|field| remove_derive_where(&mut field.attrs))
712	}
713
714	/// Remove all `derive_where` attributes from [`Fields`].
715	fn remove_derive_where_from_fields(fields: &mut Fields) {
716		match fields {
717			Fields::Named(fields) => remove_derive_where_from_fields_named(fields),
718			Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => unnamed
719				.iter_mut()
720				.for_each(|field| remove_derive_where(&mut field.attrs)),
721			Fields::Unit => (),
722		}
723	}
724
725	// Remove `derive_where` attributes from the item.
726	remove_derive_where(attrs);
727
728	// Remove `derive_where` attributes from variants or fields.
729	match data {
730		Data::Struct(DataStruct { fields, .. }) => remove_derive_where_from_fields(fields),
731		Data::Enum(DataEnum { variants, .. }) => {
732			variants
733				.iter_mut()
734				.for_each(|Variant { attrs, fields, .. }| {
735					remove_derive_where(attrs);
736					remove_derive_where_from_fields(fields)
737				})
738		}
739		Data::Union(DataUnion { fields, .. }) => remove_derive_where_from_fields_named(fields),
740	}
741
742	input
743}