Skip to main content

frozone_derive/
lib.rs

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        // TODO: handle attrs
31        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 { // fields struct may have no name (e.g. tuple structs)
40                        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    // for v in variants_names_and_freezes {
51    //     print!("variants => {}", pretty_print(&v));
52    // }
53    quote! { 1}.into()
54    // let (impl_generics, type_generics, where_clause) = generics;
55    // let generated = quote! {
56    //     impl #impl_generics frozone::Freezable for #name #type_generics #where_clause {
57    //         fn freeze() -> u64 {
58    //             use core::hash::{Hash, Hasher};
59    //
60    //             let mut hasher = core::hash::SipHasher::new();
61    //             // stringify!( [#(#fields,)*]);
62    //             [#(#variants_names_and_freezes,)*].iter().for_each(|x| {
63    //                 x.0.hash(&mut hasher);
64    //                 x.1.hash(&mut hasher);
65    //             });
66    //             hasher.finish()
67    //         }
68    //     }
69    // };
70    // let g: proc_macro2::TokenStream = generated.into();
71    // // #[cfg(test)]
72    // // {
73    // print!("AST => {}", pretty_print(&g));
74    // g.into()
75    // // }
76    // // #[cfg(not(test))]
77    // // g
78}
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        // TODO: handle attrs (such as a future #[assume_frozen] ?)
93        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                // stringify!( [#(#fields,)*]);
106                [#(#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}