1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::Data;
6use syn::DeriveInput;
7use syn::Fields;
8use syn::Index;
9
10#[proc_macro_derive(IsSame)]
11pub fn derive_is_same(input: TokenStream) -> TokenStream {
12 let input: DeriveInput = syn::parse(input).unwrap();
13 let name = &input.ident;
14
15 if let Data::Struct(data) = input.data {
16 let fields = match data.fields {
17 Fields::Named(fields) => {
18 let fields = fields.named.iter().map(|field| {
19 let name = &field.ident;
20 quote! {
21 ::is_same::IsSame::is_same(&self.#name, &other.#name)
22 }
23 });
24 quote! {
25 #(#fields)&&*
26 }
27 }
28 Fields::Unnamed(fields) => {
29 let fields = fields.unnamed.iter().enumerate().map(|(index, _field)| {
30 let index = Index::from(index);
31 quote! {
32 ::is_same::IsSame::is_same(&self.#index, &other.#index)
33 }
34 });
35 quote! {
36 #(#fields)&&*
37 }
38 }
39 Fields::Unit => quote!(true),
40 };
41 let tokens = quote! {
42 impl ::is_same::IsSame for #name {
43 fn is_same(&self, other: &Self) -> bool {
44 #fields
45 }
46 }
47 };
48 tokens.into()
49 } else {
50 panic!("derive(IsSame) can only be used with struct items")
51 }
52}