1#![no_std]
2extern crate proc_macro2;
3use proc_macro::TokenStream;
4use quote::quote;
5
6#[proc_macro_derive(Freezable)]
7pub fn derive_freezable(input: TokenStream) -> TokenStream {
8 let ast: syn::DeriveInput = syn::parse_macro_input!(input);
9 let name = &ast.ident;
10 let generics = ast.generics.split_for_impl();
11
12 match ast.data {
13 syn::Data::Struct(data) => derive_freezable_struct(data, name, generics),
14 syn::Data::Enum(data) => derive_freezable_enum(data, name, generics),
15 _ => unimplemented!(),
16 }
17}
18
19fn derive_freezable_enum(
20 data: syn::DataEnum,
21 _name: &syn::Ident,
22 _generics: (
23 syn::ImplGenerics,
24 syn::TypeGenerics,
25 Option<&syn::WhereClause>,
26 ),
27) -> TokenStream {
28 let variants_names_and_freezes = data.variants.iter().map(|f| {
29 let name = &f.ident;
30 if f.discriminant.is_some() {
32 panic!("enum variants discriminants are not supported yet");
33 }
34 let variant_fields = f.fields.members();
35 quote! {
36 (stringify!(#name), {
37 let mut hasher = core::hash::SipHasher::new();
38 [#(#variant_fields,)*].iter().for_each(|x| {
39 if let Some(ident) = x.ident { x.hash(&mut hasher);
41 }
42 <x.ty as frozone::Freezable>::freeze().hash(&mut hasher);
43 });
44 hasher.finish()
45 })
46 }
47 });
48 let _ = variants_names_and_freezes;
49
50 quote! { 1}.into()
54 }
79
80fn derive_freezable_struct(
81 data: syn::DataStruct,
82 name: &syn::Ident,
83 generics: (
84 syn::ImplGenerics,
85 syn::TypeGenerics,
86 Option<&syn::WhereClause>,
87 ),
88) -> TokenStream {
89 let fields = data.fields.iter().map(|f| {
90 let name = &f.ident;
91 let ty = &f.ty;
92 quote! {
94 (stringify!(#name), <#ty as frozone::Freezable>::freeze())
95 }
96 });
97
98 let (impl_generics, type_generics, where_clause) = generics;
99 let generated = quote! {
100 impl #impl_generics frozone::Freezable for #name #type_generics #where_clause {
101 fn freeze() -> u64 {
102 use core::hash::{Hash, Hasher};
103
104 let mut hasher = core::hash::SipHasher::new();
105 [#(#fields,)*].iter().for_each(|x| {
107 x.0.hash(&mut hasher);
108 x.1.hash(&mut hasher);
109 });
110 hasher.finish()
111 }
112 }
113 };
114
115 generated.into()
116}