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, false)?;17 let mut indexed = false;18 for attr in &field.attrs {19 if let Ok(ident) = parse_ident_from_path(&attr.path, false) {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 if fields.iter().filter(|f| f.indexed).count() > 3 {60 return Err(syn::Error::new(61 variant.fields.span(),62 "events can have at most 4 indexed fields (1 indexed field is reserved for event signature)"63 ));64 }65 let mut selector_str = format!("{}(", name);66 for (i, arg) in fields.iter().enumerate() {67 if i != 0 {68 write!(selector_str, ",").unwrap();69 }70 write!(selector_str, "{}", arg.ty).unwrap();71 }72 selector_str.push(')');73 let selector = crate::event_selector_str(&selector_str);7475 Ok(Self {76 name: name.to_owned(),77 name_screaming,78 fields,79 selector,80 selector_str,81 })82 }8384 fn expand_serializers(&self) -> proc_macro2::TokenStream {85 let name = &self.name;86 let name_screaming = &self.name_screaming;87 let fields = self.fields.iter().map(|f| &f.name);8889 let indexed = self.fields.iter().filter(|f| f.indexed).map(|f| &f.name);90 let plain = self.fields.iter().filter(|f| !f.indexed).map(|f| &f.name);9192 quote! {93 Self::#name {#(94 #fields,95 )*} => {96 topics.push(topic::from(Self::#name_screaming));97 #(98 topics.push(#indexed.to_topic());99 )*100 #(101 #plain.abi_write(&mut writer);102 )*103 }104 }105 }106107 fn expand_consts(&self) -> proc_macro2::TokenStream {108 let name_screaming = &self.name_screaming;109 let selector_str = &self.selector_str;110 let selector = &self.selector;111112 quote! {113 #[doc = #selector_str]114 const #name_screaming: [u8; 32] = [#(115 #selector,116 )*];117 }118 }119}120121pub struct Events {122 name: Ident,123 events: Vec<Event>,124}125126impl Events {127 pub fn try_from(data: &DeriveInput) -> syn::Result<Self> {128 let name = &data.ident;129 let en = match &data.data {130 Data::Enum(en) => en,131 _ => return Err(syn::Error::new(data.span(), "expected enum")),132 };133 let mut events = Vec::new();134 for variant in &en.variants {135 events.push(Event::try_from(variant)?);136 }137 Ok(Self {138 name: name.to_owned(),139 events,140 })141 }142 pub fn expand(&self) -> proc_macro2::TokenStream {143 let name = &self.name;144145 let consts = self.events.iter().map(Event::expand_consts);146 let serializers = self.events.iter().map(Event::expand_serializers);147148 quote! {149 impl #name {150 #(151 #consts152 )*153 }154155 #[automatically_derived]156 impl ::evm_coder::events::ToLog for #name {157 fn to_log(&self, contract: address) -> ::ethereum::Log {158 use ::evm_coder::events::ToTopic;159 use ::evm_coder::abi::AbiWrite;160 let mut writer = ::evm_coder::abi::AbiWriter::new();161 let mut topics = Vec::new();162 match self {163 #(164 #serializers,165 )*166 }167 ::ethereum::Log {168 address: contract,169 topics,170 data: writer.finish(),171 }172 }173 }174 }175 }176}