syn_solidity/type/
array.rs1use crate::{Expr, Lit, LitNumber, Spanned, Type};
2use proc_macro2::Span;
3use std::{
4 fmt,
5 hash::{Hash, Hasher},
6 num::NonZeroUsize,
7};
8use syn::{
9 bracketed,
10 parse::{discouraged::Speculative, Parse, ParseStream},
11 token::Bracket,
12 Result,
13};
14
15#[derive(Clone)]
17pub struct TypeArray {
18 pub ty: Box<Type>,
19 pub bracket_token: Bracket,
20 pub size: Option<Box<Expr>>,
21}
22
23impl PartialEq for TypeArray {
24 fn eq(&self, other: &Self) -> bool {
25 self.ty == other.ty && self.size() == other.size()
26 }
27}
28
29impl Eq for TypeArray {}
30
31impl Hash for TypeArray {
32 fn hash<H: Hasher>(&self, state: &mut H) {
33 self.ty.hash(state);
34 self.size().hash(state);
35 }
36}
37
38impl fmt::Display for TypeArray {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 self.ty.fmt(f)?;
41 f.write_str("[")?;
42 if let Some(s) = self.size_lit() {
43 f.write_str(s.base10_digits())?;
44 }
45 f.write_str("]")
46 }
47}
48
49impl fmt::Debug for TypeArray {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.debug_tuple("TypeArray").field(&self.ty).field(&self.size()).finish()
52 }
53}
54
55impl Parse for TypeArray {
56 fn parse(input: ParseStream<'_>) -> Result<Self> {
57 let ty = input.parse()?;
58 Self::parse_nested(Box::new(ty), input)
59 }
60}
61
62impl Spanned for TypeArray {
63 fn span(&self) -> Span {
64 let span = self.ty.span();
65 span.join(self.bracket_token.span.join()).unwrap_or(span)
66 }
67
68 fn set_span(&mut self, span: Span) {
69 self.ty.set_span(span);
70 self.bracket_token = Bracket(span);
71 if let Some(size) = &mut self.size {
72 size.set_span(span);
73 }
74 }
75}
76
77impl TypeArray {
78 pub fn size(&self) -> Option<usize> {
80 self.size_lit().map(|s| s.base10_parse().unwrap())
81 }
82
83 pub fn size_lit(&self) -> Option<&LitNumber> {
85 self.size.as_ref().map(|s| match &**s {
86 Expr::Lit(Lit::Number(n)) => n,
87 _ => panic!("unevaluated literal in array size"),
88 })
89 }
90
91 pub fn is_abi_dynamic(&self) -> bool {
93 match self.size {
94 Some(_) => self.ty.is_abi_dynamic(),
95 None => true,
96 }
97 }
98
99 pub fn parse_nested(ty: Box<Type>, input: ParseStream<'_>) -> Result<Self> {
101 let content;
102 Ok(Self {
103 ty,
104 bracket_token: bracketed!(content in input),
105 size: {
106 if content.is_empty() {
107 None
108 } else {
109 let fork = content.fork();
110 let sz = match fork.parse::<syn::LitInt>() {
111 Ok(lit) => lit,
112 Err(e) => {
113 return Err(match fork.parse::<Expr>() {
114 Ok(_) => syn::Error::new(
115 e.span(),
116 "generic expressions are not supported in array type sizes",
117 ),
118 Err(e) => e,
119 })
120 }
121 };
122 content.advance_to(&fork);
123 sz.base10_parse::<NonZeroUsize>()?;
125 Some(Box::new(Expr::Lit(Lit::Number(LitNumber::Int(sz)))))
126 }
127 },
128 })
129 }
130}