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 {
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();
enm.variants.iter_mut().for_each(|variant| {
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| {
let ident = field.ident.as_ref().unwrap().to_string();
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()
}
}