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