1use syn::{Data, DeriveInput, Field, Fields, Ident, Variant, spanned::Spanned};2use std::fmt::Write;3use quote::quote;45use crate::{parse_ident_from_path, parse_ident_from_type, snake_ident_to_screaming};67struct EventField {8 name: Ident,9 ty: Ident,10 indexed: bool,11}1213impl EventField {14 fn try_from(field: &Field) -> syn::Result<Self> {15 let name = field.ident.as_ref().unwrap();16 let ty = parse_ident_from_type(&field.ty)?;17 let mut indexed = false;18 for attr in &field.attrs {19 if let Ok(ident) = parse_ident_from_path(&attr.path) {20 if ident == "indexed" {21 indexed = true;22 }23 }24 }25 Ok(Self {26 name: name.to_owned(),27 ty: ty.to_owned(),28 indexed,29 })30 }31}3233struct Event {34 name: Ident,35 name_screaming: Ident,36 fields: Vec<EventField>,37 selector: [u8; 32],38 selector_str: String,39}4041impl Event {42 fn try_from(variant: &Variant) -> syn::Result<Self> {43 let name = &variant.ident;44 let name_screaming = snake_ident_to_screaming(&name);4546 let named = match &variant.fields {47 Fields::Named(named) => named,48 _ => {49 return Err(syn::Error::new(50 variant.fields.span(),51 "expected named fields",52 ))53 }54 };55 let mut fields = Vec::new();56 for field in &named.named {57 fields.push(EventField::try_from(&field)?);58 }59 let mut selector_str = format!("{}(", name);60 for (i, arg) in fields.iter().enumerate() {61 if i != 0 {62 write!(selector_str, ",").unwrap();63 }64 write!(selector_str, "{}", arg.ty).unwrap();65 }66 selector_str.push(')');67 let selector = crate::event_selector_str(&selector_str);6869 Ok(Self {70 name: name.to_owned(),71 name_screaming,72 fields,73 selector,74 selector_str,75 })76 }7778 fn expand_serializers(&self) -> proc_macro2::TokenStream {79 let name = &self.name;80 let name_screaming = &self.name_screaming;81 let fields = self.fields.iter().map(|f| &f.name);8283 let indexed = self.fields.iter().filter(|f| f.indexed).map(|f| &f.name);84 let plain = self.fields.iter().filter(|f| !f.indexed).map(|f| &f.name);8586 quote! {87 Self::#name {#(88 #fields,89 )*} => {90 topics.push(topic::from(Self::#name_screaming));91 #(92 topics.push(#indexed.to_topic());93 )*94 #(95 #plain.abi_write(&mut writer);96 )*97 }98 }99 }100101 fn expand_consts(&self) -> proc_macro2::TokenStream {102 let name_screaming = &self.name_screaming;103 let selector_str = &self.selector_str;104 let selector = &self.selector;105106 quote! {107 #[doc = #selector_str]108 const #name_screaming: [u8; 32] = [#(109 #selector,110 )*];111 }112 }113}114115pub struct Events {116 name: Ident,117 events: Vec<Event>,118}119120impl Events {121 pub fn try_from(data: &DeriveInput) -> syn::Result<Self> {122 let name = &data.ident;123 let en = match &data.data {124 Data::Enum(en) => en,125 _ => return Err(syn::Error::new(data.span(), "expected enum")),126 };127 let mut events = Vec::new();128 for variant in &en.variants {129 events.push(Event::try_from(variant)?);130 }131 Ok(Self {132 name: name.to_owned(),133 events,134 })135 }136 pub fn expand(&self) -> proc_macro2::TokenStream {137 let name = &self.name;138139 let consts = self.events.iter().map(Event::expand_consts);140 let serializers = self.events.iter().map(Event::expand_serializers);141142 quote! {143 impl #name {144 #(145 #consts146 )*147 }148149 #[automatically_derived]150 impl ::evm_coder::events::ToLog for #name {151 fn to_log(&self, contract: address) -> ::ethereum::Log {152 use ::evm_coder::events::ToTopic;153 use ::evm_coder::abi::AbiWrite;154 let mut writer = ::evm_coder::abi::AbiWriter::new();155 let mut topics = Vec::new();156 match self {157 #(158 #serializers,159 )*160 }161 ::ethereum::Log {162 address: contract,163 topics,164 data: writer.finish(),165 }166 }167 }168 }169 }170}