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 pub fn parse_type_structure(&self, rust_type: &str) -> TypeStructure {
178 let cleaned = rust_type.trim();
179
180 if let Some(inner) = self.extract_reference_type(cleaned) {
182 return self.parse_type_structure(&inner);
183 }
184
185 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 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 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 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 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 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 if let Some(target_primitive) = self.map_to_target_primitive(cleaned) {
233 return TypeStructure::Primitive(target_primitive);
234 }
235
236 TypeStructure::Custom(cleaned.to_string())
238 }
239
240 fn map_to_target_primitive(&self, rust_type: &str) -> Option<String> {
243 match rust_type {
244 "String" | "str" | "&str" => Some("string".to_string()),
246 "i8" | "i16" | "i32" | "i64" | "i128" | "isize" | "u8" | "u16" | "u32" | "u64"
248 | "u128" | "usize" | "f32" | "f64" => Some("number".to_string()),
249 "bool" => Some("boolean".to_string()),
251 "()" => Some("void".to_string()),
253 _ => None,
255 }
256 }
257
258 pub fn get_type_mappings(&self) -> &HashMap<String, String> {
260 &self.type_mappings
261 }
262
263 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 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 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 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 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 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 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 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 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}