fe_abi/
types.rs

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    /// Returns bytes size of the encoded type if the type is static.
106    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                // Field1.
226                Token::Map { len: None },
227                Token::String("name"),
228                Token::String("field1"),
229                Token::String("type"),
230                Token::String("uint16"),
231                Token::MapEnd,
232                // Field2.
233                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                // Field1.
267                Token::Map { len: None },
268                Token::String("name"),
269                Token::String("field1"),
270                Token::String("type"),
271                Token::String("uint16"),
272                Token::MapEnd,
273                // Field2.
274                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                // Outer tuple start.
308                Token::Map { len: None },
309                Token::String("type"),
310                Token::String("tuple"),
311                // Outer tuple components start.
312                Token::String("components"),
313                Token::Seq { len: Some(2) },
314                // Outer field1 start.
315                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                // Inner field1 start.
323                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                // Inner field1 end.
330                // Inner field2 start.
331                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                // Inner field2 end.
338                Token::SeqEnd,
339                Token::MapEnd,
340                // Outer field1 end.
341                // Outer field2 start.
342                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                // Inner field1 start.
350                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                // Inner field1 end.
357                // Inner field2 start.
358                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                // Inner field2 end.
365                Token::SeqEnd,
366                Token::MapEnd,
367                // Outer field2 end.
368                Token::SeqEnd,
369                // Outer tuple components end.
370                Token::MapEnd,
371            ],
372        )
373    }
374}