1use crate::models::TypeStructure;
2use std::collections::{HashMap, HashSet};
3
4#[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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn get_type_set(&self) -> &HashSet<String> {
172 &self.type_set
173 }
174
175 fn strip_module_prefix(&self, type_str: &str) -> String {
181 let type_str = type_str.trim();
182
183 let angle_bracket_pos = type_str.find('<');
185
186 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 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 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 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 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 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 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 if let Some(inner) = self.extract_reference_type(cleaned_str) {
263 return self.parse_type_structure(&inner);
264 }
265
266 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 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 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 if cleaned_str.starts_with('[') && cleaned_str.ends_with(']') {
283 let inner = &cleaned_str[1..cleaned_str.len() - 1];
284 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 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 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 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 if let Some(target_primitive) = self.map_to_target_primitive(cleaned_str) {
329 return TypeStructure::Primitive(target_primitive);
330 }
331
332 TypeStructure::Custom(cleaned)
334 }
335
336 fn map_to_target_primitive(&self, rust_type: &str) -> Option<String> {
339 match rust_type {
340 "String" | "str" | "&str" => Some("string".to_string()),
342 "i8" | "i16" | "i32" | "i64" | "i128" | "isize" | "u8" | "u16" | "u32" | "u64"
344 | "u128" | "usize" | "f32" | "f64" => Some("number".to_string()),
345 "bool" => Some("boolean".to_string()),
347 "()" => Some("void".to_string()),
349 _ => None,
351 }
352 }
353
354 pub fn get_type_mappings(&self) -> &HashMap<String, String> {
356 &self.type_mappings
357 }
358
359 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 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 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 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 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 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 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 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 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}