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