oasis_macros/
event_derive.rs1#[proc_macro_derive(Event, attributes(indexed))]
2pub fn event_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
3 let input = parse_macro_input!(input as syn::DeriveInput);
4 let event_name = &input.ident;
5 let generics = &input.generics;
6
7 let fields = match input.data {
8 syn::Data::Struct(syn::DataStruct { fields, .. }) => fields,
9 _ => {
10 err!(input: "an `Event` must be a struct.");
11 return proc_macro::TokenStream::new();
12 }
13 };
14
15 fn is_indexed(field: &syn::Field) -> bool {
16 field.attrs.iter().any(|attr| attr.path.is_ident("indexed"))
17 }
18
19 let indexed_field_idents = match fields {
20 syn::Fields::Named(syn::FieldsNamed { named, .. }) => named
21 .iter()
22 .filter_map(|field| {
23 if is_indexed(field) {
24 Some(syn::Member::Named(field.ident.as_ref().unwrap().clone()))
25 } else {
26 None
27 }
28 })
29 .collect(),
30 syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed, .. }) => unnamed
31 .iter()
32 .enumerate()
33 .filter_map(|(i, field)| {
34 if is_indexed(field) {
35 Some(syn::Member::Unnamed(syn::Index {
36 index: i as u32,
37 span: proc_macro2::Span::call_site(),
38 }))
39 } else {
40 None
41 }
42 })
43 .collect(),
44 syn::Fields::Unit => Vec::new(),
45 };
46
47 let impl_wrapper_ident = format_ident!("_IMPL_EVENT_FOR_{}", event_name);
48
49 proc_macro::TokenStream::from(quote! {
50 #[allow(non_upper_case_globals)]
51 const #impl_wrapper_ident: () = {
52 use oasis_std::{abi::*, exe::{encode_event_topic, Event}};
53
54 impl#generics Event for #event_name#generics {
55 fn emit(&self) {
56 let topics: &[[u8; 32]] = &[
57 encode_event_topic(&stringify!(#event_name)),
58 #(encode_event_topic(&self.#indexed_field_idents)),*
59 ];
60 let topic_refs: Vec<&[u8]> = topics.iter().map(|t| t.as_ref()).collect();
61 oasis_std::backend::emit(&topic_refs, &self.try_to_vec().unwrap());
62 }
63 }
64 };
65 })
66}