1use serde::{ser::SerializeMap, Serialize, Serializer};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum AbiType {
5 UInt(usize),
6 Int(usize),
7 Address,
8 Bool,
9 Function,
10 Array { elem_ty: Box<AbiType>, len: usize },
11 Tuple(Vec<AbiTupleField>),
12 Bytes,
13 String,
14}
15
16impl AbiType {
17 pub fn selector_type_name(&self) -> String {
18 match self {
19 Self::UInt(bits) => format!("uint{bits}"),
20 Self::Int(bits) => format!("int{bits}"),
21 Self::Address => "address".to_string(),
22 Self::Bool => "bool".to_string(),
23 Self::Function => "function".to_string(),
24 Self::Array { elem_ty, len } => {
25 if elem_ty.as_ref() == &AbiType::UInt(8) {
26 "bytes".to_string()
27 } else {
28 format!("{}[{}]", elem_ty.selector_type_name(), len)
29 }
30 }
31 Self::Tuple(elems) => format!(
32 "({})",
33 elems
34 .iter()
35 .map(|component| component.ty.selector_type_name())
36 .collect::<Vec<_>>()
37 .join(",")
38 ),
39
40 Self::Bytes => "bytes".to_string(),
41 Self::String => "string".to_string(),
42 }
43 }
44
45 pub fn abi_type_name(&self) -> String {
46 match self {
47 Self::Tuple(_) => "tuple".to_string(),
48 Self::Array { elem_ty, len } => {
49 if elem_ty.as_ref() == &AbiType::UInt(8) {
50 "bytes".to_string()
51 } else {
52 format!("{}[{}]", elem_ty.abi_type_name(), len)
53 }
54 }
55 _ => self.selector_type_name(),
56 }
57 }
58
59 pub fn header_size(&self) -> usize {
60 match self {
61 Self::UInt(_) | Self::Int(_) | Self::Address | Self::Bool | Self::Function => 32,
62
63 Self::Array { elem_ty, len } if elem_ty.is_static() => elem_ty.header_size() * len,
64 Self::Array { .. } => 32,
65
66 Self::Tuple(fields) if self.is_static() => fields
67 .iter()
68 .fold(0, |acc, field| field.ty.header_size() + acc),
69 Self::Tuple(_) => 32,
70
71 Self::Bytes | Self::String => 32,
72 }
73 }
74
75 pub fn is_primitive(&self) -> bool {
76 matches! {
77 self,
78 Self::UInt(_) | Self::Int(_) | Self::Address | Self::Bool
79 }
80 }
81
82 pub fn is_bytes(&self) -> bool {
83 matches! {
84 self,
85 Self::Bytes,
86 }
87 }
88
89 pub fn is_string(&self) -> bool {
90 matches! {
91 self,
92 Self::String
93 }
94 }
95
96 pub fn is_static(&self) -> bool {
97 match self {
98 Self::UInt(_) | Self::Int(_) | Self::Address | Self::Bool | Self::Function => true,
99 Self::Array { elem_ty, .. } => elem_ty.is_static(),
100 Self::Tuple(fields) => fields.iter().all(|field| field.ty.is_static()),
101 Self::Bytes | Self::String => false,
102 }
103 }
104
105 pub fn size(&self) -> Option<usize> {
107 match self {
108 Self::UInt(_) | Self::Int(_) | Self::Address | Self::Bool => Some(32),
109 Self::Function => Some(24),
110 Self::Array { elem_ty, len } => Some(elem_ty.size()? * len),
111 Self::Tuple(fields) => {
112 let mut size = 0;
113 for field in fields.iter() {
114 size += field.ty.size()?;
115 }
116 Some(size)
117 }
118
119 Self::Bytes | Self::String => None,
120 }
121 }
122
123 fn serialize_component<S: SerializeMap>(&self, s: &mut S) -> Result<(), S::Error> {
124 match self {
125 Self::Tuple(entry) => s.serialize_entry("components", entry),
126 Self::Array { elem_ty, .. } => elem_ty.serialize_component(s),
127 _ => Ok(()),
128 }
129 }
130}
131
132impl Serialize for AbiType {
133 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
134 let mut map = s.serialize_map(None)?;
135 let type_name = self.abi_type_name();
136
137 map.serialize_entry("type", &type_name)?;
138
139 self.serialize_component(&mut map)?;
140 map.end()
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
145pub struct AbiTupleField {
146 pub name: String,
147 #[serde(flatten)]
148 pub ty: AbiType,
149}
150
151impl AbiTupleField {
152 pub fn new(name: String, ty: impl Into<AbiType>) -> Self {
153 Self {
154 name,
155 ty: ty.into(),
156 }
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 use serde_test::{assert_ser_tokens, Token};
165
166 #[test]
167 fn primitive() {
168 let u32_ty = AbiType::UInt(32);
169 assert_ser_tokens(
170 &u32_ty,
171 &[
172 Token::Map { len: None },
173 Token::String("type"),
174 Token::String("uint32"),
175 Token::MapEnd,
176 ],
177 )
178 }
179
180 #[test]
181 fn primitive_array() {
182 let i32_ty = AbiType::Int(32);
183 let array_i32 = AbiType::Array {
184 elem_ty: i32_ty.into(),
185 len: 10,
186 };
187
188 assert_ser_tokens(
189 &array_i32,
190 &[
191 Token::Map { len: None },
192 Token::String("type"),
193 Token::String("int32[10]"),
194 Token::MapEnd,
195 ],
196 )
197 }
198
199 #[test]
200 fn tuple_array() {
201 let u16_ty = AbiType::UInt(16);
202 let bool_ty = AbiType::Bool;
203 let array_bool = AbiType::Array {
204 elem_ty: bool_ty.into(),
205 len: 16,
206 };
207
208 let field1 = AbiTupleField::new("field1".into(), u16_ty);
209 let field2 = AbiTupleField::new("field2".into(), array_bool);
210 let tuple_ty = AbiType::Tuple(vec![field1, field2]);
211
212 let tuple_array_ty = AbiType::Array {
213 elem_ty: tuple_ty.into(),
214 len: 16,
215 };
216
217 assert_ser_tokens(
218 &tuple_array_ty,
219 &[
220 Token::Map { len: None },
221 Token::String("type"),
222 Token::String("tuple[16]"),
223 Token::String("components"),
224 Token::Seq { len: Some(2) },
225 Token::Map { len: None },
227 Token::String("name"),
228 Token::String("field1"),
229 Token::String("type"),
230 Token::String("uint16"),
231 Token::MapEnd,
232 Token::Map { len: None },
234 Token::String("name"),
235 Token::String("field2"),
236 Token::String("type"),
237 Token::String("bool[16]"),
238 Token::MapEnd,
239 Token::SeqEnd,
240 Token::MapEnd,
241 ],
242 )
243 }
244
245 #[test]
246 fn simple_tuple() {
247 let u16_ty = AbiType::UInt(16);
248 let bool_ty = AbiType::Bool;
249 let bool_array_ty = AbiType::Array {
250 elem_ty: bool_ty.into(),
251 len: 16,
252 };
253
254 let field1 = AbiTupleField::new("field1".into(), u16_ty);
255 let field2 = AbiTupleField::new("field2".into(), bool_array_ty);
256 let tuple_ty = AbiType::Tuple(vec![field1, field2]);
257
258 assert_ser_tokens(
259 &tuple_ty,
260 &[
261 Token::Map { len: None },
262 Token::String("type"),
263 Token::String("tuple"),
264 Token::String("components"),
265 Token::Seq { len: Some(2) },
266 Token::Map { len: None },
268 Token::String("name"),
269 Token::String("field1"),
270 Token::String("type"),
271 Token::String("uint16"),
272 Token::MapEnd,
273 Token::Map { len: None },
275 Token::String("name"),
276 Token::String("field2"),
277 Token::String("type"),
278 Token::String("bool[16]"),
279 Token::MapEnd,
280 Token::SeqEnd,
281 Token::MapEnd,
282 ],
283 )
284 }
285
286 #[test]
287 fn complex_tuple() {
288 let u16_ty = AbiType::UInt(16);
289 let bool_ty = AbiType::Bool;
290
291 let inner_field1 = AbiTupleField::new("inner_field1".into(), u16_ty);
292 let inner_field2 = AbiTupleField::new("inner_field2".into(), bool_ty);
293 let inner_tuple_ty = AbiType::Tuple(vec![inner_field1, inner_field2]);
294
295 let inner_tuple_array_ty = AbiType::Array {
296 elem_ty: inner_tuple_ty.clone().into(),
297 len: 16,
298 };
299
300 let outer_field1 = AbiTupleField::new("outer_field1".into(), inner_tuple_array_ty);
301 let outer_field2 = AbiTupleField::new("outer_field2".into(), inner_tuple_ty);
302 let outer_tuple_ty = AbiType::Tuple(vec![outer_field1, outer_field2]);
303
304 assert_ser_tokens(
305 &outer_tuple_ty,
306 &[
307 Token::Map { len: None },
309 Token::String("type"),
310 Token::String("tuple"),
311 Token::String("components"),
313 Token::Seq { len: Some(2) },
314 Token::Map { len: None },
316 Token::String("name"),
317 Token::String("outer_field1"),
318 Token::String("type"),
319 Token::String("tuple[16]"),
320 Token::String("components"),
321 Token::Seq { len: Some(2) },
322 Token::Map { len: None },
324 Token::String("name"),
325 Token::String("inner_field1"),
326 Token::String("type"),
327 Token::String("uint16"),
328 Token::MapEnd,
329 Token::Map { len: None },
332 Token::String("name"),
333 Token::String("inner_field2"),
334 Token::String("type"),
335 Token::String("bool"),
336 Token::MapEnd,
337 Token::SeqEnd,
339 Token::MapEnd,
340 Token::Map { len: None },
343 Token::String("name"),
344 Token::String("outer_field2"),
345 Token::String("type"),
346 Token::String("tuple"),
347 Token::String("components"),
348 Token::Seq { len: Some(2) },
349 Token::Map { len: None },
351 Token::String("name"),
352 Token::String("inner_field1"),
353 Token::String("type"),
354 Token::String("uint16"),
355 Token::MapEnd,
356 Token::Map { len: None },
359 Token::String("name"),
360 Token::String("inner_field2"),
361 Token::String("type"),
362 Token::String("bool"),
363 Token::MapEnd,
364 Token::SeqEnd,
366 Token::MapEnd,
367 Token::SeqEnd,
369 Token::MapEnd,
371 ],
372 )
373 }
374}