syn_solidity/variable/
list.rs

1use crate::{SolIdent, Spanned, Type, VariableDeclaration};
2use proc_macro2::Span;
3use std::{
4    fmt,
5    ops::{Deref, DerefMut},
6};
7use syn::{
8    parse::{Parse, ParseStream},
9    punctuated::Punctuated,
10    Result, Token,
11};
12
13/// A list of comma-separated [VariableDeclaration]s.
14///
15/// Solidity reference:
16/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.parameterList>
17pub type ParameterList = Parameters<syn::token::Comma>;
18
19/// A list of semicolon-separated [VariableDeclaration]s.
20pub type FieldList = Parameters<syn::token::Semi>;
21
22/// A list of [VariableDeclaration]s, separated by `P`.
23///
24/// Currently, `P` can only be `Token![,]` or `Token![;]`.
25///
26/// It is recommended to use the type aliases where possible instead.
27#[derive(Clone, Default, PartialEq, Eq)]
28pub struct Parameters<P>(Punctuated<VariableDeclaration, P>);
29
30impl Default for &ParameterList {
31    #[inline]
32    fn default() -> Self {
33        const NEW: &ParameterList = &ParameterList::new();
34        NEW
35    }
36}
37
38impl Default for &FieldList {
39    #[inline]
40    fn default() -> Self {
41        const NEW: &FieldList = &FieldList::new();
42        NEW
43    }
44}
45
46impl<P> Deref for Parameters<P> {
47    type Target = Punctuated<VariableDeclaration, P>;
48
49    fn deref(&self) -> &Self::Target {
50        &self.0
51    }
52}
53
54impl<P> DerefMut for Parameters<P> {
55    fn deref_mut(&mut self) -> &mut Self::Target {
56        &mut self.0
57    }
58}
59
60impl fmt::Display for ParameterList {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        for (i, param) in self.iter().enumerate() {
63            if i > 0 {
64                f.write_str(", ")?;
65            }
66            param.fmt(f)?;
67        }
68        Ok(())
69    }
70}
71
72impl fmt::Display for FieldList {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        for (i, field) in self.iter().enumerate() {
75            if i > 0 {
76                f.write_str(" ")?;
77            }
78            field.fmt(f)?;
79            f.write_str(";")?;
80        }
81        Ok(())
82    }
83}
84
85impl<P> fmt::Debug for Parameters<P> {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        f.debug_list().entries(self.iter()).finish()
88    }
89}
90
91/// Parameter list
92impl Parse for ParameterList {
93    fn parse(input: ParseStream<'_>) -> Result<Self> {
94        input.parse_terminated(VariableDeclaration::parse, Token![,]).map(Self)
95    }
96}
97
98/// Struct: enforce semicolon after each field and field name.
99impl Parse for FieldList {
100    fn parse(input: ParseStream<'_>) -> Result<Self> {
101        let this = input.parse_terminated(VariableDeclaration::parse_with_name, Token![;])?;
102        if this.is_empty() {
103            Err(input.error("defining empty structs is disallowed"))
104        } else if !this.trailing_punct() {
105            Err(input.error("expected trailing semicolon"))
106        } else {
107            Ok(Self(this))
108        }
109    }
110}
111
112impl<P: Spanned> Spanned for Parameters<P> {
113    fn span(&self) -> Span {
114        self.0.span()
115    }
116
117    fn set_span(&mut self, span: Span) {
118        self.0.set_span(span);
119    }
120}
121
122impl<P> IntoIterator for Parameters<P> {
123    type IntoIter = <Punctuated<VariableDeclaration, P> as IntoIterator>::IntoIter;
124    type Item = <Self::IntoIter as Iterator>::Item;
125
126    fn into_iter(self) -> Self::IntoIter {
127        self.0.into_iter()
128    }
129}
130
131impl<'a, P> IntoIterator for &'a Parameters<P> {
132    type IntoIter = syn::punctuated::Iter<'a, VariableDeclaration>;
133    type Item = <Self::IntoIter as Iterator>::Item;
134
135    fn into_iter(self) -> Self::IntoIter {
136        self.0.iter()
137    }
138}
139
140impl<'a, P> IntoIterator for &'a mut Parameters<P> {
141    type IntoIter = syn::punctuated::IterMut<'a, VariableDeclaration>;
142    type Item = <Self::IntoIter as Iterator>::Item;
143
144    fn into_iter(self) -> Self::IntoIter {
145        self.0.iter_mut()
146    }
147}
148
149impl<P: Default> FromIterator<VariableDeclaration> for Parameters<P> {
150    fn from_iter<T: IntoIterator<Item = VariableDeclaration>>(iter: T) -> Self {
151        Self(Punctuated::from_iter(iter))
152    }
153}
154
155impl<P> Parameters<P> {
156    pub const fn new() -> Self {
157        Self(Punctuated::new())
158    }
159
160    pub fn eip712_signature(&self, mut name: String) -> String {
161        name.reserve(2 + self.len() * 32);
162        name.push('(');
163        for (i, field) in self.iter().enumerate() {
164            if i > 0 {
165                name.push(',');
166            }
167            field.fmt_eip712(&mut name).unwrap();
168        }
169        name.push(')');
170        name
171    }
172
173    pub fn names(
174        &self,
175    ) -> impl ExactSizeIterator<Item = Option<&SolIdent>> + DoubleEndedIterator + Clone {
176        self.iter().map(|var| var.name.as_ref())
177    }
178
179    pub fn types(&self) -> impl ExactSizeIterator<Item = &Type> + DoubleEndedIterator + Clone {
180        self.iter().map(|var| &var.ty)
181    }
182
183    pub fn types_mut(&mut self) -> impl ExactSizeIterator<Item = &mut Type> + DoubleEndedIterator {
184        self.iter_mut().map(|var| &mut var.ty)
185    }
186
187    pub fn types_and_names(
188        &self,
189    ) -> impl ExactSizeIterator<Item = (&Type, Option<&SolIdent>)> + DoubleEndedIterator {
190        self.iter().map(|p| (&p.ty, p.name.as_ref()))
191    }
192
193    pub fn type_strings(
194        &self,
195    ) -> impl ExactSizeIterator<Item = String> + DoubleEndedIterator + Clone + '_ {
196        self.iter().map(|var| var.ty.to_string())
197    }
198
199    #[cfg(feature = "visit")]
200    pub fn visit_types(&self, mut f: impl FnMut(&Type)) {
201        for ty in self.types() {
202            ty.visit(&mut f);
203        }
204    }
205
206    #[cfg(feature = "visit-mut")]
207    pub fn visit_types_mut(&mut self, mut f: impl FnMut(&mut Type)) {
208        for ty in self.types_mut() {
209            ty.visit_mut(&mut f);
210        }
211    }
212}