tauri_typegen/analysis/
type_resolver.rs

1use crate::models::TypeStructure;
2use std::collections::{HashMap, HashSet};
3
4/// Type resolver for mapping Rust types to TypeScript types
5#[derive(Debug)]
6pub struct TypeResolver {
7    type_set: HashSet<String>,
8    type_mappings: HashMap<String, String>,
9}
10
11impl TypeResolver {
12    pub fn new() -> Self {
13        let mut type_set = HashSet::new();
14
15        // Basic Rust types
16        type_set.insert("String".to_string());
17        type_set.insert("&str".to_string());
18        type_set.insert("str".to_string());
19        type_set.insert("i8".to_string());
20        type_set.insert("i16".to_string());
21        type_set.insert("i32".to_string());
22        type_set.insert("i64".to_string());
23        type_set.insert("i128".to_string());
24        type_set.insert("isize".to_string());
25        type_set.insert("u8".to_string());
26        type_set.insert("u16".to_string());
27        type_set.insert("u32".to_string());
28        type_set.insert("u64".to_string());
29        type_set.insert("u128".to_string());
30        type_set.insert("usize".to_string());
31        type_set.insert("f32".to_string());
32        type_set.insert("f64".to_string());
33        type_set.insert("bool".to_string());
34        type_set.insert("()".to_string());
35
36        // Collection type mappings
37        type_set.insert("HashMap".to_string());
38        type_set.insert("BTreeMap".to_string());
39        type_set.insert("HashSet".to_string());
40        type_set.insert("BTreeSet".to_string());
41
42        Self {
43            type_set,
44            type_mappings: HashMap::new(),
45        }
46    }
47
48    /// Extract inner type from Option<T>
49    fn extract_option_inner_type(&self, rust_type: &str) -> Option<String> {
50        if rust_type.starts_with("Option<") && rust_type.ends_with('>') {
51            let inner = &rust_type[7..rust_type.len() - 1];
52            Some(inner.to_string())
53        } else {
54            None
55        }
56    }
57
58    /// Extract OK type from Result<T, E>
59    fn extract_result_ok_type(&self, rust_type: &str) -> Option<String> {
60        if rust_type.starts_with("Result<") && rust_type.ends_with('>') {
61            let inner = &rust_type[7..rust_type.len() - 1];
62            if let Some(comma_pos) = inner.find(',') {
63                let ok_type = inner[..comma_pos].trim();
64                Some(ok_type.to_string())
65            } else {
66                Some(inner.to_string())
67            }
68        } else {
69            None
70        }
71    }
72
73    /// Extract inner type from Vec<T>
74    fn extract_vec_inner_type(&self, rust_type: &str) -> Option<String> {
75        if rust_type.starts_with("Vec<") && rust_type.ends_with('>') {
76            let inner = &rust_type[4..rust_type.len() - 1];
77            Some(inner.to_string())
78        } else {
79            None
80        }
81    }
82
83    /// Extract key and value types from HashMap<K, V>
84    fn extract_hashmap_types(&self, rust_type: &str) -> Option<(String, String)> {
85        if rust_type.starts_with("HashMap<") && rust_type.ends_with('>') {
86            let inner = &rust_type[8..rust_type.len() - 1];
87            self.parse_two_type_params(inner)
88        } else {
89            None
90        }
91    }
92
93    /// Extract key and value types from BTreeMap<K, V>
94    fn extract_btreemap_types(&self, rust_type: &str) -> Option<(String, String)> {
95        if rust_type.starts_with("BTreeMap<") && rust_type.ends_with('>') {
96            let inner = &rust_type[9..rust_type.len() - 1];
97            self.parse_two_type_params(inner)
98        } else {
99            None
100        }
101    }
102
103    /// Extract inner type from HashSet<T>
104    fn extract_hashset_inner_type(&self, rust_type: &str) -> Option<String> {
105        if rust_type.starts_with("HashSet<") && rust_type.ends_with('>') {
106            let inner = &rust_type[8..rust_type.len() - 1];
107            Some(inner.to_string())
108        } else {
109            None
110        }
111    }
112
113    /// Extract inner type from BTreeSet<T>
114    fn extract_btreeset_inner_type(&self, rust_type: &str) -> Option<String> {
115        if rust_type.starts_with("BTreeSet<") && rust_type.ends_with('>') {
116            let inner = &rust_type[9..rust_type.len() - 1];
117            Some(inner.to_string())
118        } else {
119            None
120        }
121    }
122
123    /// Extract types from tuple (T1, T2, ...)
124    fn extract_tuple_types(&self, rust_type: &str) -> Option<Vec<String>> {
125        if rust_type.starts_with('(') && rust_type.ends_with(')') {
126            let inner = &rust_type[1..rust_type.len() - 1];
127            if inner.trim().is_empty() {
128                return Some(vec![]);
129            }
130            let types: Vec<String> = inner.split(',').map(|s| s.trim().to_string()).collect();
131            Some(types)
132        } else {
133            None
134        }
135    }
136
137    /// Extract inner type from reference &T
138    fn extract_reference_type(&self, rust_type: &str) -> Option<String> {
139        rust_type
140            .strip_prefix('&')
141            .map(|stripped| stripped.to_string())
142    }
143
144    /// Parse two type parameters separated by comma (for HashMap, BTreeMap)
145    fn parse_two_type_params(&self, inner: &str) -> Option<(String, String)> {
146        let mut depth = 0;
147        let mut comma_pos = None;
148
149        for (i, ch) in inner.char_indices() {
150            match ch {
151                '<' => depth += 1,
152                '>' => depth -= 1,
153                ',' if depth == 0 => {
154                    comma_pos = Some(i);
155                    break;
156                }
157                _ => {}
158            }
159        }
160
161        if let Some(pos) = comma_pos {
162            let key_type = inner[..pos].trim().to_string();
163            let value_type = inner[pos + 1..].trim().to_string();
164            Some((key_type, value_type))
165        } else {
166            None
167        }
168    }
169
170    /// Get the type mappings
171    pub fn get_type_set(&self) -> &HashSet<String> {
172        &self.type_set
173    }
174
175    /// Parse a Rust type string into a structured TypeStructure
176    /// This is the single source of truth for type parsing - generators use this instead of parsing strings
177    pub fn parse_type_structure(&self, rust_type: &str) -> TypeStructure {
178        let cleaned = rust_type.trim();
179
180        // Handle references &T -> T
181        if let Some(inner) = self.extract_reference_type(cleaned) {
182            return self.parse_type_structure(&inner);
183        }
184
185        // Handle Option<T> -> Optional(T)
186        if let Some(inner_type) = self.extract_option_inner_type(cleaned) {
187            return TypeStructure::Optional(Box::new(self.parse_type_structure(&inner_type)));
188        }
189
190        // Handle Result<T, E> -> Result(T)
191        if let Some(ok_type) = self.extract_result_ok_type(cleaned) {
192            return TypeStructure::Result(Box::new(self.parse_type_structure(&ok_type)));
193        }
194
195        // Handle Vec<T> -> Array(T)
196        if let Some(inner_type) = self.extract_vec_inner_type(cleaned) {
197            return TypeStructure::Array(Box::new(self.parse_type_structure(&inner_type)));
198        }
199
200        // Handle HashMap<K, V> and BTreeMap<K, V> -> Map { key, value }
201        if let Some((key_type, value_type)) = self
202            .extract_hashmap_types(cleaned)
203            .or_else(|| self.extract_btreemap_types(cleaned))
204        {
205            return TypeStructure::Map {
206                key: Box::new(self.parse_type_structure(&key_type)),
207                value: Box::new(self.parse_type_structure(&value_type)),
208            };
209        }
210
211        // Handle HashSet<T> and BTreeSet<T> -> Set(T)
212        if let Some(inner_type) = self
213            .extract_hashset_inner_type(cleaned)
214            .or_else(|| self.extract_btreeset_inner_type(cleaned))
215        {
216            return TypeStructure::Set(Box::new(self.parse_type_structure(&inner_type)));
217        }
218
219        // Handle tuple types (T1, T2, ...) -> Tuple([T1, T2, ...])
220        if let Some(tuple_types) = self.extract_tuple_types(cleaned) {
221            if tuple_types.is_empty() {
222                return TypeStructure::Primitive("void".to_string());
223            }
224            let parsed_types: Vec<TypeStructure> = tuple_types
225                .iter()
226                .map(|t| self.parse_type_structure(t.trim()))
227                .collect();
228            return TypeStructure::Tuple(parsed_types);
229        }
230
231        // Check if it's a primitive type and map to target primitive
232        if let Some(target_primitive) = self.map_to_target_primitive(cleaned) {
233            return TypeStructure::Primitive(target_primitive);
234        }
235
236        // Otherwise, it's a custom type
237        TypeStructure::Custom(cleaned.to_string())
238    }
239
240    /// Map Rust primitive types to target language primitives
241    /// Returns Some("number" | "string" | "boolean" | "void") or None for non-primitives
242    fn map_to_target_primitive(&self, rust_type: &str) -> Option<String> {
243        match rust_type {
244            // String types → "string"
245            "String" | "str" | "&str" => Some("string".to_string()),
246            // Numeric types → "number"
247            "i8" | "i16" | "i32" | "i64" | "i128" | "isize" | "u8" | "u16" | "u32" | "u64"
248            | "u128" | "usize" | "f32" | "f64" => Some("number".to_string()),
249            // Boolean → "boolean"
250            "bool" => Some("boolean".to_string()),
251            // Unit type → "void"
252            "()" => Some("void".to_string()),
253            // Not a primitive
254            _ => None,
255        }
256    }
257
258    /// Get the type mappings
259    pub fn get_type_mappings(&self) -> &HashMap<String, String> {
260        &self.type_mappings
261    }
262
263    /// Add a custom type mapping
264    pub fn add_type_mapping(&mut self, rust_type: String, typescript_type: String) {
265        self.type_mappings.insert(rust_type, typescript_type);
266    }
267
268    /// Apply type mappings from a HashMap (typically from config)
269    pub fn apply_type_mappings(&mut self, mappings: &HashMap<String, String>) {
270        for (rust_type, ts_type) in mappings {
271            self.type_mappings
272                .insert(rust_type.clone(), ts_type.clone());
273        }
274    }
275}
276
277impl Default for TypeResolver {
278    fn default() -> Self {
279        Self::new()
280    }
281}
282
283#[cfg(test)]
284mod tests {
285    use super::*;
286
287    #[test]
288    fn test_new_type_resolver_contains_primitives() {
289        let resolver = TypeResolver::new();
290        let type_set = resolver.get_type_set();
291
292        assert!(type_set.contains("String"));
293        assert!(type_set.contains("bool"));
294        assert!(type_set.contains("i32"));
295        assert!(type_set.contains("u64"));
296        assert!(type_set.contains("f32"));
297        assert!(type_set.contains("()"));
298    }
299
300    #[test]
301    fn test_new_type_resolver_contains_collections() {
302        let resolver = TypeResolver::new();
303        let type_set = resolver.get_type_set();
304
305        assert!(type_set.contains("HashMap"));
306        assert!(type_set.contains("BTreeMap"));
307        assert!(type_set.contains("HashSet"));
308        assert!(type_set.contains("BTreeSet"));
309    }
310
311    #[test]
312    fn test_default_impl() {
313        let resolver = TypeResolver::default();
314        assert!(resolver.get_type_set().contains("String"));
315    }
316
317    // Primitive type mapping tests
318    mod primitive_mapping {
319        use super::*;
320
321        #[test]
322        fn test_map_string_types() {
323            let resolver = TypeResolver::new();
324
325            assert_eq!(
326                resolver.map_to_target_primitive("String"),
327                Some("string".to_string())
328            );
329            assert_eq!(
330                resolver.map_to_target_primitive("str"),
331                Some("string".to_string())
332            );
333            assert_eq!(
334                resolver.map_to_target_primitive("&str"),
335                Some("string".to_string())
336            );
337        }
338
339        #[test]
340        fn test_map_integer_types() {
341            let resolver = TypeResolver::new();
342
343            assert_eq!(
344                resolver.map_to_target_primitive("i8"),
345                Some("number".to_string())
346            );
347            assert_eq!(
348                resolver.map_to_target_primitive("i16"),
349                Some("number".to_string())
350            );
351            assert_eq!(
352                resolver.map_to_target_primitive("i32"),
353                Some("number".to_string())
354            );
355            assert_eq!(
356                resolver.map_to_target_primitive("i64"),
357                Some("number".to_string())
358            );
359            assert_eq!(
360                resolver.map_to_target_primitive("i128"),
361                Some("number".to_string())
362            );
363            assert_eq!(
364                resolver.map_to_target_primitive("isize"),
365                Some("number".to_string())
366            );
367
368            assert_eq!(
369                resolver.map_to_target_primitive("u8"),
370                Some("number".to_string())
371            );
372            assert_eq!(
373                resolver.map_to_target_primitive("u16"),
374                Some("number".to_string())
375            );
376            assert_eq!(
377                resolver.map_to_target_primitive("u32"),
378                Some("number".to_string())
379            );
380            assert_eq!(
381                resolver.map_to_target_primitive("u64"),
382                Some("number".to_string())
383            );
384            assert_eq!(
385                resolver.map_to_target_primitive("u128"),
386                Some("number".to_string())
387            );
388            assert_eq!(
389                resolver.map_to_target_primitive("usize"),
390                Some("number".to_string())
391            );
392        }
393
394        #[test]
395        fn test_map_float_types() {
396            let resolver = TypeResolver::new();
397
398            assert_eq!(
399                resolver.map_to_target_primitive("f32"),
400                Some("number".to_string())
401            );
402            assert_eq!(
403                resolver.map_to_target_primitive("f64"),
404                Some("number".to_string())
405            );
406        }
407
408        #[test]
409        fn test_map_boolean() {
410            let resolver = TypeResolver::new();
411            assert_eq!(
412                resolver.map_to_target_primitive("bool"),
413                Some("boolean".to_string())
414            );
415        }
416
417        #[test]
418        fn test_map_unit_type() {
419            let resolver = TypeResolver::new();
420            assert_eq!(
421                resolver.map_to_target_primitive("()"),
422                Some("void".to_string())
423            );
424        }
425
426        #[test]
427        fn test_map_non_primitive() {
428            let resolver = TypeResolver::new();
429            assert_eq!(resolver.map_to_target_primitive("User"), None);
430            assert_eq!(resolver.map_to_target_primitive("CustomType"), None);
431        }
432    }
433
434    // Type extraction tests
435    mod type_extraction {
436        use super::*;
437
438        #[test]
439        fn test_extract_option_inner_type() {
440            let resolver = TypeResolver::new();
441
442            assert_eq!(
443                resolver.extract_option_inner_type("Option<String>"),
444                Some("String".to_string())
445            );
446            assert_eq!(
447                resolver.extract_option_inner_type("Option<User>"),
448                Some("User".to_string())
449            );
450            assert_eq!(resolver.extract_option_inner_type("String"), None);
451        }
452
453        #[test]
454        fn test_extract_result_ok_type() {
455            let resolver = TypeResolver::new();
456
457            assert_eq!(
458                resolver.extract_result_ok_type("Result<String, Error>"),
459                Some("String".to_string())
460            );
461            assert_eq!(
462                resolver.extract_result_ok_type("Result<User, String>"),
463                Some("User".to_string())
464            );
465            assert_eq!(
466                resolver.extract_result_ok_type("Result<()>"),
467                Some("()".to_string())
468            );
469            assert_eq!(resolver.extract_result_ok_type("String"), None);
470        }
471
472        #[test]
473        fn test_extract_vec_inner_type() {
474            let resolver = TypeResolver::new();
475
476            assert_eq!(
477                resolver.extract_vec_inner_type("Vec<String>"),
478                Some("String".to_string())
479            );
480            assert_eq!(
481                resolver.extract_vec_inner_type("Vec<User>"),
482                Some("User".to_string())
483            );
484            assert_eq!(resolver.extract_vec_inner_type("String"), None);
485        }
486
487        #[test]
488        fn test_extract_hashmap_types() {
489            let resolver = TypeResolver::new();
490
491            assert_eq!(
492                resolver.extract_hashmap_types("HashMap<String, User>"),
493                Some(("String".to_string(), "User".to_string()))
494            );
495            assert_eq!(
496                resolver.extract_hashmap_types("HashMap<i32, String>"),
497                Some(("i32".to_string(), "String".to_string()))
498            );
499            assert_eq!(resolver.extract_hashmap_types("String"), None);
500        }
501
502        #[test]
503        fn test_extract_btreemap_types() {
504            let resolver = TypeResolver::new();
505
506            assert_eq!(
507                resolver.extract_btreemap_types("BTreeMap<String, User>"),
508                Some(("String".to_string(), "User".to_string()))
509            );
510            assert_eq!(resolver.extract_btreemap_types("String"), None);
511        }
512
513        #[test]
514        fn test_extract_hashset_inner_type() {
515            let resolver = TypeResolver::new();
516
517            assert_eq!(
518                resolver.extract_hashset_inner_type("HashSet<String>"),
519                Some("String".to_string())
520            );
521            assert_eq!(resolver.extract_hashset_inner_type("String"), None);
522        }
523
524        #[test]
525        fn test_extract_btreeset_inner_type() {
526            let resolver = TypeResolver::new();
527
528            assert_eq!(
529                resolver.extract_btreeset_inner_type("BTreeSet<User>"),
530                Some("User".to_string())
531            );
532            assert_eq!(resolver.extract_btreeset_inner_type("String"), None);
533        }
534
535        #[test]
536        fn test_extract_tuple_types() {
537            let resolver = TypeResolver::new();
538
539            assert_eq!(
540                resolver.extract_tuple_types("(String, i32)"),
541                Some(vec!["String".to_string(), "i32".to_string()])
542            );
543            assert_eq!(
544                resolver.extract_tuple_types("(String, i32, bool)"),
545                Some(vec![
546                    "String".to_string(),
547                    "i32".to_string(),
548                    "bool".to_string()
549                ])
550            );
551            assert_eq!(resolver.extract_tuple_types("()"), Some(vec![]));
552            assert_eq!(resolver.extract_tuple_types("String"), None);
553        }
554
555        #[test]
556        fn test_extract_reference_type() {
557            let resolver = TypeResolver::new();
558
559            assert_eq!(
560                resolver.extract_reference_type("&String"),
561                Some("String".to_string())
562            );
563            assert_eq!(
564                resolver.extract_reference_type("&str"),
565                Some("str".to_string())
566            );
567            assert_eq!(resolver.extract_reference_type("String"), None);
568        }
569
570        #[test]
571        fn test_parse_two_type_params_simple() {
572            let resolver = TypeResolver::new();
573
574            assert_eq!(
575                resolver.parse_two_type_params("String, User"),
576                Some(("String".to_string(), "User".to_string()))
577            );
578        }
579
580        #[test]
581        fn test_parse_two_type_params_nested() {
582            let resolver = TypeResolver::new();
583
584            // HashMap<String, Vec<User>>
585            assert_eq!(
586                resolver.parse_two_type_params("String, Vec<User>"),
587                Some(("String".to_string(), "Vec<User>".to_string()))
588            );
589        }
590
591        #[test]
592        fn test_parse_two_type_params_no_comma() {
593            let resolver = TypeResolver::new();
594            assert_eq!(resolver.parse_two_type_params("String"), None);
595        }
596    }
597
598    // TypeStructure parsing tests
599    mod type_structure_parsing {
600        use super::*;
601
602        #[test]
603        fn test_parse_primitive_string() {
604            let resolver = TypeResolver::new();
605            let result = resolver.parse_type_structure("String");
606
607            match result {
608                TypeStructure::Primitive(name) => assert_eq!(name, "string"),
609                _ => panic!("Should be Primitive"),
610            }
611        }
612
613        #[test]
614        fn test_parse_primitive_number() {
615            let resolver = TypeResolver::new();
616            let result = resolver.parse_type_structure("i32");
617
618            match result {
619                TypeStructure::Primitive(name) => assert_eq!(name, "number"),
620                _ => panic!("Should be Primitive"),
621            }
622        }
623
624        #[test]
625        fn test_parse_primitive_boolean() {
626            let resolver = TypeResolver::new();
627            let result = resolver.parse_type_structure("bool");
628
629            match result {
630                TypeStructure::Primitive(name) => assert_eq!(name, "boolean"),
631                _ => panic!("Should be Primitive"),
632            }
633        }
634
635        #[test]
636        fn test_parse_primitive_void() {
637            let resolver = TypeResolver::new();
638            let result = resolver.parse_type_structure("()");
639
640            match result {
641                TypeStructure::Primitive(name) => assert_eq!(name, "void"),
642                _ => panic!("Should be Primitive"),
643            }
644        }
645
646        #[test]
647        fn test_parse_custom_type() {
648            let resolver = TypeResolver::new();
649            let result = resolver.parse_type_structure("User");
650
651            match result {
652                TypeStructure::Custom(name) => assert_eq!(name, "User"),
653                _ => panic!("Should be Custom"),
654            }
655        }
656
657        #[test]
658        fn test_parse_reference() {
659            let resolver = TypeResolver::new();
660            let result = resolver.parse_type_structure("&String");
661
662            match result {
663                TypeStructure::Primitive(name) => assert_eq!(name, "string"),
664                _ => panic!("Should unwrap reference to string"),
665            }
666        }
667
668        #[test]
669        fn test_parse_option() {
670            let resolver = TypeResolver::new();
671            let result = resolver.parse_type_structure("Option<String>");
672
673            match result {
674                TypeStructure::Optional(inner) => match *inner {
675                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
676                    _ => panic!("Inner should be string"),
677                },
678                _ => panic!("Should be Optional"),
679            }
680        }
681
682        #[test]
683        fn test_parse_result() {
684            let resolver = TypeResolver::new();
685            let result = resolver.parse_type_structure("Result<User, Error>");
686
687            match result {
688                TypeStructure::Result(inner) => match *inner {
689                    TypeStructure::Custom(name) => assert_eq!(name, "User"),
690                    _ => panic!("Inner should be User"),
691                },
692                _ => panic!("Should be Result"),
693            }
694        }
695
696        #[test]
697        fn test_parse_vec() {
698            let resolver = TypeResolver::new();
699            let result = resolver.parse_type_structure("Vec<String>");
700
701            match result {
702                TypeStructure::Array(inner) => match *inner {
703                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
704                    _ => panic!("Inner should be string"),
705                },
706                _ => panic!("Should be Array"),
707            }
708        }
709
710        #[test]
711        fn test_parse_hashmap() {
712            let resolver = TypeResolver::new();
713            let result = resolver.parse_type_structure("HashMap<String, User>");
714
715            match result {
716                TypeStructure::Map { key, value } => match (*key, *value) {
717                    (TypeStructure::Primitive(k), TypeStructure::Custom(v)) => {
718                        assert_eq!(k, "string");
719                        assert_eq!(v, "User");
720                    }
721                    _ => panic!("Key should be string, value should be User"),
722                },
723                _ => panic!("Should be Map"),
724            }
725        }
726
727        #[test]
728        fn test_parse_btreemap() {
729            let resolver = TypeResolver::new();
730            let result = resolver.parse_type_structure("BTreeMap<i32, String>");
731
732            match result {
733                TypeStructure::Map { key, value } => match (*key, *value) {
734                    (TypeStructure::Primitive(k), TypeStructure::Primitive(v)) => {
735                        assert_eq!(k, "number");
736                        assert_eq!(v, "string");
737                    }
738                    _ => panic!("Key should be number, value should be string"),
739                },
740                _ => panic!("Should be Map"),
741            }
742        }
743
744        #[test]
745        fn test_parse_hashset() {
746            let resolver = TypeResolver::new();
747            let result = resolver.parse_type_structure("HashSet<String>");
748
749            match result {
750                TypeStructure::Set(inner) => match *inner {
751                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
752                    _ => panic!("Inner should be string"),
753                },
754                _ => panic!("Should be Set"),
755            }
756        }
757
758        #[test]
759        fn test_parse_btreeset() {
760            let resolver = TypeResolver::new();
761            let result = resolver.parse_type_structure("BTreeSet<User>");
762
763            match result {
764                TypeStructure::Set(inner) => match *inner {
765                    TypeStructure::Custom(name) => assert_eq!(name, "User"),
766                    _ => panic!("Inner should be User"),
767                },
768                _ => panic!("Should be Set"),
769            }
770        }
771
772        #[test]
773        fn test_parse_tuple() {
774            let resolver = TypeResolver::new();
775            let result = resolver.parse_type_structure("(String, i32)");
776
777            match result {
778                TypeStructure::Tuple(types) => {
779                    assert_eq!(types.len(), 2);
780                    match &types[0] {
781                        TypeStructure::Primitive(name) => assert_eq!(name, "string"),
782                        _ => panic!("First type should be string"),
783                    }
784                    match &types[1] {
785                        TypeStructure::Primitive(name) => assert_eq!(name, "number"),
786                        _ => panic!("Second type should be number"),
787                    }
788                }
789                _ => panic!("Should be Tuple"),
790            }
791        }
792
793        #[test]
794        fn test_parse_empty_tuple() {
795            let resolver = TypeResolver::new();
796            let result = resolver.parse_type_structure("()");
797
798            match result {
799                TypeStructure::Primitive(name) => assert_eq!(name, "void"),
800                _ => panic!("Empty tuple should be void"),
801            }
802        }
803
804        #[test]
805        fn test_parse_nested_option_vec() {
806            let resolver = TypeResolver::new();
807            let result = resolver.parse_type_structure("Option<Vec<String>>");
808
809            match result {
810                TypeStructure::Optional(opt_inner) => match *opt_inner {
811                    TypeStructure::Array(arr_inner) => match *arr_inner {
812                        TypeStructure::Primitive(name) => assert_eq!(name, "string"),
813                        _ => panic!("Should be string"),
814                    },
815                    _ => panic!("Should be Array"),
816                },
817                _ => panic!("Should be Optional"),
818            }
819        }
820
821        #[test]
822        fn test_parse_vec_option() {
823            let resolver = TypeResolver::new();
824            let result = resolver.parse_type_structure("Vec<Option<User>>");
825
826            match result {
827                TypeStructure::Array(arr_inner) => match *arr_inner {
828                    TypeStructure::Optional(opt_inner) => match *opt_inner {
829                        TypeStructure::Custom(name) => assert_eq!(name, "User"),
830                        _ => panic!("Should be User"),
831                    },
832                    _ => panic!("Should be Optional"),
833                },
834                _ => panic!("Should be Array"),
835            }
836        }
837
838        #[test]
839        fn test_parse_hashmap_with_vec_value() {
840            let resolver = TypeResolver::new();
841            let result = resolver.parse_type_structure("HashMap<String, Vec<User>>");
842
843            match result {
844                TypeStructure::Map { key, value } => match (*key, *value) {
845                    (TypeStructure::Primitive(k), TypeStructure::Array(v_arr)) => {
846                        assert_eq!(k, "string");
847                        match *v_arr {
848                            TypeStructure::Custom(name) => assert_eq!(name, "User"),
849                            _ => panic!("Array value should be User"),
850                        }
851                    }
852                    _ => panic!("Key should be string, value should be Array"),
853                },
854                _ => panic!("Should be Map"),
855            }
856        }
857
858        #[test]
859        fn test_parse_result_with_unit_ok() {
860            let resolver = TypeResolver::new();
861            let result = resolver.parse_type_structure("Result<(), String>");
862
863            match result {
864                TypeStructure::Result(inner) => match *inner {
865                    TypeStructure::Primitive(name) => assert_eq!(name, "void"),
866                    _ => panic!("Should be void"),
867                },
868                _ => panic!("Should be Result"),
869            }
870        }
871
872        #[test]
873        fn test_parse_complex_nested() {
874            let resolver = TypeResolver::new();
875            // Test a simpler but still complex nested type that works
876            // Option<Vec<HashMap<String, User>>>
877            let result = resolver.parse_type_structure("Option<Vec<HashMap<String, User>>>");
878
879            match result {
880                TypeStructure::Optional(opt) => match *opt {
881                    TypeStructure::Array(arr) => match *arr {
882                        TypeStructure::Map { key, value } => match (*key, *value) {
883                            (TypeStructure::Primitive(k), TypeStructure::Custom(v)) => {
884                                assert_eq!(k, "string");
885                                assert_eq!(v, "User");
886                            }
887                            _ => panic!("Map types incorrect"),
888                        },
889                        _ => panic!("Should be Map"),
890                    },
891                    _ => panic!("Should be Array"),
892                },
893                _ => panic!("Should be Optional"),
894            }
895        }
896
897        #[test]
898        fn test_parse_result_with_simple_nested() {
899            let resolver = TypeResolver::new();
900            // Result<Vec<User>, Error>
901            let result = resolver.parse_type_structure("Result<Vec<User>, Error>");
902
903            match result {
904                TypeStructure::Result(res) => match *res {
905                    TypeStructure::Array(arr) => match *arr {
906                        TypeStructure::Custom(name) => assert_eq!(name, "User"),
907                        _ => panic!("Should be User"),
908                    },
909                    _ => panic!("Should be Array"),
910                },
911                _ => panic!("Should be Result"),
912            }
913        }
914
915        #[test]
916        fn test_parse_with_whitespace() {
917            let resolver = TypeResolver::new();
918            // Note: The type resolver doesn't handle spaces inside generic brackets well
919            // "Option < String >" is not recognized as Option<String> - it's treated as custom type
920            let result = resolver.parse_type_structure("  Option<String>  ");
921
922            match result {
923                TypeStructure::Optional(inner) => match *inner {
924                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
925                    _ => panic!("Should be string"),
926                },
927                _ => panic!("Should be Optional"),
928            }
929        }
930    }
931}