referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/no_bound/
partial_eq.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use syn::spanned::Spanned;
19
20/// Derive PartialEq but do not bound any generic.
21pub fn derive_partial_eq_no_bound(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
22	let input = syn::parse_macro_input!(input as syn::DeriveInput);
23
24	let name = &input.ident;
25	let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
26
27	let impl_ = match input.data {
28		syn::Data::Struct(struct_) => match struct_.fields {
29			syn::Fields::Named(named) => {
30				let fields = named
31					.named
32					.iter()
33					.map(|i| &i.ident)
34					.map(|i| quote::quote_spanned!(i.span() => self.#i == other.#i ));
35
36				quote::quote!( true #( && #fields )* )
37			},
38			syn::Fields::Unnamed(unnamed) => {
39				let fields = unnamed
40					.unnamed
41					.iter()
42					.enumerate()
43					.map(|(i, _)| syn::Index::from(i))
44					.map(|i| quote::quote_spanned!(i.span() => self.#i == other.#i ));
45
46				quote::quote!( true #( && #fields )* )
47			},
48			syn::Fields::Unit => {
49				quote::quote!(true)
50			},
51		},
52		syn::Data::Enum(enum_) => {
53			let variants =
54				enum_.variants.iter().map(|variant| {
55					let ident = &variant.ident;
56					match &variant.fields {
57						syn::Fields::Named(named) => {
58							let names = named.named.iter().map(|i| &i.ident);
59							let other_names = names.clone().enumerate().map(|(n, ident)| {
60								syn::Ident::new(&format!("_{}", n), ident.span())
61							});
62
63							let capture = names.clone();
64							let other_capture = names
65								.clone()
66								.zip(other_names.clone())
67								.map(|(i, other_i)| quote::quote!(#i: #other_i));
68							let eq = names.zip(other_names).map(
69								|(i, other_i)| quote::quote_spanned!(i.span() => #i == #other_i),
70							);
71							quote::quote!(
72								(
73									Self::#ident { #( #capture, )* },
74									Self::#ident { #( #other_capture, )* },
75								) => true #( && #eq )*
76							)
77						},
78						syn::Fields::Unnamed(unnamed) => {
79							let names = unnamed
80								.unnamed
81								.iter()
82								.enumerate()
83								.map(|(i, f)| syn::Ident::new(&format!("_{}", i), f.span()));
84							let other_names =
85								unnamed.unnamed.iter().enumerate().map(|(i, f)| {
86									syn::Ident::new(&format!("_{}_other", i), f.span())
87								});
88							let eq = names.clone().zip(other_names.clone()).map(
89								|(i, other_i)| quote::quote_spanned!(i.span() => #i == #other_i),
90							);
91							quote::quote!(
92								(
93									Self::#ident ( #( #names, )* ),
94									Self::#ident ( #( #other_names, )* ),
95								) => true #( && #eq )*
96							)
97						},
98						syn::Fields::Unit => quote::quote!( (Self::#ident, Self::#ident) => true ),
99					}
100				});
101
102			let mut different_variants = vec![];
103			for (i, i_variant) in enum_.variants.iter().enumerate() {
104				for (j, j_variant) in enum_.variants.iter().enumerate() {
105					if i != j {
106						let i_ident = &i_variant.ident;
107						let j_ident = &j_variant.ident;
108						different_variants.push(quote::quote!(
109							(Self::#i_ident { .. }, Self::#j_ident { .. }) => false
110						))
111					}
112				}
113			}
114
115			quote::quote!( match (self, other) {
116				#( #variants, )*
117				#( #different_variants, )*
118			})
119		},
120		syn::Data::Union(_) => {
121			let msg = "Union type not supported by `derive(PartialEqNoBound)`";
122			return syn::Error::new(input.span(), msg).to_compile_error().into()
123		},
124	};
125
126	quote::quote!(
127		const _: () = {
128			#[automatically_derived]
129			#[allow(deprecated)]
130			impl #impl_generics ::core::cmp::PartialEq for #name #ty_generics #where_clause {
131				fn eq(&self, other: &Self) -> bool {
132					#impl_
133				}
134			}
135		};
136	)
137	.into()
138}