1use crate::{
2 Error, Input, Result, TypeStem, new_input,
3 utils::{spanned, str_parser},
4};
5use alloc::vec::Vec;
6use core::num::NonZeroUsize;
7use winnow::{
8 ModalResult, Parser,
9 ascii::digit0,
10 combinator::{cut_err, delimited, repeat, trace},
11 error::{ErrMode, FromExternalError},
12};
13
14#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct TypeSpecifier<'a> {
61 pub span: &'a str,
63 pub stem: TypeStem<'a>,
65 pub sizes: Vec<Option<NonZeroUsize>>,
69}
70
71impl<'a> TryFrom<&'a str> for TypeSpecifier<'a> {
72 type Error = Error;
73
74 #[inline]
75 fn try_from(s: &'a str) -> Result<Self> {
76 Self::parse(s)
77 }
78}
79
80impl AsRef<str> for TypeSpecifier<'_> {
81 #[inline]
82 fn as_ref(&self) -> &str {
83 self.span()
84 }
85}
86
87impl<'a> TypeSpecifier<'a> {
88 #[inline]
90 pub fn parse(s: &'a str) -> Result<Self> {
91 Self::parser.parse(new_input(s)).map_err(Error::parser)
92 }
93
94 pub(crate) fn parser(input: &mut Input<'a>) -> ModalResult<Self> {
96 trace(
97 "TypeSpecifier",
98 spanned(|input: &mut Input<'a>| {
99 let stem = TypeStem::parser(input)?;
100 let sizes = if input.starts_with('[') {
101 repeat(
102 1..,
103 delimited(str_parser("["), array_size_parser, cut_err(str_parser("]"))),
104 )
105 .parse_next(input)?
106 } else {
107 Vec::new()
108 };
109 Ok((stem, sizes))
110 }),
111 )
112 .parse_next(input)
113 .map(|(span, (stem, sizes))| Self { span, stem, sizes })
114 }
115
116 #[cfg(feature = "eip712")]
120 #[inline]
121 pub fn parse_eip712(s: &'a str) -> Result<Self> {
122 Self::eip712_parser.parse(new_input(s)).map_err(Error::parser)
123 }
124
125 #[cfg(feature = "eip712")]
127 pub(crate) fn eip712_parser(input: &mut Input<'a>) -> ModalResult<Self> {
128 trace(
129 "TypeSpecifier::eip712",
130 spanned(|input: &mut Input<'a>| {
131 let stem = TypeStem::eip712_parser(input)?;
132 let sizes = if input.starts_with('[') {
133 repeat(
134 1..,
135 delimited(str_parser("["), array_size_parser, cut_err(str_parser("]"))),
136 )
137 .parse_next(input)?
138 } else {
139 Vec::new()
140 };
141 Ok((stem, sizes))
142 }),
143 )
144 .parse_next(input)
145 .map(|(span, (stem, sizes))| Self { span, stem, sizes })
146 }
147
148 #[inline]
150 pub const fn span(&self) -> &'a str {
151 self.span
152 }
153
154 #[inline]
156 pub const fn stem(&self) -> &TypeStem<'_> {
157 &self.stem
158 }
159
160 #[inline]
162 pub fn try_basic_solidity(&self) -> Result<()> {
163 self.stem.try_basic_solidity()
164 }
165
166 #[inline]
168 pub fn is_array(&self) -> bool {
169 !self.sizes.is_empty()
170 }
171}
172
173fn array_size_parser(input: &mut Input<'_>) -> ModalResult<Option<NonZeroUsize>> {
174 let digits = digit0(input)?;
175 if digits.is_empty() {
176 return Ok(None);
177 }
178 digits.parse().map(Some).map_err(|e| ErrMode::from_external_error(input, e))
179}
180
181#[cfg(test)]
182mod test {
183 use super::*;
184 use crate::TupleSpecifier;
185 use alloc::string::ToString;
186
187 #[track_caller]
188 fn assert_error_contains(e: &Error, s: &str) {
189 if cfg!(feature = "std") {
190 let es = e.to_string();
191 assert!(es.contains(s), "{s:?} not in {es:?}");
192 }
193 }
194
195 #[test]
196 fn parse_test() {
197 assert_eq!(
198 TypeSpecifier::parse("uint"),
199 Ok(TypeSpecifier {
200 span: "uint",
201 stem: TypeStem::parse("uint256").unwrap(),
202 sizes: vec![],
203 })
204 );
205
206 assert_eq!(
207 TypeSpecifier::parse("uint256"),
208 Ok(TypeSpecifier {
209 span: "uint256",
210 stem: TypeStem::parse("uint256").unwrap(),
211 sizes: vec![],
212 })
213 );
214
215 assert_eq!(
216 TypeSpecifier::parse("uint256[2]"),
217 Ok(TypeSpecifier {
218 span: "uint256[2]",
219 stem: TypeStem::parse("uint256").unwrap(),
220 sizes: vec![NonZeroUsize::new(2)],
221 })
222 );
223
224 assert_eq!(
225 TypeSpecifier::parse("uint256[2][]"),
226 Ok(TypeSpecifier {
227 span: "uint256[2][]",
228 stem: TypeStem::parse("uint256").unwrap(),
229 sizes: vec![NonZeroUsize::new(2), None],
230 })
231 );
232
233 assert_eq!(
234 TypeSpecifier::parse("(uint256,uint256)"),
235 Ok(TypeSpecifier {
236 span: "(uint256,uint256)",
237 stem: TypeStem::Tuple(TupleSpecifier::parse("(uint256,uint256)").unwrap()),
238 sizes: vec![],
239 })
240 );
241
242 assert_eq!(
243 TypeSpecifier::parse("(uint256,uint256)[2]"),
244 Ok(TypeSpecifier {
245 span: "(uint256,uint256)[2]",
246 stem: TypeStem::Tuple(TupleSpecifier::parse("(uint256,uint256)").unwrap()),
247 sizes: vec![NonZeroUsize::new(2)],
248 })
249 );
250
251 assert_eq!(
252 TypeSpecifier::parse("MyStruct"),
253 Ok(TypeSpecifier {
254 span: "MyStruct",
255 stem: TypeStem::parse("MyStruct").unwrap(),
256 sizes: vec![],
257 })
258 );
259
260 assert_eq!(
261 TypeSpecifier::parse("MyStruct[2]"),
262 Ok(TypeSpecifier {
263 span: "MyStruct[2]",
264 stem: TypeStem::parse("MyStruct").unwrap(),
265 sizes: vec![NonZeroUsize::new(2)],
266 })
267 );
268 }
269
270 #[test]
271 fn sizes() {
272 TypeSpecifier::parse("a[").unwrap_err();
273 TypeSpecifier::parse("a[][").unwrap_err();
274
275 assert_eq!(
276 TypeSpecifier::parse("a[]"),
277 Ok(TypeSpecifier {
278 span: "a[]",
279 stem: TypeStem::parse("a").unwrap(),
280 sizes: vec![None],
281 }),
282 );
283
284 assert_eq!(
285 TypeSpecifier::parse("a[1]"),
286 Ok(TypeSpecifier {
287 span: "a[1]",
288 stem: TypeStem::parse("a").unwrap(),
289 sizes: vec![NonZeroUsize::new(1)],
290 }),
291 );
292
293 let e = TypeSpecifier::parse("a[0]").unwrap_err();
294 assert_error_contains(&e, "number would be zero for non-zero type");
295 TypeSpecifier::parse("a[x]").unwrap_err();
296
297 TypeSpecifier::parse("a[ ]").unwrap_err();
298 TypeSpecifier::parse("a[ ]").unwrap_err();
299 TypeSpecifier::parse("a[ 0]").unwrap_err();
300 TypeSpecifier::parse("a[0 ]").unwrap_err();
301
302 TypeSpecifier::parse("a[a]").unwrap_err();
303 TypeSpecifier::parse("a[ a]").unwrap_err();
304 TypeSpecifier::parse("a[a ]").unwrap_err();
305
306 TypeSpecifier::parse("a[ 1]").unwrap_err();
307 TypeSpecifier::parse("a[1 ]").unwrap_err();
308
309 TypeSpecifier::parse(&format!("a[{}]", usize::MAX)).unwrap();
310 let e = TypeSpecifier::parse(&format!("a[{}0]", usize::MAX)).unwrap_err();
311 assert_error_contains(&e, "number too large to fit in target type");
312 }
313
314 #[test]
315 fn try_basic_solidity() {
316 assert_eq!(TypeSpecifier::parse("uint").unwrap().try_basic_solidity(), Ok(()));
317 assert_eq!(TypeSpecifier::parse("int").unwrap().try_basic_solidity(), Ok(()));
318 assert_eq!(TypeSpecifier::parse("uint256").unwrap().try_basic_solidity(), Ok(()));
319 assert_eq!(TypeSpecifier::parse("uint256[]").unwrap().try_basic_solidity(), Ok(()));
320 assert_eq!(TypeSpecifier::parse("(uint256,uint256)").unwrap().try_basic_solidity(), Ok(()));
321 assert_eq!(
322 TypeSpecifier::parse("(uint256,uint256)[2]").unwrap().try_basic_solidity(),
323 Ok(())
324 );
325 assert_eq!(
326 TypeSpecifier::parse("tuple(uint256,uint256)").unwrap().try_basic_solidity(),
327 Ok(())
328 );
329 assert_eq!(
330 TypeSpecifier::parse("tuple(address,bytes,(bool,(string,uint256)[][3]))[2]")
331 .unwrap()
332 .try_basic_solidity(),
333 Ok(())
334 );
335 }
336
337 #[test]
338 fn not_basic_solidity() {
339 assert_eq!(
340 TypeSpecifier::parse("MyStruct").unwrap().try_basic_solidity(),
341 Err(Error::invalid_type_string("MyStruct"))
342 );
343 }
344
345 #[test]
346 fn parse_type_specifier_colon() {
347 let _spec = TypeSpecifier::parse("Test:Message").unwrap_err();
349 }
350}