is_same_derive/
lib.rs

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}