1pub fn format_bytes(bytes: usize) -> String {
5 if bytes < 1024 {
6 format!("{bytes}B")
7 } else if bytes < 1024 * 1024 {
8 format!("{:.1}KB", bytes as f64 / 1024.0)
9 } else {
10 format!("{:.1}MB", bytes as f64 / (1024.0 * 1024.0))
11 }
12}
13
14pub fn simplify_type_name(type_name: &str) -> (String, String) {
16 if type_name.is_empty() || type_name == "Unknown" {
18 return ("Unknown Type".to_string(), "Unknown".to_string());
19 }
20
21 let clean_type = type_name.trim();
23
24 if clean_type.contains("Vec<") || clean_type.contains("vec::Vec") {
26 let inner = extract_generic_type(clean_type, "Vec");
27 (format!("Vec<{inner}>"), "Collections".to_string())
28 } else if clean_type.contains("String") || clean_type.contains("string::String") {
29 ("String".to_string(), "Basic Types".to_string())
30 } else if clean_type.contains("Box<") || clean_type.contains("boxed::Box") {
31 let inner = extract_generic_type(clean_type, "Box");
32 if inner.contains("HashMap") || inner.contains("hash_map") {
34 ("HashMap<K,V>".to_string(), "Collections".to_string())
35 } else if inner.contains("BTreeMap") || inner.contains("btree_map") {
36 ("BTreeMap<K,V>".to_string(), "Collections".to_string())
37 } else if inner.contains("BTreeSet") || inner.contains("btree_set") {
38 ("BTreeSet<T>".to_string(), "Collections".to_string())
39 } else if inner.contains("HashSet") || inner.contains("hash_set") {
40 ("HashSet<T>".to_string(), "Collections".to_string())
41 } else if inner.contains("VecDeque") || inner.contains("vec_deque") {
42 ("VecDeque<T>".to_string(), "Collections".to_string())
43 } else if inner.contains("Vec") || inner.contains("vec::Vec") {
44 let vec_inner = extract_generic_type(&inner, "Vec");
45 (format!("Vec<{vec_inner}>"), "Collections".to_string())
46 } else {
47 (format!("Box<{inner}>"), "Smart Pointers".to_string())
48 }
49 } else if clean_type.contains("Rc<") || clean_type.contains("rc::Rc") {
50 let inner = extract_generic_type(clean_type, "Rc");
51 (format!("Rc<{inner}>"), "Smart Pointers".to_string())
52 } else if clean_type.contains("Arc<") || clean_type.contains("sync::Arc") {
53 let inner = extract_generic_type(clean_type, "Arc");
54 (format!("Arc<{inner}>"), "Smart Pointers".to_string())
55 } else if clean_type.contains("HashMap") || clean_type.contains("hash_map") {
56 ("HashMap<K,V>".to_string(), "Collections".to_string())
57 } else if clean_type.contains("BTreeMap") || clean_type.contains("btree_map") {
58 ("BTreeMap<K,V>".to_string(), "Collections".to_string())
59 } else if clean_type.contains("BTreeSet") || clean_type.contains("btree_set") {
60 ("BTreeSet<T>".to_string(), "Collections".to_string())
61 } else if clean_type.contains("HashSet") || clean_type.contains("hash_set") {
62 ("HashSet<T>".to_string(), "Collections".to_string())
63 } else if clean_type.contains("VecDeque") || clean_type.contains("vec_deque") {
64 ("VecDeque<T>".to_string(), "Collections".to_string())
65 } else if clean_type.contains("LinkedList") {
66 ("LinkedList<T>".to_string(), "Collections".to_string())
67 } else if clean_type.contains("&str") || clean_type == "str" {
68 ("&str".to_string(), "Basic Types".to_string())
69 } else if clean_type.contains("CString") || clean_type.contains("CStr") {
70 ("CString".to_string(), "Basic Types".to_string())
71 } else if clean_type.contains("OsString") || clean_type.contains("OsStr") {
72 ("OsString".to_string(), "Basic Types".to_string())
73 } else if clean_type.contains("PathBuf") || clean_type.contains("Path") {
74 ("PathBuf".to_string(), "Basic Types".to_string())
75 } else if clean_type.matches("i32").count() > 0
76 || clean_type.matches("u32").count() > 0
77 || clean_type.matches("i64").count() > 0
78 || clean_type.matches("u64").count() > 0
79 || clean_type.matches("f64").count() > 0
80 || clean_type.matches("f32").count() > 0
81 || clean_type.matches("i8").count() > 0
82 || clean_type.matches("u8").count() > 0
83 || clean_type.matches("i16").count() > 0
84 || clean_type.matches("u16").count() > 0
85 || clean_type.matches("isize").count() > 0
86 || clean_type.matches("usize").count() > 0
87 || clean_type.matches("bool").count() > 0
88 || clean_type.matches("char").count() > 0
89 {
90 let primitive = clean_type.split("::").last().unwrap_or(clean_type);
91 (primitive.to_string(), "Basic Types".to_string())
92 } else if clean_type.contains("[") && clean_type.contains("]") {
93 ("Array".to_string(), "Arrays".to_string())
94 } else if clean_type.starts_with("(") && clean_type.ends_with(")") {
95 ("Tuple".to_string(), "Tuples".to_string())
96 } else if clean_type.contains("Option<") {
97 ("Option<T>".to_string(), "Optionals".to_string())
98 } else if clean_type.contains("Result<") {
99 ("Result<T,E>".to_string(), "Results".to_string())
100 } else if clean_type.contains("Mutex<") || clean_type.contains("RwLock<") {
101 ("Mutex/RwLock".to_string(), "Synchronization".to_string())
102 } else if clean_type.contains("Cell<") || clean_type.contains("RefCell<") {
103 (
104 "Cell/RefCell".to_string(),
105 "Interior Mutability".to_string(),
106 )
107 } else if clean_type.contains("Weak<") {
108 ("Weak<T>".to_string(), "Smart Pointers".to_string())
109 } else if clean_type.starts_with("std::")
110 || clean_type.starts_with("alloc::")
111 || clean_type.starts_with("core::")
112 {
113 let simplified = clean_type.split("::").last().unwrap_or(clean_type);
114 (simplified.to_string(), "Standard Library".to_string())
115 } else if clean_type.contains("::") {
116 let parts: Vec<&str> = clean_type.split("::").collect();
118 if parts.len() >= 2 {
119 let type_part = parts.last().unwrap();
120 if type_part.ends_with("Error") || type_part.contains("Err") {
122 (type_part.to_string(), "Error Types".to_string())
123 } else if type_part.ends_with("Config") || type_part.ends_with("Settings") {
124 (type_part.to_string(), "Configuration".to_string())
125 } else if type_part.ends_with("Builder") {
126 (type_part.to_string(), "Builders".to_string())
127 } else {
128 (type_part.to_string(), "Custom Types".to_string())
129 }
130 } else {
131 (clean_type.to_string(), "Custom Types".to_string())
132 }
133 } else {
134 if clean_type.len() > 0 {
136 (clean_type.to_string(), "Custom Types".to_string())
137 } else {
138 ("Unknown Type".to_string(), "Unknown".to_string())
139 }
140 }
141}
142
143pub fn extract_generic_type(type_name: &str, container: &str) -> String {
145 if let Some(start) = type_name.find(&format!("{container}<")) {
146 let start = start + container.len() + 1;
147 if let Some(end) = type_name[start..].rfind('>') {
148 let inner = &type_name[start..start + end];
149 return inner.split("::").last().unwrap_or(inner).to_string();
151 }
152 }
153 "?".to_string()
154}
155
156pub fn get_simple_type(type_name: &str) -> String {
158 if type_name.contains("String") {
159 "String".to_string()
160 } else if type_name.contains("Vec") {
161 "Vec".to_string()
162 } else if type_name.contains("Box") {
163 "Box".to_string()
164 } else if type_name.contains("Rc") {
165 "Rc".to_string()
166 } else if type_name.contains("Arc") {
167 "Arc".to_string()
168 } else if type_name.contains("HashMap") {
169 "HashMap".to_string()
170 } else {
171 type_name
172 .split("::")
173 .last()
174 .unwrap_or("Unknown")
175 .to_string()
176 }
177}
178
179pub fn get_category_color(category: &str) -> String {
181 match category {
182 "Collections" => "#3498db".to_string(), "Basic Types" => "#27ae60".to_string(), "Strings" => "#27ae60".to_string(), "Text" => "#27ae60".to_string(), "Smart Pointers" => "#e74c3c".to_string(), "Reference Counted" => "#f39c12".to_string(), "Thread-Safe Shared" => "#9b59b6".to_string(), "Primitives" => "#1abc9c".to_string(), "Arrays" => "#34495e".to_string(), "Tuples" => "#16a085".to_string(), "Optionals" => "#8e44ad".to_string(), "Results" => "#d35400".to_string(), "Standard Library" => "#2980b9".to_string(), "Custom Types" => "#c0392b".to_string(), "Synchronization" => "#e67e22".to_string(), "Interior Mutability" => "#95a5a6".to_string(), "Error Types" => "#e74c3c".to_string(), "Configuration" => "#3498db".to_string(), "Builders" => "#9b59b6".to_string(), "Runtime/System Allocation" => "#bdc3c7".to_string(), "Unknown" => "#bdc3c7".to_string(), _ => "#7f8c8d".to_string(), }
205}
206
207pub fn get_type_gradient_colors(type_name: &str) -> (&'static str, &'static str) {
209 match type_name {
210 "String" => ("#00BCD4", "#00ACC1"), "Vec" => ("#2196F3", "#1976D2"), "Box" => ("#F44336", "#D32F2F"), "HashMap" => ("#4CAF50", "#388E3C"), "Rc" => ("#FF9800", "#F57C00"), "Arc" => ("#9C27B0", "#7B1FA2"), _ => ("#607D8B", "#455A64"), }
218}
219
220pub fn get_type_color(type_name: &str) -> &'static str {
222 match type_name {
223 "String" => "#2ecc71",
224 "Vec" => "#3498db",
225 "Box" => "#e74c3c",
226 "HashMap" => "#f39c12",
227 "Rc" => "#9b59b6",
228 "Arc" => "#1abc9c",
229 _ => "#95a5a6",
230 }
231}
232
233#[derive(Debug, Clone)]
235pub struct TypeHierarchy {
236 pub major_category: String,
238 pub sub_category: String,
240 pub specific_type: String,
242 pub full_type: String,
244}
245
246pub fn get_type_category_hierarchy(type_name: &str) -> TypeHierarchy {
248 if type_name.is_empty() || type_name == "Unknown" {
250 return TypeHierarchy {
251 major_category: "Unknown".to_string(),
252 sub_category: "Unidentified".to_string(),
253 specific_type: "Unknown Type".to_string(),
254 full_type: type_name.to_string(),
255 };
256 }
257
258 if type_name.contains("HashMap") || type_name.contains("hash::map") {
260 let inner = extract_generic_params(type_name, "HashMap");
261 TypeHierarchy {
262 major_category: "Collections".to_string(),
263 sub_category: "Maps".to_string(),
264 specific_type: "HashMap".to_string(),
265 full_type: if inner.is_empty() {
266 "HashMap".to_string()
267 } else {
268 format!("HashMap<{}>", inner)
269 },
270 }
271 } else if type_name.contains("BTreeMap") || type_name.contains("btree::map") {
272 let inner = extract_generic_params(type_name, "BTreeMap");
273 TypeHierarchy {
274 major_category: "Collections".to_string(),
275 sub_category: "Maps".to_string(),
276 specific_type: "BTreeMap".to_string(),
277 full_type: if inner.is_empty() {
278 "BTreeMap".to_string()
279 } else {
280 format!("BTreeMap<{}>", inner)
281 },
282 }
283 } else if type_name.contains("HashSet") || type_name.contains("hash::set") {
284 let inner = extract_generic_params(type_name, "HashSet");
285 TypeHierarchy {
286 major_category: "Collections".to_string(),
287 sub_category: "Sets".to_string(),
288 specific_type: "HashSet".to_string(),
289 full_type: if inner.is_empty() {
290 "HashSet".to_string()
291 } else {
292 format!("HashSet<{}>", inner)
293 },
294 }
295 } else if type_name.contains("Vec") && !type_name.contains("VecDeque") {
296 let inner = extract_generic_params(type_name, "Vec");
297 TypeHierarchy {
298 major_category: "Collections".to_string(),
299 sub_category: "Sequences".to_string(),
300 specific_type: "Vec".to_string(),
301 full_type: if inner.is_empty() {
302 "Vec".to_string()
303 } else {
304 format!("Vec<{}>", inner)
305 },
306 }
307 } else if type_name.contains("VecDeque") {
308 let inner = extract_generic_params(type_name, "VecDeque");
309 TypeHierarchy {
310 major_category: "Collections".to_string(),
311 sub_category: "Sequences".to_string(),
312 specific_type: "VecDeque".to_string(),
313 full_type: if inner.is_empty() {
314 "VecDeque".to_string()
315 } else {
316 format!("VecDeque<{}>", inner)
317 },
318 }
319 }
320 else if type_name.contains("String") && !type_name.contains("<") {
322 TypeHierarchy {
323 major_category: "Strings".to_string(),
324 sub_category: "Owned".to_string(),
325 specific_type: "String".to_string(),
326 full_type: "String".to_string(),
327 }
328 } else if type_name.contains("&str") || (type_name.contains("str") && type_name.contains("&")) {
329 TypeHierarchy {
330 major_category: "Strings".to_string(),
331 sub_category: "Borrowed".to_string(),
332 specific_type: "&str".to_string(),
333 full_type: "&str".to_string(),
334 }
335 }
336 else if type_name.contains("Box<") {
338 let inner = extract_generic_params(type_name, "Box");
339 TypeHierarchy {
340 major_category: "Smart Pointers".to_string(),
341 sub_category: "Owned".to_string(),
342 specific_type: "Box".to_string(),
343 full_type: if inner.is_empty() {
344 "Box".to_string()
345 } else {
346 format!("Box<{}>", inner)
347 },
348 }
349 } else if type_name.contains("Rc<") {
350 let inner = extract_generic_params(type_name, "Rc");
351 TypeHierarchy {
352 major_category: "Smart Pointers".to_string(),
353 sub_category: "Reference Counted".to_string(),
354 specific_type: "Rc".to_string(),
355 full_type: if inner.is_empty() {
356 "Rc".to_string()
357 } else {
358 format!("Rc<{}>", inner)
359 },
360 }
361 } else if type_name.contains("Arc<") {
362 let inner = extract_generic_params(type_name, "Arc");
363 TypeHierarchy {
364 major_category: "Smart Pointers".to_string(),
365 sub_category: "Thread-Safe Shared".to_string(),
366 specific_type: "Arc".to_string(),
367 full_type: if inner.is_empty() {
368 "Arc".to_string()
369 } else {
370 format!("Arc<{}>", inner)
371 },
372 }
373 }
374 else if is_primitive_type(type_name) {
376 let clean_type = type_name.split("::").last().unwrap_or(type_name);
377 let sub_cat = if clean_type.contains("i") || clean_type.contains("u") {
378 "Integers"
379 } else if clean_type.contains("f") {
380 "Floats"
381 } else if clean_type == "bool" {
382 "Boolean"
383 } else {
384 "Other"
385 };
386 TypeHierarchy {
387 major_category: "Primitives".to_string(),
388 sub_category: sub_cat.to_string(),
389 specific_type: clean_type.to_string(),
390 full_type: clean_type.to_string(),
391 }
392 }
393 else {
395 let simplified = type_name.split("::").last().unwrap_or(type_name);
396 TypeHierarchy {
397 major_category: "Custom Types".to_string(),
398 sub_category: "User Defined".to_string(),
399 specific_type: simplified.to_string(),
400 full_type: simplified.to_string(),
401 }
402 }
403}
404
405pub fn extract_generic_params(type_name: &str, container: &str) -> String {
407 if let Some(start) = type_name.find(&format!("{}<", container)) {
408 let start = start + container.len() + 1;
409 if let Some(end) = find_matching_bracket(type_name, start - 1) {
410 let inner = &type_name[start..end];
411 return inner.split("::").last().unwrap_or(inner).to_string();
413 }
414 }
415 String::new()
416}
417
418fn find_matching_bracket(s: &str, start: usize) -> Option<usize> {
420 let chars: Vec<char> = s.chars().collect();
421 if start >= chars.len() || chars[start] != '<' {
422 return None;
423 }
424
425 let mut depth = 1;
426 for i in (start + 1)..chars.len() {
427 match chars[i] {
428 '<' => depth += 1,
429 '>' => {
430 depth -= 1;
431 if depth == 0 {
432 return Some(i);
433 }
434 }
435 _ => {}
436 }
437 }
438 None
439}
440
441pub fn is_primitive_type(type_name: &str) -> bool {
443 let clean_type = type_name.split("::").last().unwrap_or(type_name);
444 matches!(
445 clean_type,
446 "i8" | "i16"
447 | "i32"
448 | "i64"
449 | "i128"
450 | "isize"
451 | "u8"
452 | "u16"
453 | "u32"
454 | "u64"
455 | "u128"
456 | "usize"
457 | "f32"
458 | "f64"
459 | "bool"
460 | "char"
461 )
462}
463
464pub fn extract_array_info(type_name: &str) -> String {
466 if let Some(start) = type_name.find('[') {
467 if let Some(end) = type_name.find(']') {
468 return type_name[start..=end].to_string();
469 }
470 }
471 "Array".to_string()
472}
473
474pub fn extract_std_module(type_name: &str) -> String {
476 let parts: Vec<&str> = type_name.split("::").collect();
477 if parts.len() >= 2 {
478 match parts[1] {
479 "collections" => "Collections".to_string(),
480 "sync" => "Synchronization".to_string(),
481 "thread" => "Threading".to_string(),
482 "fs" => "File System".to_string(),
483 "net" => "Networking".to_string(),
484 "io" => "Input/Output".to_string(),
485 _ => "Other".to_string(),
486 }
487 } else {
488 "Other".to_string()
489 }
490}