hpl-toolkit-derive-to-node 0.0.2

HPL attribute derive for defining a hashable
Documentation
use quote::quote;
use std::str::FromStr;
use syn::Fields;

pub struct HashableEnum(syn::ItemEnum);

impl HashableEnum {
    pub fn new(input: syn::ItemEnum) -> Self {
        Self(input)
    }
}

impl HashableEnum {
    pub fn render(self) -> proc_macro::TokenStream {
        // User Defined Schema
        let mut enm = self.0.clone();
        let enum_name = &enm.ident;

        let mut schema_fn_to_node_stream: proc_macro2::TokenStream =
            proc_macro2::TokenStream::new();

        // Iterating through User Defined Schema Variants
        enm.variants.iter_mut().for_each(|variant| {
            // User Defined Schema Variat
            let variant_name = &variant.ident;

            let mut schema_fn_to_node_variant = vec![];

            if matches!(variant.fields, Fields::Unit) {
                schema_fn_to_node_variant.push(format!(
                    "Self::{} => keccak::hashv(&[\"{}\".as_bytes()]).to_bytes(),",
                    variant_name, variant_name
                ));
            } else {
                schema_fn_to_node_variant.push(format!("Self::{}  ", variant_name));
                schema_fn_to_node_variant
                    .push(format!("keccak::hashv(&[ \"{}\".as_bytes(),", variant_name));

                if let Fields::Named(fields) = &mut variant.fields {
                    schema_fn_to_node_variant[0].push_str("{");
                    fields.named.iter_mut().for_each(|field| {
                        // User Defined Schema Variant Fields
                        let ident = field.ident.as_ref().unwrap().to_string();

                        // Generated Implementation for fn to_node() for User Defined Schema
                        schema_fn_to_node_variant[0].push_str(&format!("{}, ", ident));
                        schema_fn_to_node_variant.push(format!("{}.to_node().as_ref(),", ident));
                    });

                    schema_fn_to_node_variant[0].push_str("} => ");
                } else if let Fields::Unnamed(fields) = &mut variant.fields {
                    schema_fn_to_node_variant[0].push_str("(");

                    fields.unnamed.iter_mut().enumerate().for_each(|(i, _)| {
                        schema_fn_to_node_variant[0].push_str(&format!("item_{}, ", i));
                        schema_fn_to_node_variant.push(format!("item_{}.to_node().as_ref(),", i));
                    });

                    schema_fn_to_node_variant[0].push_str(") => ");
                }

                schema_fn_to_node_variant.push("]).to_bytes(),".to_string());
            }

            schema_fn_to_node_stream.extend::<proc_macro2::TokenStream>(
                proc_macro2::TokenStream::from_str(&schema_fn_to_node_variant.join("")).unwrap(),
            );
        });

        let stream: proc_macro2::TokenStream = quote! {
            impl ToNode for #enum_name {
                fn to_node(&self) -> [u8; 32] {
                    match self {
                        #schema_fn_to_node_stream
                        _ => {
                            panic!("Unsupported version");
                        }
                    }
                }
            }
        };

        stream.into()
    }
}