1use std::fmt::Display;
2
3use crate::{simplified_representation::primitives::SrType, FieldList};
4
5#[derive(Debug, PartialEq, Clone)]
7pub enum Type {
8 Int32,
9 Int64,
10 Int128,
11 Int256,
12
13 Uint32,
14 Uint64,
15 Uint128,
16 Uint256,
17
18 String,
19
20 BNum,
21 Map(Box<Type>, Box<Type>),
22
23 ByStr,
24 ByStrX(usize),
25 ByStr20,
26 ByStr20With {
28 type_name: String, fields: FieldList,
30 },
31
32 Bool,
34 Option(Box<Type>),
35 Pair(Box<Type>, Box<Type>),
36 List(Box<Type>),
37
38 Other(String),
39}
40
41impl Display for Type {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match self {
44 Type::Int32 => write!(f, "Int32"),
45 Type::Int64 => write!(f, "Int64"),
46 Type::Int128 => write!(f, "Int128"),
47 Type::Int256 => write!(f, "Int256"),
48 Type::Uint32 => write!(f, "Uint32"),
49 Type::Uint64 => write!(f, "Uint64"),
50 Type::Uint128 => write!(f, "Uint128"),
51 Type::Uint256 => write!(f, "Uint256"),
52 Type::String => write!(f, "String"),
53 Type::BNum => write!(f, "BNum"),
54 Type::Bool => write!(f, "Bool"),
55 Type::Map(ref k, ref v) => write!(f, "(Map {}, {})", k, v),
56 Type::Option(ref k) => write!(f, "(Option {})", k),
57 Type::List(ref k) => write!(f, "(List {})", k),
58 Type::Pair(ref k, ref v) => write!(f, "(Pair {} {})", k, v),
59 Type::ByStr => write!(f, "ByStr"),
60 Type::ByStrX(n) => write!(f, "ByStr{}", n),
61 Type::ByStr20 => write!(f, "ByStr20"),
62 Type::ByStr20With { type_name, fields } => {
63 let fields = fields
64 .iter()
65 .map(|field| format!("field {}: {}", field.name, field.r#type))
66 .collect::<Vec<String>>()
67 .join(", ");
68 write!(f, "ByStr20 with {type_name}{fields} end")
69 }
70 Type::Other(ref s) => write!(f, "{}", s),
71 }
72 }
73}
74
75impl From<SrType> for Type {
76 fn from(mut type_definition: SrType) -> Self {
77 match type_definition.main_type.as_str() {
78 "Int32" => Type::Int32,
79 "Int64" => Type::Int64,
80 "Int128" => Type::Int128,
81 "Int256" => Type::Int256,
82 "Uint32" => Type::Uint32,
83 "Uint64" => Type::Uint64,
84 "Uint128" => Type::Uint128,
85 "Uint256" => Type::Uint256,
86 "String" => Type::String,
87 "ByStr" => Type::ByStr,
88 "ByStrX" => todo!(),
89 "BNum" => Type::BNum,
90 "Bool" => Type::Bool,
91 "Option" => Type::Option(Box::new(type_definition.sub_types.pop().unwrap().into())),
93 "List" => Type::List(Box::new(type_definition.sub_types.pop().unwrap().into())),
94 "Pair" => {
95 let t2 = type_definition.sub_types.pop().unwrap();
96 let t1 = type_definition.sub_types.pop().unwrap();
97 Type::Pair(Box::new(t1.into()), Box::new(t2.into()))
98 }
99 "Map" => {
100 let value = type_definition.sub_types.pop().unwrap();
101 let key = type_definition.sub_types.pop().unwrap();
102 Type::Map(Box::new(key.into()), Box::new(value.into()))
103 }
104 "ByStr20" => type_definition
105 .address_type
106 .map_or(Type::ByStr20, |address_type| Type::ByStr20With {
107 type_name: address_type.type_name,
108 fields: address_type.fields,
109 }),
110 t if t.starts_with("ByStr") => {
111 if let Some(number) = t
112 .strip_prefix("ByStr")
113 .and_then(|s| s.parse::<usize>().ok())
114 {
115 Type::ByStrX(number)
116 } else {
117 Type::Other(type_definition.main_type)
118 }
119 }
120 _ => Type::Other(type_definition.main_type),
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_type_to_string() {
131 let list_type = Type::List(Box::new(Type::Pair(
133 Box::new(Type::ByStrX(20)),
134 Box::new(Type::List(Box::new(Type::Pair(
135 Box::new(Type::ByStrX(20)),
136 Box::new(Type::Uint32),
137 )))),
138 )));
139
140 assert_eq!(
141 "(List (Pair ByStr20 (List (Pair ByStr20 Uint32))))",
142 list_type.to_string()
143 );
144
145 let list_type = Type::List(Box::new(Type::Pair(
147 Box::new(Type::ByStrX(20)),
148 Box::new(Type::List(Box::new(Type::Pair(
149 Box::new(Type::ByStrX(20)),
150 Box::new(Type::List(Box::new(Type::Pair(
151 Box::new(Type::Uint32),
152 Box::new(Type::Uint128),
153 )))),
154 )))),
155 )));
156
157 assert_eq!(
158 "(List (Pair ByStr20 (List (Pair ByStr20 (List (Pair Uint32 Uint128))))))",
159 list_type.to_string()
160 );
161 }
162}