1use std::hash::{Hash, Hasher};
4use std::thread::ThreadId;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7pub fn current_timestamp_nanos() -> u64 {
9 SystemTime::now()
10 .duration_since(UNIX_EPOCH)
11 .unwrap_or_default()
12 .as_nanos() as u64
13}
14
15pub fn thread_id_to_u64(thread_id: ThreadId) -> u64 {
20 let mut hasher = std::collections::hash_map::DefaultHasher::new();
21 thread_id.hash(&mut hasher);
22 hasher.finish()
23}
24
25pub fn current_thread_id_u64() -> u64 {
30 static NEXT_THREAD_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
31 thread_local! {
32 static CAPTURE_THREAD_ID: u64 = NEXT_THREAD_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
33 }
34 CAPTURE_THREAD_ID.with(|id| *id)
35}
36
37pub fn format_bytes(bytes: usize) -> String {
39 const KB: usize = 1024;
40 const MB: usize = KB * 1024;
41 const GB: usize = MB * 1024;
42 const TB: usize = GB * 1024;
43 const PB: usize = TB * 1024;
44
45 if bytes < KB {
46 format!("{bytes}B")
47 } else if bytes < MB {
48 format!("{:.1}KB", bytes as f64 / KB as f64)
49 } else if bytes < GB {
50 format!("{:.1}MB", bytes as f64 / MB as f64)
51 } else if bytes < TB {
52 format!("{:.1}GB", bytes as f64 / GB as f64)
53 } else if bytes < PB {
54 format!("{:.1}TB", bytes as f64 / TB as f64)
55 } else {
56 format!("{:.1}PB", bytes as f64 / PB as f64)
57 }
58}
59
60pub fn simplify_type_name(type_name: &str) -> (String, String) {
62 if type_name.is_empty() || type_name == "Unknown" {
64 return ("Unknown Type".to_string(), "Unknown".to_string());
65 }
66
67 let clean_type = type_name.trim();
69
70 if clean_type.contains("Vec<") || clean_type.contains("vec::Vec") {
72 let inner = extract_generic_type(clean_type, "Vec");
73 (format!("Vec<{inner}>"), "Collections".to_string())
74 } else if clean_type.contains("HashMap") || clean_type.contains("hash_map") {
75 ("HashMap<K,V>".to_string(), "Collections".to_string())
76 } else if clean_type.contains("BTreeMap") || clean_type.contains("btree_map") {
77 ("BTreeMap<K,V>".to_string(), "Collections".to_string())
78 } else if clean_type.contains("BTreeSet") || clean_type.contains("btree_set") {
79 ("BTreeSet<T>".to_string(), "Collections".to_string())
80 } else if clean_type.contains("HashSet") || clean_type.contains("hash_set") {
81 ("HashSet<T>".to_string(), "Collections".to_string())
82 } else if clean_type.contains("VecDeque") || clean_type.contains("vec_deque") {
83 ("VecDeque<T>".to_string(), "Collections".to_string())
84 } else if clean_type.contains("Box<") || clean_type.contains("boxed::Box") {
85 let inner = extract_generic_type(clean_type, "Box");
86 if inner.contains("String") || inner.contains("string::String") {
87 ("String".to_string(), "Basic Types".to_string())
88 } else if inner.contains("HashMap") || inner.contains("hash_map") {
89 ("HashMap<K,V>".to_string(), "Collections".to_string())
90 } else if inner.contains("BTreeMap") || inner.contains("btree_map") {
91 ("BTreeMap<K,V>".to_string(), "Collections".to_string())
92 } else if inner.contains("BTreeSet") || inner.contains("btree_set") {
93 ("BTreeSet<T>".to_string(), "Collections".to_string())
94 } else if inner.contains("HashSet") || inner.contains("hash_set") {
95 ("HashSet<T>".to_string(), "Collections".to_string())
96 } else if inner.contains("VecDeque") || inner.contains("vec_deque") {
97 ("VecDeque<T>".to_string(), "Collections".to_string())
98 } else if inner.contains("Vec") || inner.contains("vec::Vec") {
99 let vec_inner = extract_generic_type(&inner, "Vec");
100 (format!("Vec<{vec_inner}>"), "Collections".to_string())
101 } else {
102 (format!("Box<{inner}>"), "Smart Pointers".to_string())
103 }
104 } else if clean_type.contains("Rc<") || clean_type.contains("rc::Rc") {
105 let inner = extract_generic_type(clean_type, "Rc");
106 if inner.contains("String") || inner.contains("string::String") {
107 ("String".to_string(), "Basic Types".to_string())
108 } else {
109 (format!("Rc<{inner}>"), "Smart Pointers".to_string())
110 }
111 } else if clean_type.contains("Arc<") || clean_type.contains("sync::Arc") {
112 let inner = extract_generic_type(clean_type, "Arc");
113 if inner.contains("String") || inner.contains("string::String") {
114 ("String".to_string(), "Basic Types".to_string())
115 } else {
116 (format!("Arc<{inner}>"), "Smart Pointers".to_string())
117 }
118 } else if clean_type.contains("String") || clean_type.contains("string::String") {
119 ("String".to_string(), "Basic Types".to_string())
120 } else if clean_type.contains("LinkedList") {
121 ("LinkedList<T>".to_string(), "Collections".to_string())
122 } else if clean_type.contains("&str") || clean_type == "str" {
123 ("&str".to_string(), "Basic Types".to_string())
124 } else if clean_type.contains("CString") || clean_type.contains("CStr") {
125 ("CString".to_string(), "Basic Types".to_string())
126 } else if clean_type.contains("OsString") || clean_type.contains("OsStr") {
127 ("OsString".to_string(), "Basic Types".to_string())
128 } else if clean_type.contains("PathBuf") || clean_type.contains("Path") {
129 ("PathBuf".to_string(), "Basic Types".to_string())
130 } else if clean_type.contains("Option<") {
131 ("Option<T>".to_string(), "Optionals".to_string())
132 } else if clean_type.contains("Result<") {
133 ("Result<T,E>".to_string(), "Results".to_string())
134 } else if clean_type.matches("i32").count() > 0
135 || clean_type.matches("u32").count() > 0
136 || clean_type.matches("i64").count() > 0
137 || clean_type.matches("u64").count() > 0
138 || clean_type.matches("f64").count() > 0
139 || clean_type.matches("f32").count() > 0
140 || clean_type.matches("i8").count() > 0
141 || clean_type.matches("u8").count() > 0
142 || clean_type.matches("i16").count() > 0
143 || clean_type.matches("u16").count() > 0
144 || clean_type.matches("isize").count() > 0
145 || clean_type.matches("usize").count() > 0
146 || clean_type.matches("bool").count() > 0
147 || clean_type.matches("char").count() > 0
148 {
149 let primitive = clean_type.split("::").last().unwrap_or(clean_type);
150 (primitive.to_string(), "Basic Types".to_string())
151 } else if clean_type.contains("[") && clean_type.contains("]") {
152 ("Array".to_string(), "Arrays".to_string())
153 } else if clean_type.starts_with("(") && clean_type.ends_with(")") {
154 ("Tuple".to_string(), "Tuples".to_string())
155 } else if clean_type.contains("Mutex<") || clean_type.contains("RwLock<") {
156 ("Mutex/RwLock".to_string(), "Synchronization".to_string())
157 } else if clean_type.contains("Cell<") || clean_type.contains("RefCell<") {
158 (
159 "Cell/RefCell".to_string(),
160 "Interior Mutability".to_string(),
161 )
162 } else if clean_type.contains("Weak<") {
163 ("Weak<T>".to_string(), "Smart Pointers".to_string())
164 } else if clean_type.starts_with("std::")
165 || clean_type.starts_with("alloc::")
166 || clean_type.starts_with("core::")
167 {
168 let simplified = clean_type.split("::").last().unwrap_or(clean_type);
169 (simplified.to_string(), "Standard Library".to_string())
170 } else if clean_type.contains("::") {
171 let parts: Vec<&str> = clean_type.split("::").collect();
173 if parts.len() >= 2 {
174 let type_part = parts.last().unwrap_or(&clean_type);
176
177 let category = if parts
179 .iter()
180 .any(|&part| part.contains("error") || part.contains("Error"))
181 || type_part.ends_with("Error")
182 || type_part.contains("Err")
183 {
184 "Error Types"
185 } else if type_part.ends_with("Config") || type_part.ends_with("Settings") {
186 "Configuration"
187 } else if type_part.ends_with("Builder") || type_part.ends_with("Factory") {
188 "Builders"
189 } else if parts
190 .iter()
191 .any(|&part| part == "std" || part == "core" || part == "alloc")
192 {
193 "Standard Library"
194 } else if parts
195 .iter()
196 .any(|&part| part.contains("test") || part.contains("mock"))
197 {
198 "Test Types"
199 } else if parts.len() > 2 {
200 "Library Types"
202 } else {
203 "Custom Types"
204 };
205
206 (type_part.to_string(), category.to_string())
207 } else {
208 let category = if clean_type.ends_with("Error") || clean_type.contains("Err") {
210 "Error Types"
211 } else if clean_type.ends_with("Config") || clean_type.ends_with("Settings") {
212 "Configuration"
213 } else if clean_type.ends_with("Builder") || clean_type.ends_with("Factory") {
214 "Builders"
215 } else if clean_type.chars().next().is_some_and(|c| c.is_uppercase()) {
216 "Custom Types"
218 } else {
219 "Other Types"
221 };
222
223 (clean_type.to_string(), category.to_string())
224 }
225 } else {
226 if !clean_type.is_empty() {
228 (clean_type.to_string(), "Custom Types".to_string())
229 } else {
230 ("Unknown Type".to_string(), "Unknown".to_string())
231 }
232 }
233}
234
235pub fn extract_generic_type(type_name: &str, container: &str) -> String {
237 if let Some(start) = type_name.find(&format!("{container}<")) {
238 let content_start = start + container.len() + 1;
239 let content = &type_name[content_start..];
240
241 let mut depth = 1;
242 let mut end = 0;
243
244 for (i, c) in content.char_indices() {
245 match c {
246 '<' => depth += 1,
247 '>' => {
248 depth -= 1;
249 if depth == 0 {
250 end = i;
251 break;
252 }
253 }
254 _ => {}
255 }
256 }
257
258 if end > 0 {
259 let inner = &content[..end];
260 return inner.split("::").last().unwrap_or(inner).to_string();
261 }
262 }
263 "?".to_string()
264}
265
266pub fn get_simple_type(type_name: &str) -> String {
268 if type_name.contains("String") {
269 "String".to_string()
270 } else if type_name.contains("Vec") {
271 "Vec".to_string()
272 } else if type_name.contains("Box") {
273 "Box".to_string()
274 } else if type_name.contains("Rc") {
275 "Rc".to_string()
276 } else if type_name.contains("Arc") {
277 "Arc".to_string()
278 } else if type_name.contains("HashMap") {
279 "HashMap".to_string()
280 } else {
281 type_name
282 .split("::")
283 .last()
284 .unwrap_or("Unknown")
285 .to_string()
286 }
287}
288
289pub fn get_category_color(category: &str) -> String {
291 match category {
292 "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(), }
315}
316
317pub fn get_type_gradient_colors(type_name: &str) -> (&'static str, &'static str) {
319 match type_name {
320 "String" => ("#00BCD4", "#00ACC1"), "Vec" => ("#2196F3", "#1976D2"), "Box" => ("#F44336", "#D32F2F"), "HashMap" => ("#4CAF50", "#388E3C"), "Rc" => ("#FF9800", "#F57C00"), "Arc" => ("#9C27B0", "#7B1FA2"), _ => ("#607D8B", "#455A64"), }
328}
329
330pub fn get_type_color(type_name: &str) -> &'static str {
332 match type_name {
333 "String" => "#2ecc71",
334 "Vec" => "#3498db",
335 "Box" => "#e74c3c",
336 "HashMap" => "#f39c12",
337 "Rc" => "#9b59b6",
338 "Arc" => "#1abc9c",
339 _ => "#95a5a6",
340 }
341}
342
343#[derive(Debug, Clone)]
345pub struct TypeHierarchy {
346 pub major_category: String,
348 pub sub_category: String,
350 pub specific_type: String,
352 pub full_type: String,
354}
355
356pub fn get_type_category_hierarchy(type_name: &str) -> TypeHierarchy {
358 if type_name.is_empty() || type_name == "Unknown" {
360 return TypeHierarchy {
361 major_category: "Unknown".to_string(),
362 sub_category: "Unidentified".to_string(),
363 specific_type: "Unknown Type".to_string(),
364 full_type: type_name.to_string(),
365 };
366 }
367
368 if type_name.contains("HashMap") || type_name.contains("hash::map") {
370 let inner = extract_generic_params(type_name, "HashMap");
371 TypeHierarchy {
372 major_category: "Collections".to_string(),
373 sub_category: "Maps".to_string(),
374 specific_type: "HashMap".to_string(),
375 full_type: if inner.is_empty() {
376 "HashMap".to_string()
377 } else {
378 format!("HashMap<{inner}>")
379 },
380 }
381 } else if type_name.contains("BTreeMap") || type_name.contains("btree::map") {
382 let inner = extract_generic_params(type_name, "BTreeMap");
383 TypeHierarchy {
384 major_category: "Collections".to_string(),
385 sub_category: "Maps".to_string(),
386 specific_type: "BTreeMap".to_string(),
387 full_type: if inner.is_empty() {
388 "BTreeMap".to_string()
389 } else {
390 format!("BTreeMap<{inner}>")
391 },
392 }
393 } else if type_name.contains("HashSet") || type_name.contains("hash::set") {
394 let inner = extract_generic_params(type_name, "HashSet");
395 TypeHierarchy {
396 major_category: "Collections".to_string(),
397 sub_category: "Sets".to_string(),
398 specific_type: "HashSet".to_string(),
399 full_type: if inner.is_empty() {
400 "HashSet".to_string()
401 } else {
402 format!("HashSet<{inner}>")
403 },
404 }
405 } else if type_name.contains("Vec") && !type_name.contains("VecDeque") {
406 let inner = extract_generic_params(type_name, "Vec");
407 TypeHierarchy {
408 major_category: "Collections".to_string(),
409 sub_category: "Sequences".to_string(),
410 specific_type: "Vec".to_string(),
411 full_type: if inner.is_empty() {
412 "Vec".to_string()
413 } else {
414 format!("Vec<{inner}>")
415 },
416 }
417 } else if type_name.contains("VecDeque") {
418 let inner = extract_generic_params(type_name, "VecDeque");
419 TypeHierarchy {
420 major_category: "Collections".to_string(),
421 sub_category: "Sequences".to_string(),
422 specific_type: "VecDeque".to_string(),
423 full_type: if inner.is_empty() {
424 "VecDeque".to_string()
425 } else {
426 format!("VecDeque<{inner}>")
427 },
428 }
429 }
430 else if type_name.contains("String") && !type_name.contains("<") {
432 TypeHierarchy {
433 major_category: "Strings".to_string(),
434 sub_category: "Owned".to_string(),
435 specific_type: "String".to_string(),
436 full_type: "String".to_string(),
437 }
438 } else if type_name.contains("&str") || (type_name.contains("str") && type_name.contains("&")) {
439 TypeHierarchy {
440 major_category: "Strings".to_string(),
441 sub_category: "Borrowed".to_string(),
442 specific_type: "&str".to_string(),
443 full_type: "&str".to_string(),
444 }
445 }
446 else if type_name.contains("Box<") {
448 let inner = extract_generic_params(type_name, "Box");
449 TypeHierarchy {
450 major_category: "Smart Pointers".to_string(),
451 sub_category: "Owned".to_string(),
452 specific_type: "Box".to_string(),
453 full_type: if inner.is_empty() {
454 "Box".to_string()
455 } else {
456 format!("Box<{inner}>")
457 },
458 }
459 } else if type_name.contains("Rc<") {
460 let inner = extract_generic_params(type_name, "Rc");
461 TypeHierarchy {
462 major_category: "Smart Pointers".to_string(),
463 sub_category: "Reference Counted".to_string(),
464 specific_type: "Rc".to_string(),
465 full_type: if inner.is_empty() {
466 "Rc".to_string()
467 } else {
468 format!("Rc<{inner}>")
469 },
470 }
471 } else if type_name.contains("Arc<") {
472 let inner = extract_generic_params(type_name, "Arc");
473 TypeHierarchy {
474 major_category: "Smart Pointers".to_string(),
475 sub_category: "Thread-Safe Shared".to_string(),
476 specific_type: "Arc".to_string(),
477 full_type: if inner.is_empty() {
478 "Arc".to_string()
479 } else {
480 format!("Arc<{inner}>")
481 },
482 }
483 }
484 else if is_primitive_type(type_name) {
486 let clean_type = type_name.split("::").last().unwrap_or(type_name);
487 let sub_cat = if clean_type.contains("i") || clean_type.contains("u") {
488 "Integers"
489 } else if clean_type.contains("f") {
490 "Floats"
491 } else if clean_type == "bool" {
492 "Boolean"
493 } else {
494 "Other"
495 };
496 TypeHierarchy {
497 major_category: "Primitives".to_string(),
498 sub_category: sub_cat.to_string(),
499 specific_type: clean_type.to_string(),
500 full_type: clean_type.to_string(),
501 }
502 }
503 else {
505 let simplified = type_name.split("::").last().unwrap_or(type_name);
506 TypeHierarchy {
507 major_category: "Custom Types".to_string(),
508 sub_category: "User Defined".to_string(),
509 specific_type: simplified.to_string(),
510 full_type: simplified.to_string(),
511 }
512 }
513}
514
515pub fn extract_generic_params(type_name: &str, container: &str) -> String {
517 if let Some(start) = type_name.find(&format!("{container}<")) {
518 let start = start + container.len() + 1;
519 if let Some(end) = find_matching_bracket(type_name, start - 1) {
520 let inner = &type_name[start..end];
521 return inner.split("::").last().unwrap_or(inner).to_string();
523 }
524 }
525 String::new()
526}
527
528fn find_matching_bracket(s: &str, start: usize) -> Option<usize> {
530 let chars: Vec<char> = s.chars().collect();
531 if start >= chars.len() || chars[start] != '<' {
532 return None;
533 }
534
535 let mut depth = 1;
536 for (i, item) in chars.iter().enumerate().skip(start + 1) {
537 match item {
538 '<' => depth += 1,
539 '>' => {
540 depth -= 1;
541 if depth == 0 {
542 return Some(i);
543 }
544 }
545 _ => {}
546 }
547 }
548 None
549}
550
551pub fn is_primitive_type(type_name: &str) -> bool {
553 let clean_type = type_name.split("::").last().unwrap_or(type_name);
554 matches!(
555 clean_type,
556 "i8" | "i16"
557 | "i32"
558 | "i64"
559 | "i128"
560 | "isize"
561 | "u8"
562 | "u16"
563 | "u32"
564 | "u64"
565 | "u128"
566 | "usize"
567 | "f32"
568 | "f64"
569 | "bool"
570 | "char"
571 )
572}
573
574pub fn extract_array_info(type_name: &str) -> String {
576 if let Some(start) = type_name.find('[') {
577 if let Some(end) = type_name.find(']') {
578 if end > start {
579 return type_name[start..=end].to_string();
580 }
581 }
582 }
583 "Array".to_string()
584}
585
586pub fn extract_std_module(type_name: &str) -> String {
588 let parts: Vec<&str> = type_name.split("::").collect();
589 if parts.len() >= 2 {
590 match parts[1] {
591 "collections" => "Collections".to_string(),
592 "sync" => "Synchronization".to_string(),
593 "thread" => "Threading".to_string(),
594 "fs" => "File System".to_string(),
595 "net" => "Networking".to_string(),
596 "io" => "Input/Output".to_string(),
597 _ => "Other".to_string(),
598 }
599 } else {
600 "Other".to_string()
601 }
602}
603
604use std::thread;
609use std::time::Duration;
610
611pub trait JoinHandleExt<T> {
613 fn join_timeout(self, timeout: Duration) -> Result<T, Box<dyn std::any::Any + Send + 'static>>;
619}
620
621impl<T: Send + 'static> JoinHandleExt<T> for thread::JoinHandle<T> {
622 fn join_timeout(self, timeout: Duration) -> Result<T, Box<dyn std::any::Any + Send + 'static>> {
623 if self.is_finished() {
625 return self.join().map_err(|e| Box::new(e) as _);
626 }
627
628 let (tx, rx) = std::sync::mpsc::channel();
630
631 thread::spawn(move || {
633 let result = self.join();
634 let _ = tx.send(result);
636 });
637
638 match rx.recv_timeout(timeout) {
640 Ok(result) => result.map_err(|e| Box::new(e) as _),
641 Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
642 Err(Box::new("Thread join timed out") as _)
645 }
646 Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
647 Err(Box::new("Thread communication error") as _)
649 }
650 }
651 }
652}
653
654#[cfg(test)]
655mod tests;