1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#[proc_macro_derive(Event, attributes(indexed))] pub fn event_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as syn::DeriveInput); let event_name = &input.ident; let indexed_fields = match input.data { syn::Data::Struct(syn::DataStruct { fields, .. }) => fields .iter() .filter(|f| f.attrs.iter().any(|attr| attr.path.is_ident("indexed"))) .cloned() .collect::<Vec<_>>(), _ => { err!(input: "An `Event` must be a non-tuple struct."); return proc_macro::TokenStream::new(); } }; let impl_wrapper_ident = format_ident!("_IMPL_EVENT_FOR_{}", event_name); let indexed_field_idents = indexed_fields.iter().map(|f| f.ident.as_ref().unwrap()); let event_name_topic = keccak_key(&event_name); let num_topics = indexed_fields.len() + 1; proc_macro::TokenStream::from(quote! { const #impl_wrapper_ident: () = { use mantle::reexports::*; impl mantle::exe::Event for #event_name { fn emit(&self) { let hashes = vec![ #(tiny_keccak::keccak256(&serde_cbor::to_vec(&self.#indexed_field_idents).unwrap())),* ]; let mut topics: Vec<&[u8]> = Vec::with_capacity(#num_topics); topics.push(&#event_name_topic); topics.append(&mut hashes.iter().map(<_>::as_ref).collect()); mantle::backend::emit(&topics, &serde_cbor::to_vec(self).unwrap()); } } }; }) }