syn_solidity/item/
event.rsuse crate::{
kw, utils::DebugPunctuated, ParameterList, SolIdent, SolPath, Spanned, Type,
VariableDeclaration,
};
use proc_macro2::Span;
use std::fmt;
use syn::{
parenthesized,
parse::{Parse, ParseStream},
punctuated::Punctuated,
token::Paren,
Attribute, Error, Result, Token,
};
#[derive(Clone)]
pub struct ItemEvent {
pub attrs: Vec<Attribute>,
pub event_token: kw::event,
pub name: SolIdent,
pub paren_token: Paren,
pub parameters: Punctuated<EventParameter, Token![,]>,
pub anonymous: Option<kw::anonymous>,
pub semi_token: Token![;],
}
impl fmt::Display for ItemEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "event {}(", self.name)?;
for (i, param) in self.parameters.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
param.fmt(f)?;
}
f.write_str(")")?;
if self.is_anonymous() {
f.write_str(" anonymous")?;
}
f.write_str(";")
}
}
impl fmt::Debug for ItemEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ItemEvent")
.field("attrs", &self.attrs)
.field("name", &self.name)
.field("arguments", DebugPunctuated::new(&self.parameters))
.field("anonymous", &self.is_anonymous())
.finish()
}
}
impl Parse for ItemEvent {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let content;
Ok(Self {
attrs: input.call(Attribute::parse_outer)?,
event_token: input.parse()?,
name: input.parse()?,
paren_token: parenthesized!(content in input),
parameters: content.parse_terminated(EventParameter::parse, Token![,])?,
anonymous: input.parse()?,
semi_token: input.parse()?,
})
}
}
impl Spanned for ItemEvent {
fn span(&self) -> Span {
self.name.span()
}
fn set_span(&mut self, span: Span) {
self.name.set_span(span);
}
}
impl ItemEvent {
#[inline]
pub const fn is_anonymous(&self) -> bool {
self.anonymous.is_some()
}
#[inline]
pub fn max_indexed(&self) -> usize {
if self.is_anonymous() {
4
} else {
3
}
}
#[inline]
pub fn exceeds_max_indexed(&self) -> bool {
self.indexed_params().count() > self.max_indexed()
}
pub fn assert_valid(&self) -> Result<()> {
if self.exceeds_max_indexed() {
let msg = if self.is_anonymous() {
"more than 4 indexed arguments for anonymous event"
} else {
"more than 3 indexed arguments for event"
};
Err(Error::new(self.span(), msg))
} else {
Ok(())
}
}
pub fn params(&self) -> ParameterList {
self.parameters.iter().map(EventParameter::as_param).collect()
}
pub fn param_types(
&self,
) -> impl ExactSizeIterator<Item = &Type> + DoubleEndedIterator + Clone {
self.parameters.iter().map(|var| &var.ty)
}
pub fn param_types_mut(
&mut self,
) -> impl ExactSizeIterator<Item = &mut Type> + DoubleEndedIterator {
self.parameters.iter_mut().map(|var| &mut var.ty)
}
pub fn param_types_and_names(
&self,
) -> impl ExactSizeIterator<Item = (&Type, Option<&SolIdent>)> + DoubleEndedIterator {
self.parameters.iter().map(|p| (&p.ty, p.name.as_ref()))
}
pub fn param_type_strings(
&self,
) -> impl ExactSizeIterator<Item = String> + DoubleEndedIterator + Clone + '_ {
self.parameters.iter().map(|var| var.ty.to_string())
}
pub fn non_indexed_params(&self) -> impl Iterator<Item = &EventParameter> {
self.parameters.iter().filter(|p| !p.is_indexed())
}
pub fn indexed_params(&self) -> impl Iterator<Item = &EventParameter> {
self.parameters.iter().filter(|p| p.is_indexed())
}
pub fn as_type(&self) -> Type {
let mut ty = Type::Tuple(self.parameters.iter().map(|arg| arg.ty.clone()).collect());
ty.set_span(self.span());
ty
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct EventParameter {
pub attrs: Vec<Attribute>,
pub ty: Type,
pub indexed: Option<kw::indexed>,
pub name: Option<SolIdent>,
}
impl fmt::Display for EventParameter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.ty.fmt(f)?;
if self.indexed.is_some() {
f.write_str(" indexed")?;
}
if let Some(name) = &self.name {
write!(f, " {name}")?;
}
Ok(())
}
}
impl fmt::Debug for EventParameter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventParameter")
.field("attrs", &self.attrs)
.field("ty", &self.ty)
.field("indexed", &self.indexed.is_some())
.field("name", &self.name)
.finish()
}
}
impl Parse for EventParameter {
fn parse(input: ParseStream<'_>) -> Result<Self> {
Ok(Self {
attrs: input.call(Attribute::parse_outer)?,
ty: input.parse()?,
indexed: input.parse()?,
name: if SolIdent::peek_any(input) { Some(input.parse()?) } else { None },
})
}
}
impl Spanned for EventParameter {
fn span(&self) -> Span {
let span = self.ty.span();
self.name.as_ref().and_then(|name| span.join(name.span())).unwrap_or(span)
}
fn set_span(&mut self, span: Span) {
self.ty.set_span(span);
if let Some(kw) = &mut self.indexed {
kw.span = span;
}
if let Some(name) = &mut self.name {
name.set_span(span);
}
}
}
impl EventParameter {
pub fn as_param(&self) -> VariableDeclaration {
VariableDeclaration {
attrs: self.attrs.clone(),
name: self.name.clone(),
storage: None,
ty: self.ty.clone(),
}
}
#[inline]
pub const fn is_indexed(&self) -> bool {
self.indexed.is_some()
}
pub const fn is_non_indexed(&self) -> bool {
self.indexed.is_none()
}
pub fn indexed_as_hash(&self, custom_is_value_type: impl Fn(&SolPath) -> bool) -> bool {
self.is_indexed() && !self.ty.is_value_type(custom_is_value_type)
}
}