tauri_typegen/analysis/
type_resolver.rs1use std::collections::HashMap;
2
3#[derive(Debug)]
5pub struct TypeResolver {
6 type_mappings: HashMap<String, String>,
7}
8
9impl TypeResolver {
10 pub fn new() -> Self {
11 let mut type_mappings = HashMap::new();
12
13 type_mappings.insert("String".to_string(), "string".to_string());
15 type_mappings.insert("&str".to_string(), "string".to_string());
16 type_mappings.insert("str".to_string(), "string".to_string());
17 type_mappings.insert("i8".to_string(), "number".to_string());
18 type_mappings.insert("i16".to_string(), "number".to_string());
19 type_mappings.insert("i32".to_string(), "number".to_string());
20 type_mappings.insert("i64".to_string(), "number".to_string());
21 type_mappings.insert("i128".to_string(), "number".to_string());
22 type_mappings.insert("isize".to_string(), "number".to_string());
23 type_mappings.insert("u8".to_string(), "number".to_string());
24 type_mappings.insert("u16".to_string(), "number".to_string());
25 type_mappings.insert("u32".to_string(), "number".to_string());
26 type_mappings.insert("u64".to_string(), "number".to_string());
27 type_mappings.insert("u128".to_string(), "number".to_string());
28 type_mappings.insert("usize".to_string(), "number".to_string());
29 type_mappings.insert("f32".to_string(), "number".to_string());
30 type_mappings.insert("f64".to_string(), "number".to_string());
31 type_mappings.insert("bool".to_string(), "boolean".to_string());
32 type_mappings.insert("()".to_string(), "void".to_string());
33
34 type_mappings.insert("HashMap".to_string(), "Map".to_string());
36 type_mappings.insert("BTreeMap".to_string(), "Map".to_string());
37 type_mappings.insert("HashSet".to_string(), "Set".to_string());
38 type_mappings.insert("BTreeSet".to_string(), "Set".to_string());
39
40 Self { type_mappings }
41 }
42
43 pub fn map_rust_type_to_typescript(&mut self, rust_type: &str) -> String {
45 if let Some(inner_type) = self.extract_option_inner_type(rust_type) {
47 let mapped_inner = self.map_rust_type_to_typescript(&inner_type);
48 return format!("{} | null", mapped_inner);
49 }
50
51 if let Some(ok_type) = self.extract_result_ok_type(rust_type) {
53 return self.map_rust_type_to_typescript(&ok_type);
54 }
55
56 if let Some(inner_type) = self.extract_vec_inner_type(rust_type) {
58 let mapped_inner = self.map_rust_type_to_typescript(&inner_type);
59 return format!("{}[]", mapped_inner);
60 }
61
62 if let Some((key_type, value_type)) = self.extract_hashmap_types(rust_type) {
64 let mapped_key = self.map_rust_type_to_typescript(&key_type);
65 let mapped_value = self.map_rust_type_to_typescript(&value_type);
66 return format!("Map<{}, {}>", mapped_key, mapped_value);
67 }
68
69 if let Some((key_type, value_type)) = self.extract_btreemap_types(rust_type) {
71 let mapped_key = self.map_rust_type_to_typescript(&key_type);
72 let mapped_value = self.map_rust_type_to_typescript(&value_type);
73 return format!("Map<{}, {}>", mapped_key, mapped_value);
74 }
75
76 if let Some(inner_type) = self.extract_hashset_inner_type(rust_type) {
78 let mapped_inner = self.map_rust_type_to_typescript(&inner_type);
79 return format!("{}[]", mapped_inner);
80 }
81
82 if let Some(inner_type) = self.extract_btreeset_inner_type(rust_type) {
84 let mapped_inner = self.map_rust_type_to_typescript(&inner_type);
85 return format!("{}[]", mapped_inner);
86 }
87
88 if let Some(tuple_types) = self.extract_tuple_types(rust_type) {
90 if tuple_types.is_empty() {
91 return "void".to_string();
92 }
93 let mapped_types: Vec<String> = tuple_types
94 .iter()
95 .map(|t| self.map_rust_type_to_typescript(t.trim()))
96 .collect();
97 return format!("[{}]", mapped_types.join(", "));
98 }
99
100 if let Some(inner_type) = self.extract_reference_type(rust_type) {
102 return self.map_rust_type_to_typescript(&inner_type);
103 }
104
105 if let Some(mapped) = self.type_mappings.get(rust_type) {
107 return mapped.clone();
108 }
109
110 rust_type.to_string()
112 }
113
114 fn extract_option_inner_type(&self, rust_type: &str) -> Option<String> {
116 if rust_type.starts_with("Option<") && rust_type.ends_with('>') {
117 let inner = &rust_type[7..rust_type.len() - 1];
118 Some(inner.to_string())
119 } else {
120 None
121 }
122 }
123
124 fn extract_result_ok_type(&self, rust_type: &str) -> Option<String> {
126 if rust_type.starts_with("Result<") && rust_type.ends_with('>') {
127 let inner = &rust_type[7..rust_type.len() - 1];
128 if let Some(comma_pos) = inner.find(',') {
129 let ok_type = inner[..comma_pos].trim();
130 Some(ok_type.to_string())
131 } else {
132 Some(inner.to_string())
133 }
134 } else {
135 None
136 }
137 }
138
139 fn extract_vec_inner_type(&self, rust_type: &str) -> Option<String> {
141 if rust_type.starts_with("Vec<") && rust_type.ends_with('>') {
142 let inner = &rust_type[4..rust_type.len() - 1];
143 Some(inner.to_string())
144 } else {
145 None
146 }
147 }
148
149 fn extract_hashmap_types(&self, rust_type: &str) -> Option<(String, String)> {
151 if rust_type.starts_with("HashMap<") && rust_type.ends_with('>') {
152 let inner = &rust_type[8..rust_type.len() - 1];
153 self.parse_two_type_params(inner)
154 } else {
155 None
156 }
157 }
158
159 fn extract_btreemap_types(&self, rust_type: &str) -> Option<(String, String)> {
161 if rust_type.starts_with("BTreeMap<") && rust_type.ends_with('>') {
162 let inner = &rust_type[9..rust_type.len() - 1];
163 self.parse_two_type_params(inner)
164 } else {
165 None
166 }
167 }
168
169 fn extract_hashset_inner_type(&self, rust_type: &str) -> Option<String> {
171 if rust_type.starts_with("HashSet<") && rust_type.ends_with('>') {
172 let inner = &rust_type[8..rust_type.len() - 1];
173 Some(inner.to_string())
174 } else {
175 None
176 }
177 }
178
179 fn extract_btreeset_inner_type(&self, rust_type: &str) -> Option<String> {
181 if rust_type.starts_with("BTreeSet<") && rust_type.ends_with('>') {
182 let inner = &rust_type[9..rust_type.len() - 1];
183 Some(inner.to_string())
184 } else {
185 None
186 }
187 }
188
189 fn extract_tuple_types(&self, rust_type: &str) -> Option<Vec<String>> {
191 if rust_type.starts_with('(') && rust_type.ends_with(')') {
192 let inner = &rust_type[1..rust_type.len() - 1];
193 if inner.trim().is_empty() {
194 return Some(vec![]);
195 }
196 let types: Vec<String> = inner.split(',').map(|s| s.trim().to_string()).collect();
197 Some(types)
198 } else {
199 None
200 }
201 }
202
203 fn extract_reference_type(&self, rust_type: &str) -> Option<String> {
205 rust_type
206 .strip_prefix('&')
207 .map(|stripped| stripped.to_string())
208 }
209
210 fn parse_two_type_params(&self, inner: &str) -> Option<(String, String)> {
212 let mut depth = 0;
213 let mut comma_pos = None;
214
215 for (i, ch) in inner.char_indices() {
216 match ch {
217 '<' => depth += 1,
218 '>' => depth -= 1,
219 ',' if depth == 0 => {
220 comma_pos = Some(i);
221 break;
222 }
223 _ => {}
224 }
225 }
226
227 if let Some(pos) = comma_pos {
228 let key_type = inner[..pos].trim().to_string();
229 let value_type = inner[pos + 1..].trim().to_string();
230 Some((key_type, value_type))
231 } else {
232 None
233 }
234 }
235
236 pub fn get_type_mappings(&self) -> &HashMap<String, String> {
238 &self.type_mappings
239 }
240
241 pub fn add_type_mapping(&mut self, rust_type: String, typescript_type: String) {
243 self.type_mappings.insert(rust_type, typescript_type);
244 }
245}
246
247impl Default for TypeResolver {
248 fn default() -> Self {
249 Self::new()
250 }
251}