Skip to main content

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    /// Strip module prefixes from a type name, handling generic arguments
176    /// Examples:
177    /// - "std::vec::Vec" -> "Vec"
178    /// - "::core::option::Option" -> "Option"
179    /// - "core::option::Option<prost::alloc::string::String>" -> "Option<String>"
180    fn strip_module_prefix(&self, type_str: &str) -> String {
181        let type_str = type_str.trim();
182
183        // Find the position of the first '<' if it exists
184        let angle_bracket_pos = type_str.find('<');
185
186        // Split into type name and generic arguments
187        let (type_name, generics) = if let Some(pos) = angle_bracket_pos {
188            (&type_str[..pos], Some(&type_str[pos..]))
189        } else {
190            (type_str, None)
191        };
192
193        // Strip leading :: and all module path prefixes from type name
194        let cleaned_type_name = type_name
195            .strip_prefix("::")
196            .unwrap_or(type_name)
197            .split("::")
198            .last()
199            .unwrap_or(type_name);
200
201        // Recursively clean generic arguments
202        if let Some(gen_str) = generics {
203            let cleaned_generics = self.clean_generic_arguments(gen_str);
204            format!("{}{}", cleaned_type_name, cleaned_generics)
205        } else {
206            cleaned_type_name.to_string()
207        }
208    }
209
210    /// Clean up module paths within generic arguments
211    /// Example: "<prost::alloc::string::String, core::option::Option<i32>>" -> "<String, Option<i32>>"
212    fn clean_generic_arguments(&self, gen_str: &str) -> String {
213        if !gen_str.starts_with('<') || !gen_str.ends_with('>') {
214            return gen_str.to_string();
215        }
216
217        let inner = &gen_str[1..gen_str.len() - 1];
218        let mut result = String::from("<");
219        let mut depth = 0;
220        let mut current_arg = String::new();
221
222        for ch in inner.chars() {
223            match ch {
224                '<' => {
225                    depth += 1;
226                    current_arg.push(ch);
227                }
228                '>' => {
229                    depth -= 1;
230                    current_arg.push(ch);
231                }
232                ',' if depth == 0 => {
233                    // Clean this argument and add it
234                    let cleaned = self.strip_module_prefix(current_arg.trim());
235                    result.push_str(&cleaned);
236                    result.push_str(", ");
237                    current_arg.clear();
238                }
239                _ => {
240                    current_arg.push(ch);
241                }
242            }
243        }
244
245        // Don't forget the last argument
246        if !current_arg.trim().is_empty() {
247            let cleaned = self.strip_module_prefix(current_arg.trim());
248            result.push_str(&cleaned);
249        }
250
251        result.push('>');
252        result
253    }
254
255    /// Parse a Rust type string into a structured TypeStructure
256    /// This is the single source of truth for type parsing - generators use this instead of parsing strings
257    pub fn parse_type_structure(&self, rust_type: &str) -> TypeStructure {
258        let cleaned = self.strip_module_prefix(rust_type);
259        let cleaned_str = cleaned.as_str();
260
261        // Handle references &T -> T
262        if let Some(inner) = self.extract_reference_type(cleaned_str) {
263            return self.parse_type_structure(&inner);
264        }
265
266        // Handle Option<T> -> Optional(T)
267        if let Some(inner_type) = self.extract_option_inner_type(cleaned_str) {
268            return TypeStructure::Optional(Box::new(self.parse_type_structure(&inner_type)));
269        }
270
271        // Handle Result<T, E> -> Result(T)
272        if let Some(ok_type) = self.extract_result_ok_type(cleaned_str) {
273            return TypeStructure::Result(Box::new(self.parse_type_structure(&ok_type)));
274        }
275
276        // Handle Vec<T> -> Array(T)
277        if let Some(inner_type) = self.extract_vec_inner_type(cleaned_str) {
278            return TypeStructure::Array(Box::new(self.parse_type_structure(&inner_type)));
279        }
280
281        // Handle [T] or [T; N] -> Array(T)
282        if cleaned_str.starts_with('[') && cleaned_str.ends_with(']') {
283            let inner = &cleaned_str[1..cleaned_str.len() - 1];
284            // Split by ; for [T; N]
285            let inner_type = if let Some(semi_pos) = inner.find(';') {
286                inner[..semi_pos].trim()
287            } else {
288                inner.trim()
289            };
290
291            if !inner_type.is_empty() {
292                return TypeStructure::Array(Box::new(self.parse_type_structure(inner_type)));
293            }
294        }
295
296        // Handle HashMap<K, V> and BTreeMap<K, V> -> Map { key, value }
297        if let Some((key_type, value_type)) = self
298            .extract_hashmap_types(cleaned_str)
299            .or_else(|| self.extract_btreemap_types(cleaned_str))
300        {
301            return TypeStructure::Map {
302                key: Box::new(self.parse_type_structure(&key_type)),
303                value: Box::new(self.parse_type_structure(&value_type)),
304            };
305        }
306
307        // Handle HashSet<T> and BTreeSet<T> -> Set(T)
308        if let Some(inner_type) = self
309            .extract_hashset_inner_type(cleaned_str)
310            .or_else(|| self.extract_btreeset_inner_type(cleaned_str))
311        {
312            return TypeStructure::Set(Box::new(self.parse_type_structure(&inner_type)));
313        }
314
315        // Handle tuple types (T1, T2, ...) -> Tuple([T1, T2, ...])
316        if let Some(tuple_types) = self.extract_tuple_types(cleaned_str) {
317            if tuple_types.is_empty() {
318                return TypeStructure::Primitive("void".to_string());
319            }
320            let parsed_types: Vec<TypeStructure> = tuple_types
321                .iter()
322                .map(|t| self.parse_type_structure(t.trim()))
323                .collect();
324            return TypeStructure::Tuple(parsed_types);
325        }
326
327        // Check if it's a primitive type and map to target primitive
328        if let Some(target_primitive) = self.map_to_target_primitive(cleaned_str) {
329            return TypeStructure::Primitive(target_primitive);
330        }
331
332        // Otherwise, it's a custom type
333        TypeStructure::Custom(cleaned)
334    }
335
336    /// Map Rust primitive types to target language primitives
337    /// Returns Some("number" | "string" | "boolean" | "void") or None for non-primitives
338    fn map_to_target_primitive(&self, rust_type: &str) -> Option<String> {
339        match rust_type {
340            // String types → "string"
341            "String" | "str" | "&str" => Some("string".to_string()),
342            // Numeric types → "number"
343            "i8" | "i16" | "i32" | "i64" | "i128" | "isize" | "u8" | "u16" | "u32" | "u64"
344            | "u128" | "usize" | "f32" | "f64" => Some("number".to_string()),
345            // Boolean → "boolean"
346            "bool" => Some("boolean".to_string()),
347            // Unit type → "void"
348            "()" => Some("void".to_string()),
349            // Not a primitive
350            _ => None,
351        }
352    }
353
354    /// Get the type mappings
355    pub fn get_type_mappings(&self) -> &HashMap<String, String> {
356        &self.type_mappings
357    }
358
359    /// Add a custom type mapping
360    pub fn add_type_mapping(&mut self, rust_type: String, typescript_type: String) {
361        self.type_mappings.insert(rust_type, typescript_type);
362    }
363
364    /// Apply type mappings from a HashMap (typically from config)
365    pub fn apply_type_mappings(&mut self, mappings: &HashMap<String, String>) {
366        for (rust_type, ts_type) in mappings {
367            self.type_mappings
368                .insert(rust_type.clone(), ts_type.clone());
369        }
370    }
371}
372
373impl Default for TypeResolver {
374    fn default() -> Self {
375        Self::new()
376    }
377}
378
379#[cfg(test)]
380mod tests {
381    use super::*;
382
383    #[test]
384    fn test_new_type_resolver_contains_primitives() {
385        let resolver = TypeResolver::new();
386        let type_set = resolver.get_type_set();
387
388        assert!(type_set.contains("String"));
389        assert!(type_set.contains("bool"));
390        assert!(type_set.contains("i32"));
391        assert!(type_set.contains("u64"));
392        assert!(type_set.contains("f32"));
393        assert!(type_set.contains("()"));
394    }
395
396    #[test]
397    fn test_new_type_resolver_contains_collections() {
398        let resolver = TypeResolver::new();
399        let type_set = resolver.get_type_set();
400
401        assert!(type_set.contains("HashMap"));
402        assert!(type_set.contains("BTreeMap"));
403        assert!(type_set.contains("HashSet"));
404        assert!(type_set.contains("BTreeSet"));
405    }
406
407    #[test]
408    fn test_default_impl() {
409        let resolver = TypeResolver::default();
410        assert!(resolver.get_type_set().contains("String"));
411    }
412
413    // Primitive type mapping tests
414    mod primitive_mapping {
415        use super::*;
416
417        #[test]
418        fn test_map_string_types() {
419            let resolver = TypeResolver::new();
420
421            assert_eq!(
422                resolver.map_to_target_primitive("String"),
423                Some("string".to_string())
424            );
425            assert_eq!(
426                resolver.map_to_target_primitive("str"),
427                Some("string".to_string())
428            );
429            assert_eq!(
430                resolver.map_to_target_primitive("&str"),
431                Some("string".to_string())
432            );
433        }
434
435        #[test]
436        fn test_map_integer_types() {
437            let resolver = TypeResolver::new();
438
439            assert_eq!(
440                resolver.map_to_target_primitive("i8"),
441                Some("number".to_string())
442            );
443            assert_eq!(
444                resolver.map_to_target_primitive("i16"),
445                Some("number".to_string())
446            );
447            assert_eq!(
448                resolver.map_to_target_primitive("i32"),
449                Some("number".to_string())
450            );
451            assert_eq!(
452                resolver.map_to_target_primitive("i64"),
453                Some("number".to_string())
454            );
455            assert_eq!(
456                resolver.map_to_target_primitive("i128"),
457                Some("number".to_string())
458            );
459            assert_eq!(
460                resolver.map_to_target_primitive("isize"),
461                Some("number".to_string())
462            );
463
464            assert_eq!(
465                resolver.map_to_target_primitive("u8"),
466                Some("number".to_string())
467            );
468            assert_eq!(
469                resolver.map_to_target_primitive("u16"),
470                Some("number".to_string())
471            );
472            assert_eq!(
473                resolver.map_to_target_primitive("u32"),
474                Some("number".to_string())
475            );
476            assert_eq!(
477                resolver.map_to_target_primitive("u64"),
478                Some("number".to_string())
479            );
480            assert_eq!(
481                resolver.map_to_target_primitive("u128"),
482                Some("number".to_string())
483            );
484            assert_eq!(
485                resolver.map_to_target_primitive("usize"),
486                Some("number".to_string())
487            );
488        }
489
490        #[test]
491        fn test_map_float_types() {
492            let resolver = TypeResolver::new();
493
494            assert_eq!(
495                resolver.map_to_target_primitive("f32"),
496                Some("number".to_string())
497            );
498            assert_eq!(
499                resolver.map_to_target_primitive("f64"),
500                Some("number".to_string())
501            );
502        }
503
504        #[test]
505        fn test_map_boolean() {
506            let resolver = TypeResolver::new();
507            assert_eq!(
508                resolver.map_to_target_primitive("bool"),
509                Some("boolean".to_string())
510            );
511        }
512
513        #[test]
514        fn test_map_unit_type() {
515            let resolver = TypeResolver::new();
516            assert_eq!(
517                resolver.map_to_target_primitive("()"),
518                Some("void".to_string())
519            );
520        }
521
522        #[test]
523        fn test_map_non_primitive() {
524            let resolver = TypeResolver::new();
525            assert_eq!(resolver.map_to_target_primitive("User"), None);
526            assert_eq!(resolver.map_to_target_primitive("CustomType"), None);
527        }
528    }
529
530    // Type extraction tests
531    mod type_extraction {
532        use super::*;
533
534        #[test]
535        fn test_extract_option_inner_type() {
536            let resolver = TypeResolver::new();
537
538            assert_eq!(
539                resolver.extract_option_inner_type("Option<String>"),
540                Some("String".to_string())
541            );
542            assert_eq!(
543                resolver.extract_option_inner_type("Option<User>"),
544                Some("User".to_string())
545            );
546            assert_eq!(resolver.extract_option_inner_type("String"), None);
547        }
548
549        #[test]
550        fn test_extract_result_ok_type() {
551            let resolver = TypeResolver::new();
552
553            assert_eq!(
554                resolver.extract_result_ok_type("Result<String, Error>"),
555                Some("String".to_string())
556            );
557            assert_eq!(
558                resolver.extract_result_ok_type("Result<User, String>"),
559                Some("User".to_string())
560            );
561            assert_eq!(
562                resolver.extract_result_ok_type("Result<()>"),
563                Some("()".to_string())
564            );
565            assert_eq!(resolver.extract_result_ok_type("String"), None);
566        }
567
568        #[test]
569        fn test_extract_vec_inner_type() {
570            let resolver = TypeResolver::new();
571
572            assert_eq!(
573                resolver.extract_vec_inner_type("Vec<String>"),
574                Some("String".to_string())
575            );
576            assert_eq!(
577                resolver.extract_vec_inner_type("Vec<User>"),
578                Some("User".to_string())
579            );
580            assert_eq!(resolver.extract_vec_inner_type("String"), None);
581        }
582
583        #[test]
584        fn test_extract_hashmap_types() {
585            let resolver = TypeResolver::new();
586
587            assert_eq!(
588                resolver.extract_hashmap_types("HashMap<String, User>"),
589                Some(("String".to_string(), "User".to_string()))
590            );
591            assert_eq!(
592                resolver.extract_hashmap_types("HashMap<i32, String>"),
593                Some(("i32".to_string(), "String".to_string()))
594            );
595            assert_eq!(resolver.extract_hashmap_types("String"), None);
596        }
597
598        #[test]
599        fn test_extract_btreemap_types() {
600            let resolver = TypeResolver::new();
601
602            assert_eq!(
603                resolver.extract_btreemap_types("BTreeMap<String, User>"),
604                Some(("String".to_string(), "User".to_string()))
605            );
606            assert_eq!(resolver.extract_btreemap_types("String"), None);
607        }
608
609        #[test]
610        fn test_extract_hashset_inner_type() {
611            let resolver = TypeResolver::new();
612
613            assert_eq!(
614                resolver.extract_hashset_inner_type("HashSet<String>"),
615                Some("String".to_string())
616            );
617            assert_eq!(resolver.extract_hashset_inner_type("String"), None);
618        }
619
620        #[test]
621        fn test_extract_btreeset_inner_type() {
622            let resolver = TypeResolver::new();
623
624            assert_eq!(
625                resolver.extract_btreeset_inner_type("BTreeSet<User>"),
626                Some("User".to_string())
627            );
628            assert_eq!(resolver.extract_btreeset_inner_type("String"), None);
629        }
630
631        #[test]
632        fn test_extract_tuple_types() {
633            let resolver = TypeResolver::new();
634
635            assert_eq!(
636                resolver.extract_tuple_types("(String, i32)"),
637                Some(vec!["String".to_string(), "i32".to_string()])
638            );
639            assert_eq!(
640                resolver.extract_tuple_types("(String, i32, bool)"),
641                Some(vec![
642                    "String".to_string(),
643                    "i32".to_string(),
644                    "bool".to_string()
645                ])
646            );
647            assert_eq!(resolver.extract_tuple_types("()"), Some(vec![]));
648            assert_eq!(resolver.extract_tuple_types("String"), None);
649        }
650
651        #[test]
652        fn test_extract_reference_type() {
653            let resolver = TypeResolver::new();
654
655            assert_eq!(
656                resolver.extract_reference_type("&String"),
657                Some("String".to_string())
658            );
659            assert_eq!(
660                resolver.extract_reference_type("&str"),
661                Some("str".to_string())
662            );
663            assert_eq!(resolver.extract_reference_type("String"), None);
664        }
665
666        #[test]
667        fn test_parse_two_type_params_simple() {
668            let resolver = TypeResolver::new();
669
670            assert_eq!(
671                resolver.parse_two_type_params("String, User"),
672                Some(("String".to_string(), "User".to_string()))
673            );
674        }
675
676        #[test]
677        fn test_parse_two_type_params_nested() {
678            let resolver = TypeResolver::new();
679
680            // HashMap<String, Vec<User>>
681            assert_eq!(
682                resolver.parse_two_type_params("String, Vec<User>"),
683                Some(("String".to_string(), "Vec<User>".to_string()))
684            );
685        }
686
687        #[test]
688        fn test_parse_two_type_params_no_comma() {
689            let resolver = TypeResolver::new();
690            assert_eq!(resolver.parse_two_type_params("String"), None);
691        }
692    }
693
694    // TypeStructure parsing tests
695    mod type_structure_parsing {
696        use super::*;
697
698        #[test]
699        fn test_parse_primitive_string() {
700            let resolver = TypeResolver::new();
701            let result = resolver.parse_type_structure("String");
702
703            match result {
704                TypeStructure::Primitive(name) => assert_eq!(name, "string"),
705                _ => panic!("Should be Primitive"),
706            }
707        }
708
709        #[test]
710        fn test_parse_primitive_number() {
711            let resolver = TypeResolver::new();
712            let result = resolver.parse_type_structure("i32");
713
714            match result {
715                TypeStructure::Primitive(name) => assert_eq!(name, "number"),
716                _ => panic!("Should be Primitive"),
717            }
718        }
719
720        #[test]
721        fn test_parse_primitive_boolean() {
722            let resolver = TypeResolver::new();
723            let result = resolver.parse_type_structure("bool");
724
725            match result {
726                TypeStructure::Primitive(name) => assert_eq!(name, "boolean"),
727                _ => panic!("Should be Primitive"),
728            }
729        }
730
731        #[test]
732        fn test_parse_primitive_void() {
733            let resolver = TypeResolver::new();
734            let result = resolver.parse_type_structure("()");
735
736            match result {
737                TypeStructure::Primitive(name) => assert_eq!(name, "void"),
738                _ => panic!("Should be Primitive"),
739            }
740        }
741
742        #[test]
743        fn test_parse_custom_type() {
744            let resolver = TypeResolver::new();
745            let result = resolver.parse_type_structure("User");
746
747            match result {
748                TypeStructure::Custom(name) => assert_eq!(name, "User"),
749                _ => panic!("Should be Custom"),
750            }
751        }
752
753        #[test]
754        fn test_parse_reference() {
755            let resolver = TypeResolver::new();
756            let result = resolver.parse_type_structure("&String");
757
758            match result {
759                TypeStructure::Primitive(name) => assert_eq!(name, "string"),
760                _ => panic!("Should unwrap reference to string"),
761            }
762        }
763
764        #[test]
765        fn test_parse_option() {
766            let resolver = TypeResolver::new();
767            let result = resolver.parse_type_structure("Option<String>");
768
769            match result {
770                TypeStructure::Optional(inner) => match *inner {
771                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
772                    _ => panic!("Inner should be string"),
773                },
774                _ => panic!("Should be Optional"),
775            }
776        }
777
778        #[test]
779        fn test_parse_result() {
780            let resolver = TypeResolver::new();
781            let result = resolver.parse_type_structure("Result<User, Error>");
782
783            match result {
784                TypeStructure::Result(inner) => match *inner {
785                    TypeStructure::Custom(name) => assert_eq!(name, "User"),
786                    _ => panic!("Inner should be User"),
787                },
788                _ => panic!("Should be Result"),
789            }
790        }
791
792        #[test]
793        fn test_parse_vec() {
794            let resolver = TypeResolver::new();
795            let result = resolver.parse_type_structure("Vec<String>");
796
797            match result {
798                TypeStructure::Array(inner) => match *inner {
799                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
800                    _ => panic!("Inner should be string"),
801                },
802                _ => panic!("Should be Array"),
803            }
804        }
805
806        #[test]
807        fn test_parse_hashmap() {
808            let resolver = TypeResolver::new();
809            let result = resolver.parse_type_structure("HashMap<String, User>");
810
811            match result {
812                TypeStructure::Map { key, value } => match (*key, *value) {
813                    (TypeStructure::Primitive(k), TypeStructure::Custom(v)) => {
814                        assert_eq!(k, "string");
815                        assert_eq!(v, "User");
816                    }
817                    _ => panic!("Key should be string, value should be User"),
818                },
819                _ => panic!("Should be Map"),
820            }
821        }
822
823        #[test]
824        fn test_parse_btreemap() {
825            let resolver = TypeResolver::new();
826            let result = resolver.parse_type_structure("BTreeMap<i32, String>");
827
828            match result {
829                TypeStructure::Map { key, value } => match (*key, *value) {
830                    (TypeStructure::Primitive(k), TypeStructure::Primitive(v)) => {
831                        assert_eq!(k, "number");
832                        assert_eq!(v, "string");
833                    }
834                    _ => panic!("Key should be number, value should be string"),
835                },
836                _ => panic!("Should be Map"),
837            }
838        }
839
840        #[test]
841        fn test_parse_hashset() {
842            let resolver = TypeResolver::new();
843            let result = resolver.parse_type_structure("HashSet<String>");
844
845            match result {
846                TypeStructure::Set(inner) => match *inner {
847                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
848                    _ => panic!("Inner should be string"),
849                },
850                _ => panic!("Should be Set"),
851            }
852        }
853
854        #[test]
855        fn test_parse_btreeset() {
856            let resolver = TypeResolver::new();
857            let result = resolver.parse_type_structure("BTreeSet<User>");
858
859            match result {
860                TypeStructure::Set(inner) => match *inner {
861                    TypeStructure::Custom(name) => assert_eq!(name, "User"),
862                    _ => panic!("Inner should be User"),
863                },
864                _ => panic!("Should be Set"),
865            }
866        }
867
868        #[test]
869        fn test_parse_tuple() {
870            let resolver = TypeResolver::new();
871            let result = resolver.parse_type_structure("(String, i32)");
872
873            match result {
874                TypeStructure::Tuple(types) => {
875                    assert_eq!(types.len(), 2);
876                    match &types[0] {
877                        TypeStructure::Primitive(name) => assert_eq!(name, "string"),
878                        _ => panic!("First type should be string"),
879                    }
880                    match &types[1] {
881                        TypeStructure::Primitive(name) => assert_eq!(name, "number"),
882                        _ => panic!("Second type should be number"),
883                    }
884                }
885                _ => panic!("Should be Tuple"),
886            }
887        }
888
889        #[test]
890        fn test_parse_empty_tuple() {
891            let resolver = TypeResolver::new();
892            let result = resolver.parse_type_structure("()");
893
894            match result {
895                TypeStructure::Primitive(name) => assert_eq!(name, "void"),
896                _ => panic!("Empty tuple should be void"),
897            }
898        }
899
900        #[test]
901        fn test_parse_nested_option_vec() {
902            let resolver = TypeResolver::new();
903            let result = resolver.parse_type_structure("Option<Vec<String>>");
904
905            match result {
906                TypeStructure::Optional(opt_inner) => match *opt_inner {
907                    TypeStructure::Array(arr_inner) => match *arr_inner {
908                        TypeStructure::Primitive(name) => assert_eq!(name, "string"),
909                        _ => panic!("Should be string"),
910                    },
911                    _ => panic!("Should be Array"),
912                },
913                _ => panic!("Should be Optional"),
914            }
915        }
916
917        #[test]
918        fn test_parse_vec_option() {
919            let resolver = TypeResolver::new();
920            let result = resolver.parse_type_structure("Vec<Option<User>>");
921
922            match result {
923                TypeStructure::Array(arr_inner) => match *arr_inner {
924                    TypeStructure::Optional(opt_inner) => match *opt_inner {
925                        TypeStructure::Custom(name) => assert_eq!(name, "User"),
926                        _ => panic!("Should be User"),
927                    },
928                    _ => panic!("Should be Optional"),
929                },
930                _ => panic!("Should be Array"),
931            }
932        }
933
934        #[test]
935        fn test_parse_hashmap_with_vec_value() {
936            let resolver = TypeResolver::new();
937            let result = resolver.parse_type_structure("HashMap<String, Vec<User>>");
938
939            match result {
940                TypeStructure::Map { key, value } => match (*key, *value) {
941                    (TypeStructure::Primitive(k), TypeStructure::Array(v_arr)) => {
942                        assert_eq!(k, "string");
943                        match *v_arr {
944                            TypeStructure::Custom(name) => assert_eq!(name, "User"),
945                            _ => panic!("Array value should be User"),
946                        }
947                    }
948                    _ => panic!("Key should be string, value should be Array"),
949                },
950                _ => panic!("Should be Map"),
951            }
952        }
953
954        #[test]
955        fn test_parse_result_with_unit_ok() {
956            let resolver = TypeResolver::new();
957            let result = resolver.parse_type_structure("Result<(), String>");
958
959            match result {
960                TypeStructure::Result(inner) => match *inner {
961                    TypeStructure::Primitive(name) => assert_eq!(name, "void"),
962                    _ => panic!("Should be void"),
963                },
964                _ => panic!("Should be Result"),
965            }
966        }
967
968        #[test]
969        fn test_parse_complex_nested() {
970            let resolver = TypeResolver::new();
971            // Test a simpler but still complex nested type that works
972            // Option<Vec<HashMap<String, User>>>
973            let result = resolver.parse_type_structure("Option<Vec<HashMap<String, User>>>");
974
975            match result {
976                TypeStructure::Optional(opt) => match *opt {
977                    TypeStructure::Array(arr) => match *arr {
978                        TypeStructure::Map { key, value } => match (*key, *value) {
979                            (TypeStructure::Primitive(k), TypeStructure::Custom(v)) => {
980                                assert_eq!(k, "string");
981                                assert_eq!(v, "User");
982                            }
983                            _ => panic!("Map types incorrect"),
984                        },
985                        _ => panic!("Should be Map"),
986                    },
987                    _ => panic!("Should be Array"),
988                },
989                _ => panic!("Should be Optional"),
990            }
991        }
992
993        #[test]
994        fn test_parse_result_with_simple_nested() {
995            let resolver = TypeResolver::new();
996            // Result<Vec<User>, Error>
997            let result = resolver.parse_type_structure("Result<Vec<User>, Error>");
998
999            match result {
1000                TypeStructure::Result(res) => match *res {
1001                    TypeStructure::Array(arr) => match *arr {
1002                        TypeStructure::Custom(name) => assert_eq!(name, "User"),
1003                        _ => panic!("Should be User"),
1004                    },
1005                    _ => panic!("Should be Array"),
1006                },
1007                _ => panic!("Should be Result"),
1008            }
1009        }
1010
1011        #[test]
1012        fn test_parse_with_whitespace() {
1013            let resolver = TypeResolver::new();
1014            // Note: The type resolver doesn't handle spaces inside generic brackets well
1015            // "Option < String >" is not recognized as Option<String> - it's treated as custom type
1016            let result = resolver.parse_type_structure("  Option<String>  ");
1017
1018            match result {
1019                TypeStructure::Optional(inner) => match *inner {
1020                    TypeStructure::Primitive(name) => assert_eq!(name, "string"),
1021                    _ => panic!("Should be string"),
1022                },
1023                _ => panic!("Should be Optional"),
1024            }
1025        }
1026    }
1027}