syn_solidity/item/
event.rs1use crate::{
2 ParameterList, SolIdent, SolPath, Spanned, Type, VariableDeclaration, kw,
3 utils::DebugPunctuated,
4};
5use proc_macro2::Span;
6use std::fmt;
7use syn::{
8 Attribute, Error, Result, Token, parenthesized,
9 parse::{Parse, ParseStream},
10 punctuated::Punctuated,
11 token::Paren,
12};
13
14#[derive(Clone)]
15pub struct ItemEvent {
16 pub attrs: Vec<Attribute>,
17 pub event_token: kw::event,
18 pub name: SolIdent,
19 pub paren_token: Paren,
20 pub parameters: Punctuated<EventParameter, Token![,]>,
21 pub anonymous: Option<kw::anonymous>,
22 pub semi_token: Token![;],
23}
24
25impl fmt::Display for ItemEvent {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(f, "event {}(", self.name)?;
28 for (i, param) in self.parameters.iter().enumerate() {
29 if i > 0 {
30 write!(f, ", ")?;
31 }
32 param.fmt(f)?;
33 }
34 f.write_str(")")?;
35 if self.is_anonymous() {
36 f.write_str(" anonymous")?;
37 }
38 f.write_str(";")
39 }
40}
41
42impl fmt::Debug for ItemEvent {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.debug_struct("ItemEvent")
45 .field("attrs", &self.attrs)
46 .field("name", &self.name)
47 .field("arguments", DebugPunctuated::new(&self.parameters))
48 .field("anonymous", &self.is_anonymous())
49 .finish()
50 }
51}
52
53impl Parse for ItemEvent {
54 fn parse(input: ParseStream<'_>) -> Result<Self> {
55 let content;
56 Ok(Self {
57 attrs: input.call(Attribute::parse_outer)?,
58 event_token: input.parse()?,
59 name: input.parse()?,
60 paren_token: parenthesized!(content in input),
61 parameters: content.parse_terminated(EventParameter::parse, Token![,])?,
62 anonymous: input.parse()?,
63 semi_token: input.parse()?,
64 })
65 }
66}
67
68impl Spanned for ItemEvent {
69 fn span(&self) -> Span {
70 self.name.span()
71 }
72
73 fn set_span(&mut self, span: Span) {
74 self.name.set_span(span);
75 }
76}
77
78impl ItemEvent {
79 #[inline]
81 pub const fn is_anonymous(&self) -> bool {
82 self.anonymous.is_some()
83 }
84
85 #[inline]
89 pub fn max_indexed(&self) -> usize {
90 if self.is_anonymous() { 4 } else { 3 }
91 }
92
93 #[inline]
98 pub fn exceeds_max_indexed(&self) -> bool {
99 self.indexed_params().count() > self.max_indexed()
100 }
101
102 pub fn assert_valid(&self) -> Result<()> {
104 if self.exceeds_max_indexed() {
105 let msg = if self.is_anonymous() {
106 "more than 4 indexed arguments for anonymous event"
107 } else {
108 "more than 3 indexed arguments for event"
109 };
110 Err(Error::new(self.span(), msg))
111 } else {
112 Ok(())
113 }
114 }
115
116 pub fn params(&self) -> ParameterList {
117 self.parameters.iter().map(EventParameter::as_param).collect()
118 }
119
120 pub fn param_types(
121 &self,
122 ) -> impl ExactSizeIterator<Item = &Type> + DoubleEndedIterator + Clone {
123 self.parameters.iter().map(|var| &var.ty)
124 }
125
126 pub fn param_types_mut(
127 &mut self,
128 ) -> impl ExactSizeIterator<Item = &mut Type> + DoubleEndedIterator {
129 self.parameters.iter_mut().map(|var| &mut var.ty)
130 }
131
132 pub fn param_types_and_names(
133 &self,
134 ) -> impl ExactSizeIterator<Item = (&Type, Option<&SolIdent>)> + DoubleEndedIterator {
135 self.parameters.iter().map(|p| (&p.ty, p.name.as_ref()))
136 }
137
138 pub fn param_type_strings(
139 &self,
140 ) -> impl ExactSizeIterator<Item = String> + DoubleEndedIterator + Clone + '_ {
141 self.parameters.iter().map(|var| var.ty.to_string())
142 }
143
144 pub fn non_indexed_params(&self) -> impl Iterator<Item = &EventParameter> {
145 self.parameters.iter().filter(|p| !p.is_indexed())
146 }
147
148 pub fn indexed_params(&self) -> impl Iterator<Item = &EventParameter> {
149 self.parameters.iter().filter(|p| p.is_indexed())
150 }
151
152 pub fn as_type(&self) -> Type {
153 let mut ty = Type::Tuple(self.parameters.iter().map(|arg| arg.ty.clone()).collect());
154 ty.set_span(self.span());
155 ty
156 }
157}
158
159#[derive(Clone, PartialEq, Eq, Hash)]
163pub struct EventParameter {
164 pub attrs: Vec<Attribute>,
165 pub ty: Type,
166 pub indexed: Option<kw::indexed>,
167 pub name: Option<SolIdent>,
168}
169
170impl fmt::Display for EventParameter {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 self.ty.fmt(f)?;
173 if self.indexed.is_some() {
174 f.write_str(" indexed")?;
175 }
176 if let Some(name) = &self.name {
177 write!(f, " {name}")?;
178 }
179 Ok(())
180 }
181}
182
183impl fmt::Debug for EventParameter {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 f.debug_struct("EventParameter")
186 .field("attrs", &self.attrs)
187 .field("ty", &self.ty)
188 .field("indexed", &self.indexed.is_some())
189 .field("name", &self.name)
190 .finish()
191 }
192}
193
194impl Parse for EventParameter {
195 fn parse(input: ParseStream<'_>) -> Result<Self> {
196 Ok(Self {
197 attrs: input.call(Attribute::parse_outer)?,
198 ty: input.parse()?,
199 indexed: input.parse()?,
200 name: if SolIdent::peek_any(input) { Some(input.parse()?) } else { None },
201 })
202 }
203}
204
205impl Spanned for EventParameter {
206 fn span(&self) -> Span {
208 let span = self.ty.span();
209 self.name.as_ref().and_then(|name| span.join(name.span())).unwrap_or(span)
210 }
211
212 fn set_span(&mut self, span: Span) {
214 self.ty.set_span(span);
215 if let Some(kw) = &mut self.indexed {
216 kw.span = span;
217 }
218 if let Some(name) = &mut self.name {
219 name.set_span(span);
220 }
221 }
222}
223
224impl EventParameter {
225 pub fn as_param(&self) -> VariableDeclaration {
227 VariableDeclaration {
228 attrs: self.attrs.clone(),
229 name: self.name.clone(),
230 storage: None,
231 ty: self.ty.clone(),
232 }
233 }
234
235 #[inline]
237 pub const fn is_indexed(&self) -> bool {
238 self.indexed.is_some()
239 }
240
241 pub const fn is_non_indexed(&self) -> bool {
244 self.indexed.is_none()
245 }
246
247 pub fn indexed_as_hash(&self, custom_is_value_type: impl Fn(&SolPath) -> bool) -> bool {
255 self.is_indexed() && !self.ty.is_value_type(custom_is_value_type)
256 }
257}