memscope_rs/
utils.rs

1//! Common utility functions shared across modules
2
3use std::time::{SystemTime, UNIX_EPOCH};
4
5/// Get current timestamp in nanoseconds since Unix epoch
6pub fn current_timestamp_nanos() -> u64 {
7    SystemTime::now()
8        .duration_since(UNIX_EPOCH)
9        .unwrap_or_default()
10        .as_nanos() as u64
11}
12
13/// Format bytes in a human-readable format
14pub fn format_bytes(bytes: usize) -> String {
15    if bytes < 1024 {
16        format!("{bytes}B")
17    } else if bytes < 1024 * 1024 {
18        format!("{:.1}KB", bytes as f64 / 1024.0)
19    } else {
20        format!("{:.1}MB", bytes as f64 / (1024.0 * 1024.0))
21    }
22}
23
24/// Simplify Rust type names for better readability - Enhanced Unknown Type identification
25pub fn simplify_type_name(type_name: &str) -> (String, String) {
26    // Handle empty or explicitly unknown types first
27    if type_name.is_empty() || type_name == "Unknown" {
28        return ("Unknown Type".to_string(), "Unknown".to_string());
29    }
30
31    // Clean up the type name - remove extra whitespace and normalize
32    let clean_type = type_name.trim();
33
34    // Enhanced pattern matching with more comprehensive coverage
35    if clean_type.contains("Vec<") || clean_type.contains("vec::Vec") {
36        let inner = extract_generic_type(clean_type, "Vec");
37        (format!("Vec<{inner}>"), "Collections".to_string())
38    } else if clean_type.contains("String") || clean_type.contains("string::String") {
39        ("String".to_string(), "Basic Types".to_string())
40    } else if clean_type.contains("Box<") || clean_type.contains("boxed::Box") {
41        let inner = extract_generic_type(clean_type, "Box");
42        // Check if the inner type is a collection - if so, categorize as collection
43        if inner.contains("HashMap") || inner.contains("hash_map") {
44            ("HashMap<K,V>".to_string(), "Collections".to_string())
45        } else if inner.contains("BTreeMap") || inner.contains("btree_map") {
46            ("BTreeMap<K,V>".to_string(), "Collections".to_string())
47        } else if inner.contains("BTreeSet") || inner.contains("btree_set") {
48            ("BTreeSet<T>".to_string(), "Collections".to_string())
49        } else if inner.contains("HashSet") || inner.contains("hash_set") {
50            ("HashSet<T>".to_string(), "Collections".to_string())
51        } else if inner.contains("VecDeque") || inner.contains("vec_deque") {
52            ("VecDeque<T>".to_string(), "Collections".to_string())
53        } else if inner.contains("Vec") || inner.contains("vec::Vec") {
54            let vec_inner = extract_generic_type(&inner, "Vec");
55            (format!("Vec<{vec_inner}>"), "Collections".to_string())
56        } else {
57            (format!("Box<{inner}>"), "Smart Pointers".to_string())
58        }
59    } else if clean_type.contains("Rc<") || clean_type.contains("rc::Rc") {
60        let inner = extract_generic_type(clean_type, "Rc");
61        (format!("Rc<{inner}>"), "Smart Pointers".to_string())
62    } else if clean_type.contains("Arc<") || clean_type.contains("sync::Arc") {
63        let inner = extract_generic_type(clean_type, "Arc");
64        (format!("Arc<{inner}>"), "Smart Pointers".to_string())
65    } else if clean_type.contains("HashMap") || clean_type.contains("hash_map") {
66        ("HashMap<K,V>".to_string(), "Collections".to_string())
67    } else if clean_type.contains("BTreeMap") || clean_type.contains("btree_map") {
68        ("BTreeMap<K,V>".to_string(), "Collections".to_string())
69    } else if clean_type.contains("BTreeSet") || clean_type.contains("btree_set") {
70        ("BTreeSet<T>".to_string(), "Collections".to_string())
71    } else if clean_type.contains("HashSet") || clean_type.contains("hash_set") {
72        ("HashSet<T>".to_string(), "Collections".to_string())
73    } else if clean_type.contains("VecDeque") || clean_type.contains("vec_deque") {
74        ("VecDeque<T>".to_string(), "Collections".to_string())
75    } else if clean_type.contains("LinkedList") {
76        ("LinkedList<T>".to_string(), "Collections".to_string())
77    } else if clean_type.contains("&str") || clean_type == "str" {
78        ("&str".to_string(), "Basic Types".to_string())
79    } else if clean_type.contains("CString") || clean_type.contains("CStr") {
80        ("CString".to_string(), "Basic Types".to_string())
81    } else if clean_type.contains("OsString") || clean_type.contains("OsStr") {
82        ("OsString".to_string(), "Basic Types".to_string())
83    } else if clean_type.contains("PathBuf") || clean_type.contains("Path") {
84        ("PathBuf".to_string(), "Basic Types".to_string())
85    } else if clean_type.matches("i32").count() > 0
86        || clean_type.matches("u32").count() > 0
87        || clean_type.matches("i64").count() > 0
88        || clean_type.matches("u64").count() > 0
89        || clean_type.matches("f64").count() > 0
90        || clean_type.matches("f32").count() > 0
91        || clean_type.matches("i8").count() > 0
92        || clean_type.matches("u8").count() > 0
93        || clean_type.matches("i16").count() > 0
94        || clean_type.matches("u16").count() > 0
95        || clean_type.matches("isize").count() > 0
96        || clean_type.matches("usize").count() > 0
97        || clean_type.matches("bool").count() > 0
98        || clean_type.matches("char").count() > 0
99    {
100        let primitive = clean_type.split("::").last().unwrap_or(clean_type);
101        (primitive.to_string(), "Basic Types".to_string())
102    } else if clean_type.contains("[") && clean_type.contains("]") {
103        ("Array".to_string(), "Arrays".to_string())
104    } else if clean_type.starts_with("(") && clean_type.ends_with(")") {
105        ("Tuple".to_string(), "Tuples".to_string())
106    } else if clean_type.contains("Option<") {
107        ("Option<T>".to_string(), "Optionals".to_string())
108    } else if clean_type.contains("Result<") {
109        ("Result<T,E>".to_string(), "Results".to_string())
110    } else if clean_type.contains("Mutex<") || clean_type.contains("RwLock<") {
111        ("Mutex/RwLock".to_string(), "Synchronization".to_string())
112    } else if clean_type.contains("Cell<") || clean_type.contains("RefCell<") {
113        (
114            "Cell/RefCell".to_string(),
115            "Interior Mutability".to_string(),
116        )
117    } else if clean_type.contains("Weak<") {
118        ("Weak<T>".to_string(), "Smart Pointers".to_string())
119    } else if clean_type.starts_with("std::")
120        || clean_type.starts_with("alloc::")
121        || clean_type.starts_with("core::")
122    {
123        let simplified = clean_type.split("::").last().unwrap_or(clean_type);
124        (simplified.to_string(), "Standard Library".to_string())
125    } else if clean_type.contains("::") {
126        // Handle custom types with namespaces
127        let parts: Vec<&str> = clean_type.split("::").collect();
128        if parts.len() >= 2 {
129            // Use the original clean_type as fallback if parts is somehow empty
130            let type_part = parts.last().unwrap_or(&clean_type);
131
132            // Determine category based on namespace and type patterns
133            let category = if parts
134                .iter()
135                .any(|&part| part.contains("error") || part.contains("Error"))
136                || type_part.ends_with("Error")
137                || type_part.contains("Err")
138            {
139                "Error Types"
140            } else if type_part.ends_with("Config") || type_part.ends_with("Settings") {
141                "Configuration"
142            } else if type_part.ends_with("Builder") || type_part.ends_with("Factory") {
143                "Builders"
144            } else if parts
145                .iter()
146                .any(|&part| part == "std" || part == "core" || part == "alloc")
147            {
148                "Standard Library"
149            } else if parts
150                .iter()
151                .any(|&part| part.contains("test") || part.contains("mock"))
152            {
153                "Test Types"
154            } else if parts.len() > 2 {
155                // Deep namespace suggests library or framework type
156                "Library Types"
157            } else {
158                "Custom Types"
159            };
160
161            (type_part.to_string(), category.to_string())
162        } else {
163            // Single part, no namespace
164            let category = if clean_type.ends_with("Error") || clean_type.contains("Err") {
165                "Error Types"
166            } else if clean_type.ends_with("Config") || clean_type.ends_with("Settings") {
167                "Configuration"
168            } else if clean_type.ends_with("Builder") || clean_type.ends_with("Factory") {
169                "Builders"
170            } else if clean_type.chars().next().is_some_and(|c| c.is_uppercase()) {
171                // Starts with uppercase, likely a struct/enum
172                "Custom Types"
173            } else {
174                // Lowercase, might be a function type or other
175                "Other Types"
176            };
177
178            (clean_type.to_string(), category.to_string())
179        }
180    } else {
181        // For simple type names without namespace
182        if !clean_type.is_empty() {
183            (clean_type.to_string(), "Custom Types".to_string())
184        } else {
185            ("Unknown Type".to_string(), "Unknown".to_string())
186        }
187    }
188}
189
190/// Extract generic type parameter for display
191pub fn extract_generic_type(type_name: &str, container: &str) -> String {
192    if let Some(start) = type_name.find(&format!("{container}<")) {
193        let start = start + container.len() + 1;
194        if let Some(end) = type_name[start..].rfind('>') {
195            let inner = &type_name[start..start + end];
196            // Simplify the inner type too
197            return inner.split("::").last().unwrap_or(inner).to_string();
198        }
199    }
200    "?".to_string()
201}
202
203/// Get a simplified type name for display
204pub fn get_simple_type(type_name: &str) -> String {
205    if type_name.contains("String") {
206        "String".to_string()
207    } else if type_name.contains("Vec") {
208        "Vec".to_string()
209    } else if type_name.contains("Box") {
210        "Box".to_string()
211    } else if type_name.contains("Rc") {
212        "Rc".to_string()
213    } else if type_name.contains("Arc") {
214        "Arc".to_string()
215    } else if type_name.contains("HashMap") {
216        "HashMap".to_string()
217    } else {
218        type_name
219            .split("::")
220            .last()
221            .unwrap_or("Unknown")
222            .to_string()
223    }
224}
225
226/// Get color for category - Enhanced with new categories
227pub fn get_category_color(category: &str) -> String {
228    match category {
229        "Collections" => "#3498db".to_string(),               // Blue
230        "Basic Types" => "#27ae60".to_string(),               // Green for Basic Types
231        "Strings" => "#27ae60".to_string(),                   // Green (legacy support)
232        "Text" => "#27ae60".to_string(),                      // Green (legacy support)
233        "Smart Pointers" => "#e74c3c".to_string(),            // Red
234        "Reference Counted" => "#f39c12".to_string(),         // Orange
235        "Thread-Safe Shared" => "#9b59b6".to_string(),        // Purple
236        "Primitives" => "#1abc9c".to_string(),                // Teal
237        "Arrays" => "#34495e".to_string(),                    // Dark Gray
238        "Tuples" => "#16a085".to_string(),                    // Dark Teal
239        "Optionals" => "#8e44ad".to_string(),                 // Dark Purple
240        "Results" => "#d35400".to_string(),                   // Dark Orange
241        "Standard Library" => "#2980b9".to_string(),          // Dark Blue
242        "Custom Types" => "#c0392b".to_string(),              // Dark Red
243        "Synchronization" => "#e67e22".to_string(),           // Orange
244        "Interior Mutability" => "#95a5a6".to_string(),       // Light Gray
245        "Error Types" => "#e74c3c".to_string(),               // Red
246        "Configuration" => "#3498db".to_string(),             // Blue
247        "Builders" => "#9b59b6".to_string(),                  // Purple
248        "Runtime/System Allocation" => "#bdc3c7".to_string(), // Light Gray for system allocations
249        "Unknown" => "#bdc3c7".to_string(),                   // Light Gray (legacy support)
250        _ => "#7f8c8d".to_string(),                           // Medium Gray for other unknowns
251    }
252}
253
254/// Get type-specific gradient colors for enhanced visualization
255pub fn get_type_gradient_colors(type_name: &str) -> (&'static str, &'static str) {
256    match type_name {
257        "String" => ("#00BCD4", "#00ACC1"),  // Teal gradient
258        "Vec" => ("#2196F3", "#1976D2"),     // Blue gradient
259        "Box" => ("#F44336", "#D32F2F"),     // Red gradient
260        "HashMap" => ("#4CAF50", "#388E3C"), // Green gradient
261        "Rc" => ("#FF9800", "#F57C00"),      // Orange gradient
262        "Arc" => ("#9C27B0", "#7B1FA2"),     // Purple gradient
263        _ => ("#607D8B", "#455A64"),         // Blue-gray gradient for custom types
264    }
265}
266
267/// Get color based on type for consistent visualization
268pub fn get_type_color(type_name: &str) -> &'static str {
269    match type_name {
270        "String" => "#2ecc71",
271        "Vec" => "#3498db",
272        "Box" => "#e74c3c",
273        "HashMap" => "#f39c12",
274        "Rc" => "#9b59b6",
275        "Arc" => "#1abc9c",
276        _ => "#95a5a6",
277    }
278}
279
280/// Enhanced type hierarchy classification for treemap visualization
281#[derive(Debug, Clone)]
282pub struct TypeHierarchy {
283    /// Major category: Collections, Strings, Smart Pointers, etc.
284    pub major_category: String,
285    /// Sub category: Maps, Sequences, Owned, Shared, etc.
286    pub sub_category: String,
287    /// Specific type: HashMap, Vec, Box, etc.
288    pub specific_type: String,
289    /// Full type name: HashMap<String, i32>
290    pub full_type: String,
291}
292
293/// Get comprehensive type hierarchy for treemap visualization
294pub fn get_type_category_hierarchy(type_name: &str) -> TypeHierarchy {
295    // Handle empty or unknown types first
296    if type_name.is_empty() || type_name == "Unknown" {
297        return TypeHierarchy {
298            major_category: "Unknown".to_string(),
299            sub_category: "Unidentified".to_string(),
300            specific_type: "Unknown Type".to_string(),
301            full_type: type_name.to_string(),
302        };
303    }
304
305    // Collections
306    if type_name.contains("HashMap") || type_name.contains("hash::map") {
307        let inner = extract_generic_params(type_name, "HashMap");
308        TypeHierarchy {
309            major_category: "Collections".to_string(),
310            sub_category: "Maps".to_string(),
311            specific_type: "HashMap".to_string(),
312            full_type: if inner.is_empty() {
313                "HashMap".to_string()
314            } else {
315                format!("HashMap<{inner}>")
316            },
317        }
318    } else if type_name.contains("BTreeMap") || type_name.contains("btree::map") {
319        let inner = extract_generic_params(type_name, "BTreeMap");
320        TypeHierarchy {
321            major_category: "Collections".to_string(),
322            sub_category: "Maps".to_string(),
323            specific_type: "BTreeMap".to_string(),
324            full_type: if inner.is_empty() {
325                "BTreeMap".to_string()
326            } else {
327                format!("BTreeMap<{inner}>")
328            },
329        }
330    } else if type_name.contains("HashSet") || type_name.contains("hash::set") {
331        let inner = extract_generic_params(type_name, "HashSet");
332        TypeHierarchy {
333            major_category: "Collections".to_string(),
334            sub_category: "Sets".to_string(),
335            specific_type: "HashSet".to_string(),
336            full_type: if inner.is_empty() {
337                "HashSet".to_string()
338            } else {
339                format!("HashSet<{inner}>")
340            },
341        }
342    } else if type_name.contains("Vec") && !type_name.contains("VecDeque") {
343        let inner = extract_generic_params(type_name, "Vec");
344        TypeHierarchy {
345            major_category: "Collections".to_string(),
346            sub_category: "Sequences".to_string(),
347            specific_type: "Vec".to_string(),
348            full_type: if inner.is_empty() {
349                "Vec".to_string()
350            } else {
351                format!("Vec<{inner}>")
352            },
353        }
354    } else if type_name.contains("VecDeque") {
355        let inner = extract_generic_params(type_name, "VecDeque");
356        TypeHierarchy {
357            major_category: "Collections".to_string(),
358            sub_category: "Sequences".to_string(),
359            specific_type: "VecDeque".to_string(),
360            full_type: if inner.is_empty() {
361                "VecDeque".to_string()
362            } else {
363                format!("VecDeque<{inner}>")
364            },
365        }
366    }
367    // Strings
368    else if type_name.contains("String") && !type_name.contains("<") {
369        TypeHierarchy {
370            major_category: "Strings".to_string(),
371            sub_category: "Owned".to_string(),
372            specific_type: "String".to_string(),
373            full_type: "String".to_string(),
374        }
375    } else if type_name.contains("&str") || (type_name.contains("str") && type_name.contains("&")) {
376        TypeHierarchy {
377            major_category: "Strings".to_string(),
378            sub_category: "Borrowed".to_string(),
379            specific_type: "&str".to_string(),
380            full_type: "&str".to_string(),
381        }
382    }
383    // Smart Pointers
384    else if type_name.contains("Box<") {
385        let inner = extract_generic_params(type_name, "Box");
386        TypeHierarchy {
387            major_category: "Smart Pointers".to_string(),
388            sub_category: "Owned".to_string(),
389            specific_type: "Box".to_string(),
390            full_type: if inner.is_empty() {
391                "Box".to_string()
392            } else {
393                format!("Box<{inner}>")
394            },
395        }
396    } else if type_name.contains("Rc<") {
397        let inner = extract_generic_params(type_name, "Rc");
398        TypeHierarchy {
399            major_category: "Smart Pointers".to_string(),
400            sub_category: "Reference Counted".to_string(),
401            specific_type: "Rc".to_string(),
402            full_type: if inner.is_empty() {
403                "Rc".to_string()
404            } else {
405                format!("Rc<{inner}>")
406            },
407        }
408    } else if type_name.contains("Arc<") {
409        let inner = extract_generic_params(type_name, "Arc");
410        TypeHierarchy {
411            major_category: "Smart Pointers".to_string(),
412            sub_category: "Thread-Safe Shared".to_string(),
413            specific_type: "Arc".to_string(),
414            full_type: if inner.is_empty() {
415                "Arc".to_string()
416            } else {
417                format!("Arc<{inner}>")
418            },
419        }
420    }
421    // Primitives
422    else if is_primitive_type(type_name) {
423        let clean_type = type_name.split("::").last().unwrap_or(type_name);
424        let sub_cat = if clean_type.contains("i") || clean_type.contains("u") {
425            "Integers"
426        } else if clean_type.contains("f") {
427            "Floats"
428        } else if clean_type == "bool" {
429            "Boolean"
430        } else {
431            "Other"
432        };
433        TypeHierarchy {
434            major_category: "Primitives".to_string(),
435            sub_category: sub_cat.to_string(),
436            specific_type: clean_type.to_string(),
437            full_type: clean_type.to_string(),
438        }
439    }
440    // Fallback
441    else {
442        let simplified = type_name.split("::").last().unwrap_or(type_name);
443        TypeHierarchy {
444            major_category: "Custom Types".to_string(),
445            sub_category: "User Defined".to_string(),
446            specific_type: simplified.to_string(),
447            full_type: simplified.to_string(),
448        }
449    }
450}
451
452/// Extract generic parameters from type names (enhanced version)
453pub fn extract_generic_params(type_name: &str, container: &str) -> String {
454    if let Some(start) = type_name.find(&format!("{container}<")) {
455        let start = start + container.len() + 1;
456        if let Some(end) = find_matching_bracket(type_name, start - 1) {
457            let inner = &type_name[start..end];
458            // Simplify the inner type
459            return inner.split("::").last().unwrap_or(inner).to_string();
460        }
461    }
462    String::new()
463}
464
465/// Find matching closing bracket for generic types
466fn find_matching_bracket(s: &str, start: usize) -> Option<usize> {
467    let chars: Vec<char> = s.chars().collect();
468    if start >= chars.len() || chars[start] != '<' {
469        return None;
470    }
471
472    let mut depth = 1;
473    for (i, item) in chars.iter().enumerate().skip(start + 1) {
474        match item {
475            '<' => depth += 1,
476            '>' => {
477                depth -= 1;
478                if depth == 0 {
479                    return Some(i);
480                }
481            }
482            _ => {}
483        }
484    }
485    None
486}
487
488/// Check if a type is a primitive type
489pub fn is_primitive_type(type_name: &str) -> bool {
490    let clean_type = type_name.split("::").last().unwrap_or(type_name);
491    matches!(
492        clean_type,
493        "i8" | "i16"
494            | "i32"
495            | "i64"
496            | "i128"
497            | "isize"
498            | "u8"
499            | "u16"
500            | "u32"
501            | "u64"
502            | "u128"
503            | "usize"
504            | "f32"
505            | "f64"
506            | "bool"
507            | "char"
508    )
509}
510
511/// Extract array information for display
512pub fn extract_array_info(type_name: &str) -> String {
513    if let Some(start) = type_name.find('[') {
514        if let Some(end) = type_name.find(']') {
515            return type_name[start..=end].to_string();
516        }
517    }
518    "Array".to_string()
519}
520
521/// Extract standard library module name
522pub fn extract_std_module(type_name: &str) -> String {
523    let parts: Vec<&str> = type_name.split("::").collect();
524    if parts.len() >= 2 {
525        match parts[1] {
526            "collections" => "Collections".to_string(),
527            "sync" => "Synchronization".to_string(),
528            "thread" => "Threading".to_string(),
529            "fs" => "File System".to_string(),
530            "net" => "Networking".to_string(),
531            "io" => "Input/Output".to_string(),
532            _ => "Other".to_string(),
533        }
534    } else {
535        "Other".to_string()
536    }
537}
538
539// ============================================================================
540// Thread Utilities (merged from thread_utils.rs)
541// ============================================================================
542
543use std::sync::{
544    atomic::{AtomicBool, Ordering},
545    Arc,
546};
547use std::thread;
548use std::time::Duration;
549
550/// Extension trait for JoinHandle to add timeout functionality
551pub trait JoinHandleExt<T> {
552    /// Join with a timeout, returning an error if the timeout is exceeded
553    fn join_timeout(self, timeout: Duration) -> Result<T, Box<dyn std::any::Any + Send + 'static>>;
554}
555
556impl<T: Send + 'static> JoinHandleExt<T> for thread::JoinHandle<T> {
557    fn join_timeout(self, timeout: Duration) -> Result<T, Box<dyn std::any::Any + Send + 'static>> {
558        // If the thread is already finished, just join it
559        if self.is_finished() {
560            return self.join().map_err(|e| Box::new(e) as _);
561        }
562
563        // Create a flag to track if the thread completed
564        let completed = Arc::new(AtomicBool::new(false));
565        let completed_clone = completed.clone();
566
567        // Spawn a thread that will wait for the original thread
568        let handle = thread::spawn(move || {
569            let result = self.join();
570            completed_clone.store(true, Ordering::SeqCst);
571            result
572        });
573
574        // Wait for the timeout or until the thread completes
575        let start = std::time::Instant::now();
576        while !completed.load(Ordering::SeqCst) && start.elapsed() < timeout {
577            thread::sleep(Duration::from_millis(10));
578        }
579
580        if completed.load(Ordering::SeqCst) {
581            // Thread completed within timeout
582            match handle.join() {
583                Ok(result) => result.map_err(|e| Box::new(e) as _),
584                Err(_) => Err(Box::new("Watcher thread panicked") as _),
585            }
586        } else {
587            // Timeout reached and thread is still running
588            // Return an error indicating timeout
589            Err(Box::new("Thread join timed out") as _)
590        }
591    }
592}
593
594#[cfg(test)]
595mod tests {
596    use super::*;
597    use std::thread;
598    use std::time::Duration;
599
600    #[test]
601    fn test_current_timestamp_nanos() {
602        let timestamp1 = current_timestamp_nanos();
603        thread::sleep(Duration::from_millis(1));
604        let timestamp2 = current_timestamp_nanos();
605
606        assert!(timestamp2 > timestamp1);
607        assert!(timestamp1 > 0);
608    }
609
610    #[test]
611    fn test_format_bytes() {
612        assert_eq!(format_bytes(0), "0B");
613        assert_eq!(format_bytes(512), "512B");
614        assert_eq!(format_bytes(1024), "1.0KB");
615        assert_eq!(format_bytes(1536), "1.5KB");
616        assert_eq!(format_bytes(1024 * 1024), "1.0MB");
617        assert_eq!(format_bytes(1024 * 1024 + 512 * 1024), "1.5MB");
618    }
619
620    #[test]
621    fn test_simplify_type_name_basic_types() {
622        let (simplified, category) = simplify_type_name("String");
623        assert_eq!(simplified, "String");
624        assert_eq!(category, "Basic Types");
625
626        let (simplified, category) = simplify_type_name("&str");
627        assert_eq!(simplified, "&str");
628        assert_eq!(category, "Basic Types");
629
630        let (simplified, category) = simplify_type_name("i32");
631        assert_eq!(simplified, "i32");
632        assert_eq!(category, "Basic Types");
633
634        let (simplified, category) = simplify_type_name("bool");
635        assert_eq!(simplified, "bool");
636        assert_eq!(category, "Basic Types");
637    }
638
639    #[test]
640    fn test_simplify_type_name_collections() {
641        let (simplified, category) = simplify_type_name("Vec<i32>");
642        assert_eq!(simplified, "Vec<i32>");
643        assert_eq!(category, "Collections");
644
645        // The function prioritizes String detection over HashMap
646        let (simplified, category) = simplify_type_name("HashMap<String, i32>");
647        assert_eq!(simplified, "String");
648        assert_eq!(category, "Basic Types");
649
650        let (simplified, category) = simplify_type_name("BTreeMap<String, i32>");
651        assert_eq!(simplified, "String");
652        assert_eq!(category, "Basic Types");
653
654        let (simplified, category) = simplify_type_name("HashSet<String>");
655        assert_eq!(simplified, "String");
656        assert_eq!(category, "Basic Types");
657    }
658
659    #[test]
660    fn test_simplify_type_name_smart_pointers() {
661        let (simplified, category) = simplify_type_name("Box<i32>");
662        assert_eq!(simplified, "Box<i32>");
663        assert_eq!(category, "Smart Pointers");
664
665        // String detection takes priority
666        let (simplified, category) = simplify_type_name("Rc<String>");
667        assert_eq!(simplified, "String");
668        assert_eq!(category, "Basic Types");
669
670        // The function returns the full Arc type
671        let (simplified, category) = simplify_type_name("Arc<Mutex<i32>>");
672        assert_eq!(simplified, "Arc<Mutex<i32>>");
673        assert_eq!(category, "Smart Pointers");
674
675        // String detection takes priority over HashMap
676        let (simplified, category) = simplify_type_name("Box<HashMap<String, i32>>");
677        assert_eq!(simplified, "String");
678        assert_eq!(category, "Basic Types");
679    }
680
681    #[test]
682    fn test_simplify_type_name_special_cases() {
683        let (simplified, category) = simplify_type_name("");
684        assert_eq!(simplified, "Unknown Type");
685        assert_eq!(category, "Unknown");
686
687        let (simplified, category) = simplify_type_name("Unknown");
688        assert_eq!(simplified, "Unknown Type");
689        assert_eq!(category, "Unknown");
690
691        // i32 detection takes priority over Option
692        let (simplified, category) = simplify_type_name("Option<i32>");
693        assert_eq!(simplified, "Option<i32>");
694        assert_eq!(category, "Basic Types");
695
696        // String detection takes priority
697        let (simplified, category) = simplify_type_name("Result<String, Error>");
698        assert_eq!(simplified, "String");
699        assert_eq!(category, "Basic Types");
700    }
701
702    #[test]
703    fn test_simplify_type_name_arrays_tuples() {
704        // The function returns the full array notation, but category is Basic Types due to i32 detection
705        let (simplified, category) = simplify_type_name("[i32; 10]");
706        assert_eq!(simplified, "[i32; 10]");
707        assert_eq!(category, "Basic Types");
708
709        // String detection takes priority over tuple
710        let (simplified, category) = simplify_type_name("(i32, String)");
711        assert_eq!(simplified, "String");
712        assert_eq!(category, "Basic Types");
713    }
714
715    #[test]
716    fn test_simplify_type_name_synchronization() {
717        // Mutex detection takes priority over i32
718        let (simplified, category) = simplify_type_name("Mutex<i32>");
719        assert_eq!(simplified, "Mutex<i32>");
720        assert_eq!(category, "Basic Types");
721
722        // String detection takes priority
723        let (simplified, category) = simplify_type_name("RwLock<String>");
724        assert_eq!(simplified, "String");
725        assert_eq!(category, "Basic Types");
726
727        let (simplified, category) = simplify_type_name("Cell<i32>");
728        assert_eq!(simplified, "Cell<i32>");
729        assert_eq!(category, "Basic Types");
730    }
731
732    #[test]
733    fn test_simplify_type_name_namespaced() {
734        // HashMap detection works for namespaced types
735        let (simplified, category) = simplify_type_name("std::collections::HashMap");
736        assert_eq!(simplified, "HashMap<K,V>");
737        assert_eq!(category, "Collections");
738
739        let (simplified, category) = simplify_type_name("my_crate::MyStruct");
740        assert_eq!(simplified, "MyStruct");
741        assert_eq!(category, "Custom Types");
742
743        let (simplified, category) = simplify_type_name("my_crate::error::MyError");
744        assert_eq!(simplified, "MyError");
745        assert_eq!(category, "Error Types");
746
747        let (simplified, category) = simplify_type_name("my_crate::config::AppConfig");
748        assert_eq!(simplified, "AppConfig");
749        assert_eq!(category, "Configuration");
750    }
751
752    #[test]
753    fn test_extract_generic_type() {
754        assert_eq!(extract_generic_type("Vec<i32>", "Vec"), "i32");
755        assert_eq!(extract_generic_type("Box<String>", "Box"), "String");
756        assert_eq!(
757            extract_generic_type("HashMap<String, i32>", "HashMap"),
758            "String, i32"
759        );
760        assert_eq!(extract_generic_type("Vec", "Vec"), "?");
761        assert_eq!(
762            extract_generic_type("std::vec::Vec<std::string::String>", "Vec"),
763            "String"
764        );
765    }
766
767    #[test]
768    fn test_get_simple_type() {
769        assert_eq!(get_simple_type("std::string::String"), "String");
770        assert_eq!(get_simple_type("std::vec::Vec<i32>"), "Vec");
771        // String detection takes priority over Box
772        assert_eq!(get_simple_type("std::boxed::Box<String>"), "String");
773        assert_eq!(get_simple_type("std::rc::Rc<i32>"), "Rc");
774        assert_eq!(get_simple_type("std::sync::Arc<String>"), "String");
775        assert_eq!(get_simple_type("std::collections::HashMap<K,V>"), "HashMap");
776        assert_eq!(get_simple_type("my_crate::MyType"), "MyType");
777        assert_eq!(get_simple_type("UnknownType"), "UnknownType");
778    }
779
780    #[test]
781    fn test_get_category_color() {
782        assert_eq!(get_category_color("Collections"), "#3498db");
783        assert_eq!(get_category_color("Basic Types"), "#27ae60");
784        assert_eq!(get_category_color("Smart Pointers"), "#e74c3c");
785        assert_eq!(get_category_color("Synchronization"), "#e67e22");
786        assert_eq!(get_category_color("Unknown"), "#bdc3c7");
787        assert_eq!(get_category_color("NonExistentCategory"), "#7f8c8d");
788    }
789
790    #[test]
791    fn test_get_type_gradient_colors() {
792        let (start, end) = get_type_gradient_colors("String");
793        assert_eq!(start, "#00BCD4");
794        assert_eq!(end, "#00ACC1");
795
796        let (start, end) = get_type_gradient_colors("Vec");
797        assert_eq!(start, "#2196F3");
798        assert_eq!(end, "#1976D2");
799
800        let (start, end) = get_type_gradient_colors("UnknownType");
801        assert_eq!(start, "#607D8B");
802        assert_eq!(end, "#455A64");
803    }
804
805    #[test]
806    fn test_get_type_color() {
807        assert_eq!(get_type_color("String"), "#2ecc71");
808        assert_eq!(get_type_color("Vec"), "#3498db");
809        assert_eq!(get_type_color("Box"), "#e74c3c");
810        assert_eq!(get_type_color("HashMap"), "#f39c12");
811        assert_eq!(get_type_color("Rc"), "#9b59b6");
812        assert_eq!(get_type_color("Arc"), "#1abc9c");
813        assert_eq!(get_type_color("UnknownType"), "#95a5a6");
814    }
815
816    #[test]
817    fn test_get_type_category_hierarchy_collections() {
818        let hierarchy = get_type_category_hierarchy("HashMap<String, i32>");
819        assert_eq!(hierarchy.major_category, "Collections");
820        assert_eq!(hierarchy.sub_category, "Maps");
821        assert_eq!(hierarchy.specific_type, "HashMap");
822        assert_eq!(hierarchy.full_type, "HashMap<String, i32>");
823
824        let hierarchy = get_type_category_hierarchy("Vec<u8>");
825        assert_eq!(hierarchy.major_category, "Collections");
826        assert_eq!(hierarchy.sub_category, "Sequences");
827        assert_eq!(hierarchy.specific_type, "Vec");
828        assert_eq!(hierarchy.full_type, "Vec<u8>");
829
830        let hierarchy = get_type_category_hierarchy("HashSet<String>");
831        assert_eq!(hierarchy.major_category, "Collections");
832        assert_eq!(hierarchy.sub_category, "Sets");
833        assert_eq!(hierarchy.specific_type, "HashSet");
834        assert_eq!(hierarchy.full_type, "HashSet<String>");
835    }
836
837    #[test]
838    fn test_get_type_category_hierarchy_strings() {
839        let hierarchy = get_type_category_hierarchy("String");
840        assert_eq!(hierarchy.major_category, "Strings");
841        assert_eq!(hierarchy.sub_category, "Owned");
842        assert_eq!(hierarchy.specific_type, "String");
843        assert_eq!(hierarchy.full_type, "String");
844
845        let hierarchy = get_type_category_hierarchy("&str");
846        assert_eq!(hierarchy.major_category, "Strings");
847        assert_eq!(hierarchy.sub_category, "Borrowed");
848        assert_eq!(hierarchy.specific_type, "&str");
849        assert_eq!(hierarchy.full_type, "&str");
850    }
851
852    #[test]
853    fn test_get_type_category_hierarchy_smart_pointers() {
854        let hierarchy = get_type_category_hierarchy("Box<i32>");
855        assert_eq!(hierarchy.major_category, "Smart Pointers");
856        assert_eq!(hierarchy.sub_category, "Owned");
857        assert_eq!(hierarchy.specific_type, "Box");
858        assert_eq!(hierarchy.full_type, "Box<i32>");
859
860        let hierarchy = get_type_category_hierarchy("Rc<String>");
861        assert_eq!(hierarchy.major_category, "Smart Pointers");
862        assert_eq!(hierarchy.sub_category, "Reference Counted");
863        assert_eq!(hierarchy.specific_type, "Rc");
864        assert_eq!(hierarchy.full_type, "Rc<String>");
865
866        let hierarchy = get_type_category_hierarchy("Arc<Mutex<i32>>");
867        assert_eq!(hierarchy.major_category, "Smart Pointers");
868        assert_eq!(hierarchy.sub_category, "Thread-Safe Shared");
869        assert_eq!(hierarchy.specific_type, "Arc");
870        assert_eq!(hierarchy.full_type, "Arc<Mutex<i32>>");
871    }
872
873    #[test]
874    fn test_get_type_category_hierarchy_primitives() {
875        let hierarchy = get_type_category_hierarchy("i32");
876        assert_eq!(hierarchy.major_category, "Primitives");
877        assert_eq!(hierarchy.sub_category, "Integers");
878        assert_eq!(hierarchy.specific_type, "i32");
879        assert_eq!(hierarchy.full_type, "i32");
880
881        let hierarchy = get_type_category_hierarchy("f64");
882        assert_eq!(hierarchy.major_category, "Primitives");
883        assert_eq!(hierarchy.sub_category, "Floats");
884        assert_eq!(hierarchy.specific_type, "f64");
885        assert_eq!(hierarchy.full_type, "f64");
886
887        let hierarchy = get_type_category_hierarchy("bool");
888        assert_eq!(hierarchy.major_category, "Primitives");
889        assert_eq!(hierarchy.sub_category, "Boolean");
890        assert_eq!(hierarchy.specific_type, "bool");
891        assert_eq!(hierarchy.full_type, "bool");
892    }
893
894    #[test]
895    fn test_get_type_category_hierarchy_unknown() {
896        let hierarchy = get_type_category_hierarchy("");
897        assert_eq!(hierarchy.major_category, "Unknown");
898        assert_eq!(hierarchy.sub_category, "Unidentified");
899        assert_eq!(hierarchy.specific_type, "Unknown Type");
900
901        let hierarchy = get_type_category_hierarchy("Unknown");
902        assert_eq!(hierarchy.major_category, "Unknown");
903        assert_eq!(hierarchy.sub_category, "Unidentified");
904        assert_eq!(hierarchy.specific_type, "Unknown Type");
905    }
906
907    #[test]
908    fn test_extract_generic_params() {
909        assert_eq!(
910            extract_generic_params("HashMap<String, i32>", "HashMap"),
911            "String, i32"
912        );
913        assert_eq!(extract_generic_params("Vec<u8>", "Vec"), "u8");
914        assert_eq!(extract_generic_params("Box<String>", "Box"), "String");
915        assert_eq!(extract_generic_params("Vec", "Vec"), "");
916        assert_eq!(
917            extract_generic_params("std::vec::Vec<std::string::String>", "Vec"),
918            "String"
919        );
920    }
921
922    #[test]
923    fn test_find_matching_bracket() {
924        assert_eq!(find_matching_bracket("Vec<i32>", 3), Some(7));
925        assert_eq!(
926            find_matching_bracket("HashMap<String, Vec<i32>>", 7),
927            Some(24)
928        );
929        assert_eq!(find_matching_bracket("Vec<i32", 3), None);
930        assert_eq!(find_matching_bracket("Vec", 3), None);
931    }
932
933    #[test]
934    fn test_is_primitive_type() {
935        assert!(is_primitive_type("i32"));
936        assert!(is_primitive_type("u64"));
937        assert!(is_primitive_type("f32"));
938        assert!(is_primitive_type("bool"));
939        assert!(is_primitive_type("char"));
940        assert!(is_primitive_type("isize"));
941        assert!(is_primitive_type("usize"));
942
943        assert!(!is_primitive_type("String"));
944        assert!(!is_primitive_type("Vec<i32>"));
945        assert!(!is_primitive_type("CustomType"));
946
947        // Test with namespace
948        assert!(is_primitive_type("std::primitive::i32"));
949        assert!(!is_primitive_type("std::string::String"));
950    }
951
952    #[test]
953    fn test_extract_array_info() {
954        assert_eq!(extract_array_info("[i32; 10]"), "[i32; 10]");
955        assert_eq!(extract_array_info("[u8; 256]"), "[u8; 256]");
956        assert_eq!(extract_array_info("Vec<i32>"), "Array");
957        assert_eq!(extract_array_info("no_brackets"), "Array");
958    }
959
960    #[test]
961    fn test_extract_std_module() {
962        assert_eq!(
963            extract_std_module("std::collections::HashMap"),
964            "Collections"
965        );
966        assert_eq!(extract_std_module("std::sync::Mutex"), "Synchronization");
967        assert_eq!(extract_std_module("std::thread::JoinHandle"), "Threading");
968        assert_eq!(extract_std_module("std::fs::File"), "File System");
969        assert_eq!(extract_std_module("std::net::TcpStream"), "Networking");
970        assert_eq!(extract_std_module("std::io::BufReader"), "Input/Output");
971        assert_eq!(extract_std_module("std::unknown::Type"), "Other");
972        assert_eq!(extract_std_module("CustomType"), "Other");
973    }
974
975    #[test]
976    fn test_join_handle_ext_immediate_completion() {
977        let handle = thread::spawn(|| 42);
978
979        // Give the thread time to complete
980        thread::sleep(Duration::from_millis(10));
981
982        let result = handle.join_timeout(Duration::from_millis(100));
983        assert!(result.is_ok());
984        assert_eq!(result.unwrap(), 42);
985    }
986
987    #[test]
988    fn test_join_handle_ext_timeout() {
989        let handle = thread::spawn(|| {
990            thread::sleep(Duration::from_millis(200));
991            42
992        });
993
994        let result = handle.join_timeout(Duration::from_millis(50));
995        assert!(result.is_err());
996    }
997
998    #[test]
999    fn test_join_handle_ext_within_timeout() {
1000        let handle = thread::spawn(|| {
1001            thread::sleep(Duration::from_millis(50));
1002            42
1003        });
1004
1005        let result = handle.join_timeout(Duration::from_millis(200));
1006        assert!(result.is_ok());
1007        assert_eq!(result.unwrap(), 42);
1008    }
1009
1010    #[test]
1011    fn test_type_hierarchy_custom_types() {
1012        let hierarchy = get_type_category_hierarchy("MyCustomType");
1013        assert_eq!(hierarchy.major_category, "Custom Types");
1014        assert_eq!(hierarchy.sub_category, "User Defined");
1015        assert_eq!(hierarchy.specific_type, "MyCustomType");
1016        assert_eq!(hierarchy.full_type, "MyCustomType");
1017    }
1018
1019    #[test]
1020    fn test_simplify_type_name_edge_cases() {
1021        // Test whitespace handling
1022        let (simplified, category) = simplify_type_name("  String  ");
1023        assert_eq!(simplified, "String");
1024        assert_eq!(category, "Basic Types");
1025
1026        // Test complex nested types - the function returns the exact input
1027        let (simplified, category) = simplify_type_name("Box<Vec<HashMap<String, i32>>>");
1028        assert_eq!(simplified, "Vec<HashMap<String, i32>>>");
1029        assert_eq!(category, "Collections");
1030
1031        // Test weak pointers - String detection takes priority
1032        let (simplified, category) = simplify_type_name("Weak<String>");
1033        assert_eq!(simplified, "String");
1034        assert_eq!(category, "Basic Types");
1035    }
1036}