git.delta.rocks / unique-network / refs/commits / 4afa738abcfc

difftreelog

source

crates/evm-coder-macros/src/to_log.rs3.6 KiBsourcehistory
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}