memscope_rs/
lib.rs

1//! Memory tracking and visualization tools for Rust applications.
2//!
3//! This crate provides tools for tracking memory allocations and visualizing
4//! memory usage in Rust applications. It includes a custom global allocator
5//! that tracks all heap allocations and deallocations, and provides utilities
6//! for exporting memory usage data in various formats.
7
8#![warn(missing_docs)]
9
10/// Macro for advanced type Trackable implementations
11pub mod advanced_trackable_macro;
12/// Advanced type analysis framework
13pub mod advanced_types;
14/// Advanced memory analysis functionality
15pub mod analysis;
16/// Command-line interface functionality
17pub mod cli;
18/// Core memory tracking functionality
19pub mod core;
20/// Export and visualization functionality
21pub mod export;
22/// Utility functions
23pub mod utils;
24/// Variable registry for lightweight HashMap-based variable tracking
25pub mod variable_registry;
26
27// Re-export key functions from unified modules
28/// Enhanced types for comprehensive memory analysis
29pub mod enhanced_types;
30pub use advanced_types::*;
31pub use analysis::*;
32pub use export::*;
33// Note: Macros are automatically available when the crate is imported
34
35// Re-export main types for easier use
36pub use analysis::enhanced_memory_analysis::EnhancedMemoryAnalyzer;
37pub use analysis::unsafe_ffi_tracker::{get_global_unsafe_ffi_tracker, UnsafeFFITracker};
38pub use core::allocator::TrackingAllocator;
39pub use core::tracker::{get_global_tracker, ExportOptions, MemoryTracker};
40pub use core::types::{AllocationInfo, TrackingError, TrackingResult};
41pub use export::visualization::{export_lifecycle_timeline, export_memory_analysis};
42pub use utils::{format_bytes, get_simple_type, simplify_type_name};
43
44// Re-export the derive macro when the derive feature is enabled
45#[cfg(feature = "derive")]
46pub use memscope_derive::Trackable;
47
48// Set up the global allocator when the tracking-allocator feature is enabled
49#[cfg(feature = "tracking-allocator")]
50#[global_allocator]
51/// Global tracking allocator instance used when the tracking-allocator feature is enabled.
52pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
53
54/// Trait for types that can be tracked by the memory tracker.
55pub trait Trackable {
56    /// Get the pointer to the heap allocation for this value.
57    fn get_heap_ptr(&self) -> Option<usize>;
58
59    /// Get the type name for this value.
60    fn get_type_name(&self) -> &'static str;
61
62    /// Get estimated size of the allocation.
63    fn get_size_estimate(&self) -> usize;
64
65    /// Get the reference count for smart pointers (default: 1 for non-smart pointers)
66    fn get_ref_count(&self) -> usize {
67        1
68    }
69
70    /// Get the data pointer for grouping related instances (default: same as heap_ptr)
71    fn get_data_ptr(&self) -> usize {
72        self.get_heap_ptr().unwrap_or(0)
73    }
74
75    /// Get all internal heap allocations for composite types (default: empty for simple types)
76    fn get_internal_allocations(&self, _var_name: &str) -> Vec<(usize, String)> {
77        Vec::new()
78    }
79
80    /// Track clone relationship for smart pointers (default: no-op for non-smart pointers)
81    fn track_clone_relationship(&self, _clone_ptr: usize, _source_ptr: usize) {
82        // Default implementation does nothing
83    }
84
85    /// Update reference count tracking for smart pointers (default: no-op for non-smart pointers)
86    fn update_ref_count_tracking(&self, _ptr: usize) {
87        // Default implementation does nothing
88    }
89
90    /// Get advanced type analysis information (default: None for simple types)
91    fn get_advanced_type_info(&self) -> Option<crate::advanced_types::AdvancedTypeInfo> {
92        // Check if this is an advanced type and analyze it
93        let type_name = self.get_type_name();
94        if crate::advanced_types::is_advanced_type(type_name) {
95            // Create a minimal allocation info for analysis
96            let allocation = crate::core::types::AllocationInfo {
97                ptr: self.get_heap_ptr().unwrap_or(0),
98                size: self.get_size_estimate(),
99                var_name: None,
100                type_name: Some(type_name.to_string()),
101                scope_name: None,
102                timestamp_alloc: std::time::SystemTime::now()
103                    .duration_since(std::time::UNIX_EPOCH)
104                    .unwrap_or_default()
105                    .as_nanos() as u64,
106                timestamp_dealloc: None,
107                thread_id: format!("{:?}", std::thread::current().id()),
108                borrow_count: 0,
109                stack_trace: None,
110                is_leaked: false,
111                lifetime_ms: None,
112                smart_pointer_info: None,
113                memory_layout: None,
114                generic_info: None,
115                dynamic_type_info: None,
116                runtime_state: None,
117                stack_allocation: None,
118                temporary_object: None,
119                fragmentation_analysis: None,
120                generic_instantiation: None,
121                type_relationships: None,
122                type_usage: None,
123                function_call_tracking: None,
124                lifecycle_tracking: None,
125                access_tracking: None,
126            };
127
128            Some(
129                crate::advanced_types::GenericAdvancedTypeAnalyzer::analyze_by_type_name(
130                    type_name,
131                    &allocation,
132                ),
133            )
134        } else {
135            None
136        }
137    }
138}
139
140// Implement Trackable for common heap-allocated types
141impl<T> Trackable for Vec<T> {
142    fn get_heap_ptr(&self) -> Option<usize> {
143        if self.capacity() > 0 {
144            Some(self.as_ptr() as usize)
145        } else {
146            None
147        }
148    }
149
150    fn get_type_name(&self) -> &'static str {
151        std::any::type_name::<Vec<T>>()
152    }
153
154    fn get_size_estimate(&self) -> usize {
155        self.capacity() * std::mem::size_of::<T>()
156    }
157}
158
159impl Trackable for String {
160    fn get_heap_ptr(&self) -> Option<usize> {
161        if self.capacity() > 0 {
162            Some(self.as_ptr() as usize)
163        } else {
164            None
165        }
166    }
167
168    fn get_type_name(&self) -> &'static str {
169        "String"
170    }
171
172    fn get_size_estimate(&self) -> usize {
173        self.capacity()
174    }
175}
176
177impl<T> Trackable for Box<T> {
178    fn get_heap_ptr(&self) -> Option<usize> {
179        Some(self.as_ref() as *const T as usize)
180    }
181
182    fn get_type_name(&self) -> &'static str {
183        std::any::type_name::<Box<T>>()
184    }
185
186    fn get_size_estimate(&self) -> usize {
187        std::mem::size_of::<T>()
188    }
189}
190
191impl<T> Trackable for std::rc::Rc<T> {
192    fn get_heap_ptr(&self) -> Option<usize> {
193        // For Rc, we create a truly unique identifier by using the Rc instance address
194        // This ensures each TrackedVariable<Rc<T>> gets a completely unique identifier
195        let instance_ptr = self as *const _ as usize;
196
197        // Use the instance pointer directly, but ensure it's in a safe range for JSON
198        // Add an offset to distinguish from regular heap pointers
199        Some(0x5000_0000 + (instance_ptr % 0x0FFF_FFFF))
200    }
201
202    fn get_type_name(&self) -> &'static str {
203        std::any::type_name::<std::rc::Rc<T>>()
204    }
205
206    fn get_size_estimate(&self) -> usize {
207        std::mem::size_of::<T>() + std::mem::size_of::<usize>() * 2 // Data + ref counts
208    }
209
210    /// Get the reference count for this Rc
211    fn get_ref_count(&self) -> usize {
212        std::rc::Rc::strong_count(self)
213    }
214
215    /// Get the data pointer for grouping related Rc instances
216    fn get_data_ptr(&self) -> usize {
217        std::rc::Rc::as_ptr(self) as usize
218    }
219
220    fn track_clone_relationship(&self, clone_ptr: usize, source_ptr: usize) {
221        let tracker = crate::core::tracker::get_global_tracker();
222        let data_ptr = self.get_data_ptr();
223        let strong_count = std::rc::Rc::strong_count(self);
224        let weak_count = std::rc::Rc::weak_count(self);
225
226        if let Err(e) = tracker.track_smart_pointer_clone(
227            clone_ptr,
228            source_ptr,
229            data_ptr,
230            strong_count,
231            weak_count,
232        ) {
233            tracing::warn!("Failed to track Rc clone relationship: {}", e);
234        }
235    }
236
237    fn update_ref_count_tracking(&self, ptr: usize) {
238        let tracker = crate::core::tracker::get_global_tracker();
239        let strong_count = std::rc::Rc::strong_count(self);
240        let weak_count = std::rc::Rc::weak_count(self);
241
242        if let Err(e) = tracker.update_smart_pointer_ref_count(ptr, strong_count, weak_count) {
243            tracing::warn!("Failed to update Rc ref count: {}", e);
244        }
245    }
246}
247
248impl<T> Trackable for std::sync::Arc<T> {
249    fn get_heap_ptr(&self) -> Option<usize> {
250        // For Arc, we create a truly unique identifier by using the Arc instance address
251        // This ensures each TrackedVariable<Arc<T>> gets a completely unique identifier
252        let instance_ptr = self as *const _ as usize;
253
254        // Use the instance pointer directly, but ensure it's in a safe range for JSON
255        // Add an offset to distinguish from regular heap pointers and Rc
256        Some(0x6000_0000 + (instance_ptr % 0x0FFF_FFFF))
257    }
258
259    fn get_type_name(&self) -> &'static str {
260        std::any::type_name::<std::sync::Arc<T>>()
261    }
262
263    fn get_size_estimate(&self) -> usize {
264        std::mem::size_of::<T>() + std::mem::size_of::<std::sync::atomic::AtomicUsize>() * 2
265        // Data + atomic ref counts
266    }
267
268    /// Get the reference count for this Arc
269    fn get_ref_count(&self) -> usize {
270        std::sync::Arc::strong_count(self)
271    }
272
273    /// Get the data pointer for grouping related Arc instances
274    fn get_data_ptr(&self) -> usize {
275        std::sync::Arc::as_ptr(self) as usize
276    }
277
278    fn track_clone_relationship(&self, clone_ptr: usize, source_ptr: usize) {
279        let tracker = crate::core::tracker::get_global_tracker();
280        let data_ptr = self.get_data_ptr();
281        let strong_count = std::sync::Arc::strong_count(self);
282        let weak_count = std::sync::Arc::weak_count(self);
283
284        if let Err(e) = tracker.track_smart_pointer_clone(
285            clone_ptr,
286            source_ptr,
287            data_ptr,
288            strong_count,
289            weak_count,
290        ) {
291            tracing::warn!("Failed to track Arc clone relationship: {}", e);
292        }
293    }
294
295    fn update_ref_count_tracking(&self, ptr: usize) {
296        let tracker = crate::core::tracker::get_global_tracker();
297        let strong_count = std::sync::Arc::strong_count(self);
298        let weak_count = std::sync::Arc::weak_count(self);
299
300        if let Err(e) = tracker.update_smart_pointer_ref_count(ptr, strong_count, weak_count) {
301            tracing::warn!("Failed to update Arc ref count: {}", e);
302        }
303    }
304}
305
306impl<K, V> Trackable for std::collections::HashMap<K, V> {
307    fn get_heap_ptr(&self) -> Option<usize> {
308        // HashMap has internal heap allocations for buckets
309        // We'll use the HashMap's address as a proxy
310        Some(self as *const _ as usize)
311    }
312
313    fn get_type_name(&self) -> &'static str {
314        std::any::type_name::<std::collections::HashMap<K, V>>()
315    }
316
317    fn get_size_estimate(&self) -> usize {
318        // Rough estimate: capacity * (key_size + value_size + overhead)
319        self.capacity() * (std::mem::size_of::<K>() + std::mem::size_of::<V>() + 16)
320    }
321}
322
323impl<K, V> Trackable for std::collections::BTreeMap<K, V> {
324    fn get_heap_ptr(&self) -> Option<usize> {
325        if self.is_empty() {
326            None
327        } else {
328            Some(self as *const _ as usize)
329        }
330    }
331
332    fn get_type_name(&self) -> &'static str {
333        std::any::type_name::<std::collections::BTreeMap<K, V>>()
334    }
335
336    fn get_size_estimate(&self) -> usize {
337        // BTreeMap nodes: rough estimate
338        self.len() * (std::mem::size_of::<K>() + std::mem::size_of::<V>() + 32)
339    }
340}
341
342impl<T> Trackable for std::collections::HashSet<T> {
343    fn get_heap_ptr(&self) -> Option<usize> {
344        if self.is_empty() {
345            None
346        } else {
347            Some(self as *const _ as usize)
348        }
349    }
350
351    fn get_type_name(&self) -> &'static str {
352        std::any::type_name::<std::collections::HashSet<T>>()
353    }
354
355    fn get_size_estimate(&self) -> usize {
356        self.capacity() * (std::mem::size_of::<T>() + 8) // T + hash overhead
357    }
358}
359
360impl<T> Trackable for std::collections::BTreeSet<T> {
361    fn get_heap_ptr(&self) -> Option<usize> {
362        if self.is_empty() {
363            None
364        } else {
365            Some(self as *const _ as usize)
366        }
367    }
368
369    fn get_type_name(&self) -> &'static str {
370        std::any::type_name::<std::collections::BTreeSet<T>>()
371    }
372
373    fn get_size_estimate(&self) -> usize {
374        self.len() * (std::mem::size_of::<T>() + 24) // T + tree node overhead
375    }
376}
377
378impl<T> Trackable for std::collections::VecDeque<T> {
379    fn get_heap_ptr(&self) -> Option<usize> {
380        if self.capacity() > 0 {
381            Some(self.as_slices().0.as_ptr() as usize)
382        } else {
383            None
384        }
385    }
386
387    fn get_type_name(&self) -> &'static str {
388        std::any::type_name::<std::collections::VecDeque<T>>()
389    }
390
391    fn get_size_estimate(&self) -> usize {
392        self.capacity() * std::mem::size_of::<T>()
393    }
394}
395
396impl<T> Trackable for std::collections::LinkedList<T> {
397    fn get_heap_ptr(&self) -> Option<usize> {
398        if self.is_empty() {
399            None
400        } else {
401            Some(self as *const _ as usize)
402        }
403    }
404
405    fn get_type_name(&self) -> &'static str {
406        std::any::type_name::<std::collections::LinkedList<T>>()
407    }
408
409    fn get_size_estimate(&self) -> usize {
410        self.len() * (std::mem::size_of::<T>() + std::mem::size_of::<usize>() * 2)
411        // T + prev/next pointers
412    }
413}
414
415impl<T> Trackable for std::collections::BinaryHeap<T> {
416    fn get_heap_ptr(&self) -> Option<usize> {
417        if self.capacity() > 0 {
418            Some(self as *const _ as usize)
419        } else {
420            None
421        }
422    }
423
424    fn get_type_name(&self) -> &'static str {
425        std::any::type_name::<std::collections::BinaryHeap<T>>()
426    }
427
428    fn get_size_estimate(&self) -> usize {
429        self.capacity() * std::mem::size_of::<T>()
430    }
431}
432
433impl<T> Trackable for std::rc::Weak<T> {
434    fn get_heap_ptr(&self) -> Option<usize> {
435        // Weak pointers don't own the data, but we can track the weak reference itself
436        let instance_ptr = self as *const _ as usize;
437        Some(0x7000_0000 + (instance_ptr % 0x0FFF_FFFF))
438    }
439
440    fn get_type_name(&self) -> &'static str {
441        std::any::type_name::<std::rc::Weak<T>>()
442    }
443
444    fn get_size_estimate(&self) -> usize {
445        std::mem::size_of::<std::rc::Weak<T>>()
446    }
447
448    fn get_ref_count(&self) -> usize {
449        self.weak_count()
450    }
451
452    fn get_data_ptr(&self) -> usize {
453        // Try to upgrade and get data pointer, return 0 if data is gone
454        if let Some(upgraded) = self.upgrade() {
455            std::rc::Rc::as_ptr(&upgraded) as usize
456        } else {
457            0 // Data has been deallocated
458        }
459    }
460}
461
462impl<T> Trackable for std::sync::Weak<T> {
463    fn get_heap_ptr(&self) -> Option<usize> {
464        // Weak pointers don't own the data, but we can track the weak reference itself
465        let instance_ptr = self as *const _ as usize;
466        Some(0x8000_0000 + (instance_ptr % 0x0FFF_FFFF))
467    }
468
469    fn get_type_name(&self) -> &'static str {
470        std::any::type_name::<std::sync::Weak<T>>()
471    }
472
473    fn get_size_estimate(&self) -> usize {
474        std::mem::size_of::<std::sync::Weak<T>>()
475    }
476
477    fn get_ref_count(&self) -> usize {
478        self.weak_count()
479    }
480
481    fn get_data_ptr(&self) -> usize {
482        // Try to upgrade and get data pointer, return 0 if data is gone
483        if let Some(upgraded) = self.upgrade() {
484            std::sync::Arc::as_ptr(&upgraded) as usize
485        } else {
486            0 // Data has been deallocated
487        }
488    }
489}
490
491// Use the macro to implement Trackable for advanced types
492impl_advanced_trackable!(std::cell::RefCell<T>, 0xA000_0000);
493impl_advanced_trackable!(std::sync::Mutex<T>, 0xB000_0000);
494impl_advanced_trackable!(std::sync::RwLock<T>, 0xC000_0000);
495
496// Additional advanced types with the macro
497impl_advanced_trackable!(std::cell::Cell<T>, 0xA100_0000);
498impl_advanced_trackable!(std::sync::mpsc::Sender<T>, 0xD000_0000);
499impl_advanced_trackable!(std::sync::mpsc::Receiver<T>, 0xD100_0000);
500impl_advanced_trackable!(std::sync::atomic::AtomicBool, 0xE000_0000, no_generics);
501impl_advanced_trackable!(std::sync::atomic::AtomicUsize, 0xE100_0000, no_generics);
502impl_advanced_trackable!(std::sync::atomic::AtomicIsize, 0xE200_0000, no_generics);
503impl_advanced_trackable!(std::sync::atomic::AtomicU8, 0xE300_0000, no_generics);
504impl_advanced_trackable!(std::sync::atomic::AtomicU16, 0xE400_0000, no_generics);
505impl_advanced_trackable!(std::sync::atomic::AtomicU32, 0xE500_0000, no_generics);
506impl_advanced_trackable!(std::sync::atomic::AtomicU64, 0xE600_0000, no_generics);
507impl_advanced_trackable!(std::sync::atomic::AtomicI8, 0xE700_0000, no_generics);
508impl_advanced_trackable!(std::sync::atomic::AtomicI16, 0xE800_0000, no_generics);
509impl_advanced_trackable!(std::sync::atomic::AtomicI32, 0xE900_0000, no_generics);
510impl_advanced_trackable!(std::sync::atomic::AtomicI64, 0xEA00_0000, no_generics);
511impl_advanced_trackable!(std::mem::ManuallyDrop<T>, 0xF000_0000);
512impl_advanced_trackable!(std::mem::MaybeUninit<T>, 0xF100_0000);
513impl_advanced_trackable!(std::pin::Pin<T>, 0xF200_0000);
514
515// Implement for Option<T> where T: Trackable
516impl<T: Trackable> Trackable for Option<T> {
517    fn get_heap_ptr(&self) -> Option<usize> {
518        match self {
519            Some(value) => value.get_heap_ptr(),
520            None => None,
521        }
522    }
523
524    fn get_type_name(&self) -> &'static str {
525        std::any::type_name::<Option<T>>()
526    }
527
528    fn get_size_estimate(&self) -> usize {
529        match self {
530            Some(value) => std::mem::size_of::<Option<T>>() + value.get_size_estimate(),
531            None => std::mem::size_of::<Option<T>>(),
532        }
533    }
534
535    fn get_internal_allocations(&self, var_name: &str) -> Vec<(usize, String)> {
536        match self {
537            Some(value) => value.get_internal_allocations(&format!("{}::Some", var_name)),
538            None => Vec::new(),
539        }
540    }
541}
542
543// Implement for Result<T, E> where T: Trackable, E: Trackable
544impl<T: Trackable, E: Trackable> Trackable for Result<T, E> {
545    fn get_heap_ptr(&self) -> Option<usize> {
546        match self {
547            Ok(value) => value.get_heap_ptr(),
548            Err(error) => error.get_heap_ptr(),
549        }
550    }
551
552    fn get_type_name(&self) -> &'static str {
553        std::any::type_name::<Result<T, E>>()
554    }
555
556    fn get_size_estimate(&self) -> usize {
557        match self {
558            Ok(value) => std::mem::size_of::<Result<T, E>>() + value.get_size_estimate(),
559            Err(error) => std::mem::size_of::<Result<T, E>>() + error.get_size_estimate(),
560        }
561    }
562
563    fn get_internal_allocations(&self, var_name: &str) -> Vec<(usize, String)> {
564        match self {
565            Ok(value) => value.get_internal_allocations(&format!("{}::Ok", var_name)),
566            Err(error) => error.get_internal_allocations(&format!("{}::Err", var_name)),
567        }
568    }
569}
570
571/// **[RECOMMENDED]** Track a variable's memory allocation without taking ownership.
572///
573/// This is the **default and recommended** tracking macro for most use cases.
574/// It performs zero-cost tracking by reference, allowing continued use of the original variable.
575///
576/// ## ✅ Use this when:
577/// - You want to track memory usage without changing your code
578/// - Performance is critical (zero overhead)
579/// - You need to continue using the variable after tracking
580/// - You're tracking many variables and don't want clone overhead
581/// - You're doing basic memory profiling and analysis
582///
583/// ## ❌ Don't use this when:
584/// - You need precise lifecycle tracking with automatic cleanup
585/// - You're tracking temporary variables that will be moved/consumed immediately
586///
587/// # Example
588/// ```rust
589/// use memscope_rs::track_var;
590///
591/// let my_vec = vec![1, 2, 3, 4, 5];
592/// track_var!(my_vec); // Zero-cost tracking
593/// // my_vec can still be used normally - no ownership changes!
594/// println!("Vector: {:?}", my_vec);
595/// my_vec.push(6); // Still fully usable
596/// ```
597#[macro_export]
598macro_rules! track_var {
599    ($var:expr) => {{
600        let var_name = stringify!($var);
601        let _ = $crate::_track_var_impl(&$var, var_name);
602        // Pure tracking - no return value to avoid any ownership implications
603    }};
604}
605
606/// **[ADVANCED]** Track a variable with full lifecycle management and ownership transfer.
607///
608/// This macro creates a tracking wrapper that takes ownership of the variable
609/// and provides automatic lifecycle tracking with precise timing measurements.
610/// The wrapper includes robust drop protection to prevent duplicate tracking
611/// and enhanced smart pointer detection for accurate analysis.
612///
613/// ## ✅ Use this when:
614/// - You need precise lifecycle tracking with automatic cleanup detection
615/// - You want to measure exact variable lifetimes
616/// - You're doing advanced memory analysis or debugging
617/// - You're tracking variables that will be consumed/moved anyway
618/// - You need the wrapper's additional methods (get(), get_mut(), into_inner())
619/// - You're working with smart pointers (Rc, Arc, Box) that need special handling
620///
621/// ## ❌ Don't use this when:
622/// - You need to continue using the original variable (use `track_var!` instead)
623/// - Performance is critical and you don't need lifecycle timing
624/// - You're tracking many variables (clone overhead)
625/// - You're doing basic memory profiling
626///
627/// ## 🛡️ Safety Features:
628/// - **Drop Protection**: Prevents duplicate destruction tracking even if `into_inner()` is used
629/// - **Smart Pointer Detection**: Automatically detects and handles Rc, Arc, and Box types
630/// - **Error Resilience**: Uses panic-safe error handling to prevent drop failures
631/// - **Atomic Protection**: Thread-safe duplicate tracking prevention
632///
633/// ## ⚠️ Performance Note:
634/// This macro takes ownership of the variable. If you need the original variable
635/// afterwards, you'll need to clone it first, which has performance implications.
636///
637/// # Example
638/// ```rust
639/// use memscope_rs::track_var_owned;
640/// use std::rc::Rc;
641///
642/// // Regular type tracking
643/// let my_vec = vec![1, 2, 3, 4, 5];
644/// let tracked_vec = track_var_owned!(my_vec); // Takes ownership
645/// // tracked_vec behaves like my_vec but with automatic lifecycle tracking
646/// println!("Length: {}", tracked_vec.len()); // Transparent access via Deref
647/// let original = tracked_vec.into_inner(); // Get original back if needed
648///
649/// // Smart pointer tracking with enhanced detection
650/// let smart_ptr = Rc::new(vec![1, 2, 3]);
651/// let tracked_smart = track_var_owned!(smart_ptr); // Automatically detects Rc
652/// println!("Ref count: {}", Rc::strong_count(&tracked_smart)); // Works transparently
653/// ```
654#[macro_export]
655macro_rules! track_var_owned {
656    ($var:expr) => {{
657        let var_name = stringify!($var);
658        $crate::TrackedVariable::new($var, var_name.to_string())
659    }};
660}
661
662/// **[SMART]** Intelligent tracking that automatically chooses the best strategy.
663///
664/// This macro automatically detects the variable type and chooses the optimal tracking approach:
665/// - For `Copy` types (i32, f64, bool, etc.): Creates a copy for tracking (zero overhead)
666/// - For non-`Copy` types: Uses reference-based tracking like `track_var!`
667/// - For smart pointers (Rc, Arc): Clones the pointer (cheap reference increment)
668///
669/// ## ✅ Use this when:
670/// - You want the best of both worlds without thinking about it
671/// - You're tracking mixed types (some Copy, some not)
672/// - You want automatic optimization based on type characteristics
673/// - You're prototyping and want convenience
674///
675/// ## ❌ Don't use this when:
676/// - You need explicit control over tracking behavior
677/// - You're in performance-critical code and want predictable behavior
678/// - You need precise lifecycle tracking (use `track_var_owned!` instead)
679///
680/// # Example
681/// ```rust
682/// use memscope_rs::track_var_smart;
683///
684/// let number = 42i32;           // Copy type - will be copied
685/// let my_vec = vec![1, 2, 3];   // Non-Copy - will be tracked by reference
686/// let rc_data = Rc::new(vec![]); // Smart pointer - will clone the Rc
687///
688/// track_var_smart!(number);   // Copies the i32 (cheap)
689/// track_var_smart!(my_vec);    // Tracks by reference (zero cost)
690/// track_var_smart!(rc_data);   // Clones Rc (cheap reference increment)
691///
692/// // All variables remain fully usable!
693/// println!("{}, {:?}, {:?}", number, my_vec, rc_data);
694/// ```
695#[macro_export]
696macro_rules! track_var_smart {
697    ($var:expr) => {{
698        let var_name = stringify!($var);
699        $crate::_smart_track_var_impl($var, var_name)
700    }};
701}
702
703// Global counter for generating unique identifiers for TrackedVariable instances
704static TRACKED_VARIABLE_COUNTER: std::sync::atomic::AtomicUsize =
705    std::sync::atomic::AtomicUsize::new(1);
706
707/// Smart pointer detection and analysis utilities.
708///
709/// This module provides centralized logic for detecting and handling different types
710/// of smart pointers (Rc, Arc, Box) in a consistent and maintainable way.
711/// It replaces scattered string-matching logic with type-safe detection methods.
712pub mod smart_pointer_utils {
713    /// Smart pointer type information
714    #[derive(Debug, Clone, PartialEq)]
715    pub enum SmartPointerType {
716        /// Reference counted pointer (std::rc::Rc)
717        Rc,
718        /// Atomically reference counted pointer (std::sync::Arc)
719        Arc,
720        /// Heap allocated box (std::boxed::Box)
721        Box,
722        /// Not a smart pointer
723        None,
724    }
725
726    /// Detect smart pointer type from type name
727    pub fn detect_smart_pointer_type(type_name: &str) -> SmartPointerType {
728        if type_name.contains("::Rc<") || type_name.contains("std::rc::Rc<") {
729            SmartPointerType::Rc
730        } else if type_name.contains("::Arc<") || type_name.contains("std::sync::Arc<") {
731            SmartPointerType::Arc
732        } else if type_name.contains("::Box<") || type_name.contains("std::boxed::Box<") {
733            SmartPointerType::Box
734        } else {
735            SmartPointerType::None
736        }
737    }
738
739    /// Check if a type is a smart pointer
740    pub fn is_smart_pointer(type_name: &str) -> bool {
741        detect_smart_pointer_type(type_name) != SmartPointerType::None
742    }
743
744    /// Generate unique synthetic pointer for smart pointer tracking
745    pub fn generate_synthetic_pointer(
746        smart_pointer_type: SmartPointerType,
747        unique_id: usize,
748    ) -> usize {
749        match smart_pointer_type {
750            SmartPointerType::Rc => 0x5000_0000 + unique_id,
751            SmartPointerType::Arc => 0x6000_0000 + unique_id,
752            SmartPointerType::Box => 0x7000_0000 + unique_id,
753            SmartPointerType::None => unique_id, // Fallback, shouldn't be used
754        }
755    }
756}
757
758/// A wrapper that provides automatic lifecycle tracking for variables.
759///
760/// This struct wraps any `Trackable` type and automatically handles:
761/// - Creation tracking when constructed
762/// - Destruction tracking when dropped with duplicate protection
763/// - Transparent access to the wrapped value via Deref/DerefMut
764/// - Smart pointer detection and specialized handling for Rc, Arc, and Box
765/// - Thread-safe drop protection using atomic flags
766/// - Panic-safe error handling in drop logic
767///
768/// ## Key Features:
769/// - **Drop Protection**: Prevents duplicate destruction tracking
770/// - **Smart Pointer Support**: Automatic detection and handling of reference-counted types
771/// - **Error Resilience**: Robust error handling that won't crash on tracking failures
772/// - **Thread Safety**: Uses atomic operations for safe concurrent access
773/// - **Zero-Cost Abstraction**: Transparent access to wrapped value with minimal overhead
774pub struct TrackedVariable<T: Trackable> {
775    inner: T,
776    var_name: String,
777    ptr: Option<usize>,
778    creation_time: u64,
779    unique_id: usize, // Unique identifier for this TrackedVariable instance
780    destruction_tracked: std::sync::atomic::AtomicBool, // Protection against duplicate drop tracking
781}
782
783impl<T: Trackable> TrackedVariable<T> {
784    /// Create a new tracked variable wrapper.
785    pub fn new(value: T, var_name: String) -> Self {
786        let creation_time = std::time::SystemTime::now()
787            .duration_since(std::time::UNIX_EPOCH)
788            .unwrap_or_default()
789            .as_nanos() as u64;
790
791        let unique_id = TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
792        let type_name = value.get_type_name().to_string();
793        let smart_pointer_type = smart_pointer_utils::detect_smart_pointer_type(&type_name);
794        let is_smart_pointer = smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
795
796        // For smart pointers, use a unique synthetic pointer based on the TrackedVariable instance
797        // For other types, use their heap pointer or generate a synthetic one if none exists
798        let ptr = if is_smart_pointer {
799            Some(smart_pointer_utils::generate_synthetic_pointer(
800                smart_pointer_type,
801                unique_id,
802            ))
803        } else {
804            // For non-smart pointer types, use heap pointer or generate synthetic pointer
805            value.get_heap_ptr().or_else(|| {
806                // Generate synthetic pointer for types without heap allocation
807                Some(0x8000_0000 + unique_id)
808            })
809        };
810
811        // Track creation using the same logic as _track_var_impl
812        if let Some(ptr_val) = ptr {
813            let tracker = get_global_tracker();
814
815            // 1. Register variable in HashMap registry (lightweight and fast)
816            let _ = crate::variable_registry::VariableRegistry::register_variable(
817                ptr_val,
818                var_name.clone(),
819                type_name.clone(),
820                value.get_size_estimate(),
821            );
822
823            // 2. Associate variable with current scope
824            let scope_tracker = crate::core::scope_tracker::get_global_scope_tracker();
825            let _ = scope_tracker.associate_variable(var_name.clone(), value.get_size_estimate());
826
827            // 3. Create appropriate allocation based on type (same as _track_var_impl)
828            if is_smart_pointer {
829                // For smart pointers, create specialized allocation
830                let ref_count = value.get_ref_count();
831                let data_ptr = value.get_data_ptr();
832
833                let _ = tracker.create_smart_pointer_allocation(
834                    ptr_val,
835                    value.get_size_estimate(),
836                    var_name.clone(),
837                    type_name.clone(),
838                    creation_time,
839                    ref_count,
840                    data_ptr,
841                );
842
843                tracing::debug!(
844                    "🎯 Created smart pointer tracking for '{}' at ptr 0x{:x}, ref_count={}",
845                    var_name,
846                    ptr_val,
847                    ref_count
848                );
849            } else if ptr_val >= 0x8000_0000 {
850                // For synthetic pointers, create synthetic allocation
851                let _ = tracker.create_synthetic_allocation(
852                    ptr_val,
853                    value.get_size_estimate(),
854                    var_name.clone(),
855                    type_name.clone(),
856                    creation_time,
857                );
858
859                tracing::debug!(
860                    "🎯 Created synthetic tracking for '{}' at ptr 0x{:x}",
861                    var_name,
862                    ptr_val
863                );
864            } else {
865                // For real heap pointers, use association
866                let _ = tracker.associate_var(ptr_val, var_name.clone(), type_name.clone());
867
868                tracing::debug!(
869                    "🎯 Associated variable '{}' of type '{}' at ptr 0x{:x}",
870                    var_name,
871                    type_name,
872                    ptr_val
873                );
874            }
875        }
876
877        Self {
878            inner: value,
879            var_name,
880            ptr,
881            creation_time,
882            unique_id,
883            destruction_tracked: std::sync::atomic::AtomicBool::new(false),
884        }
885    }
886
887    /// Get a reference to the inner value.
888    pub fn get(&self) -> &T {
889        &self.inner
890    }
891
892    /// Get a mutable reference to the inner value.
893    pub fn get_mut(&mut self) -> &mut T {
894        &mut self.inner
895    }
896
897    /// Consume the wrapper and return the inner value.
898    ///
899    /// This method safely extracts the wrapped value while ensuring that
900    /// destruction tracking occurs exactly once. It uses atomic protection
901    /// to prevent duplicate tracking even if the Drop trait would normally
902    /// execute afterwards.
903    ///
904    /// ## Safety Features:
905    /// - Uses `ManuallyDrop` to prevent automatic Drop execution
906    /// - Atomic flag prevents duplicate destruction tracking
907    /// - Proper error handling for tracking failures
908    /// - Smart pointer detection for specialized handling
909    pub fn into_inner(self) -> T {
910        // Use ManuallyDrop to prevent automatic Drop execution
911        let mut manual_drop_self = std::mem::ManuallyDrop::new(self);
912
913        // Manually trigger drop logic if not already tracked
914        if let Some(ptr_val) = manual_drop_self.ptr.take() {
915            // Check if destruction was already tracked to prevent duplicates
916            if !manual_drop_self
917                .destruction_tracked
918                .swap(true, std::sync::atomic::Ordering::Relaxed)
919            {
920                let type_name = manual_drop_self.inner.get_type_name();
921                let smart_pointer_type = smart_pointer_utils::detect_smart_pointer_type(type_name);
922                let is_smart_pointer =
923                    smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
924
925                if is_smart_pointer {
926                    let final_ref_count = manual_drop_self.inner.get_ref_count();
927                    if let Err(e) = Self::track_smart_pointer_destruction(
928                        &manual_drop_self.var_name,
929                        ptr_val,
930                        manual_drop_self.creation_time,
931                        final_ref_count,
932                    ) {
933                        tracing::warn!(
934                            "Failed to track smart pointer destruction in into_inner(): {}",
935                            e
936                        );
937                    }
938                } else {
939                    if let Err(e) = Self::track_destruction(
940                        &manual_drop_self.var_name,
941                        ptr_val,
942                        manual_drop_self.creation_time,
943                    ) {
944                        tracing::warn!("Failed to track destruction in into_inner(): {}", e);
945                    }
946                }
947            }
948        }
949
950        // Safe ownership transfer
951        // SAFETY: We're taking ownership of the inner value and preventing Drop from running
952        unsafe { std::ptr::read(&manual_drop_self.inner) }
953    }
954
955    /// Internal method to track variable destruction.
956    fn track_destruction(var_name: &str, ptr: usize, creation_time: u64) -> TrackingResult<()> {
957        let destruction_time = std::time::SystemTime::now()
958            .duration_since(std::time::UNIX_EPOCH)
959            .unwrap_or_default()
960            .as_nanos() as u64;
961
962        let lifetime_ms = (destruction_time.saturating_sub(creation_time)) / 1_000_000;
963
964        // Update variable registry with destruction info
965        if let Err(e) = crate::variable_registry::VariableRegistry::mark_variable_destroyed(
966            ptr,
967            destruction_time,
968        ) {
969            tracing::warn!("Failed to mark variable destroyed in registry: {}", e);
970        }
971
972        // Track deallocation with precise lifetime in memory tracker
973        let tracker = get_global_tracker();
974        tracker.track_deallocation_with_lifetime(ptr, lifetime_ms)?;
975
976        tracing::debug!(
977            "Destroyed tracked variable '{}' at ptr 0x{:x}, lifetime: {}ms",
978            var_name,
979            ptr,
980            lifetime_ms
981        );
982
983        Ok(())
984    }
985
986    /// Internal method to track smart pointer destruction with enhanced metadata.
987    fn track_smart_pointer_destruction(
988        var_name: &str,
989        ptr: usize,
990        creation_time: u64,
991        final_ref_count: usize,
992    ) -> TrackingResult<()> {
993        let destruction_time = std::time::SystemTime::now()
994            .duration_since(std::time::UNIX_EPOCH)
995            .unwrap_or_default()
996            .as_nanos() as u64;
997
998        let lifetime_ms = (destruction_time.saturating_sub(creation_time)) / 1_000_000;
999
1000        // Update variable registry with destruction info
1001        if let Err(e) = crate::variable_registry::VariableRegistry::mark_variable_destroyed(
1002            ptr,
1003            destruction_time,
1004        ) {
1005            tracing::warn!("Failed to mark smart pointer destroyed in registry: {}", e);
1006        }
1007
1008        // Track smart pointer deallocation with enhanced metadata
1009        let tracker = get_global_tracker();
1010        tracker.track_smart_pointer_deallocation(ptr, lifetime_ms, final_ref_count)?;
1011
1012        tracing::debug!(
1013            "Destroyed smart pointer '{}' at ptr 0x{:x}, lifetime: {}ms, final_ref_count: {}",
1014            var_name,
1015            ptr,
1016            lifetime_ms,
1017            final_ref_count
1018        );
1019
1020        Ok(())
1021    }
1022}
1023
1024impl<T: Trackable> Drop for TrackedVariable<T> {
1025    fn drop(&mut self) {
1026        // Only execute drop logic if ptr exists and destruction hasn't been tracked yet
1027        if let Some(ptr_val) = self.ptr.take() {
1028            // Check if destruction was already tracked to prevent duplicates
1029            if !self
1030                .destruction_tracked
1031                .swap(true, std::sync::atomic::Ordering::Relaxed)
1032            {
1033                // Use catch_unwind to prevent panic in drop from affecting program termination
1034                let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1035                    // Skip expensive drop tracking in fast mode
1036                    let tracker = get_global_tracker();
1037                    if tracker.is_fast_mode() {
1038                        return;
1039                    }
1040
1041                    let type_name = self.inner.get_type_name();
1042                    let smart_pointer_type =
1043                        smart_pointer_utils::detect_smart_pointer_type(type_name);
1044                    let is_smart_pointer =
1045                        smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
1046
1047                    if is_smart_pointer {
1048                        // For smart pointers, get the final reference count before destruction
1049                        let final_ref_count = self.inner.get_ref_count();
1050                        if let Err(e) = Self::track_smart_pointer_destruction(
1051                            &self.var_name,
1052                            ptr_val,
1053                            self.creation_time,
1054                            final_ref_count,
1055                        ) {
1056                            tracing::error!(
1057                                "Failed to track smart pointer destruction in drop: {}",
1058                                e
1059                            );
1060                        }
1061                    } else {
1062                        // For regular types, use standard destruction tracking
1063                        if let Err(e) =
1064                            Self::track_destruction(&self.var_name, ptr_val, self.creation_time)
1065                        {
1066                            tracing::error!("Failed to track destruction in drop: {}", e);
1067                        }
1068                    }
1069                }));
1070            }
1071        }
1072    }
1073}
1074
1075// Implement Deref and DerefMut for transparent access
1076impl<T: Trackable> std::ops::Deref for TrackedVariable<T> {
1077    type Target = T;
1078
1079    fn deref(&self) -> &Self::Target {
1080        &self.inner
1081    }
1082}
1083
1084impl<T: Trackable> std::ops::DerefMut for TrackedVariable<T> {
1085    fn deref_mut(&mut self) -> &mut Self::Target {
1086        &mut self.inner
1087    }
1088}
1089
1090// Implement common traits to make TrackedVariable behave like the inner type
1091impl<T: Trackable + std::fmt::Debug> std::fmt::Debug for TrackedVariable<T> {
1092    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1093        write!(f, "TrackedVariable({:?})", self.inner)
1094    }
1095}
1096
1097impl<T: Trackable + std::fmt::Display> std::fmt::Display for TrackedVariable<T> {
1098    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1099        write!(f, "{}", self.inner)
1100    }
1101}
1102
1103impl<T: Trackable + Clone> Clone for TrackedVariable<T> {
1104    fn clone(&self) -> Self {
1105        // Create a new tracked variable for the clone with a unique name
1106        let clone_name = format!("{}_clone_{}", self.var_name, self.unique_id);
1107        Self::new(self.inner.clone(), clone_name)
1108    }
1109}
1110
1111/// Internal implementation function for the track_var! macro.
1112/// This function should not be called directly.
1113///
1114/// Enhanced with log-based variable name persistence for lifecycle-independent tracking.
1115#[doc(hidden)]
1116pub fn _track_var_impl<T: Trackable>(var: &T, var_name: &str) -> TrackingResult<()> {
1117    let tracker = get_global_tracker();
1118
1119    // Fast path for testing mode
1120    if tracker.is_fast_mode() {
1121        let unique_id = TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1122        let synthetic_ptr = 0x8000_0000 + unique_id;
1123        return tracker.fast_track_allocation(
1124            synthetic_ptr,
1125            var.get_size_estimate(),
1126            var_name.to_string(),
1127        );
1128    }
1129
1130    let type_name = var.get_type_name().to_string();
1131    let smart_pointer_type = smart_pointer_utils::detect_smart_pointer_type(&type_name);
1132    let is_smart_pointer = smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
1133
1134    // Get or generate pointer (consistent with TrackedVariable::new logic)
1135    let ptr = if is_smart_pointer {
1136        // For smart pointers, generate a unique synthetic pointer
1137        let unique_id = TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1138        Some(smart_pointer_utils::generate_synthetic_pointer(
1139            smart_pointer_type,
1140            unique_id,
1141        ))
1142    } else {
1143        // For non-smart pointer types, use heap pointer or generate synthetic pointer
1144        var.get_heap_ptr().or_else(|| {
1145            // Generate synthetic pointer for types without heap allocation
1146            let unique_id =
1147                TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1148            Some(0x8000_0000 + unique_id)
1149        })
1150    };
1151
1152    if let Some(ptr_val) = ptr {
1153        let creation_time = std::time::SystemTime::now()
1154            .duration_since(std::time::UNIX_EPOCH)
1155            .unwrap_or_default()
1156            .as_nanos() as u64;
1157
1158        // 1. Register variable in HashMap registry (lightweight and fast)
1159        let _ = crate::variable_registry::VariableRegistry::register_variable(
1160            ptr_val,
1161            var_name.to_string(),
1162            type_name.clone(),
1163            var.get_size_estimate(),
1164        );
1165
1166        // 2. Associate variable with current scope
1167        let scope_tracker = crate::core::scope_tracker::get_global_scope_tracker();
1168        let _ = scope_tracker.associate_variable(var_name.to_string(), var.get_size_estimate());
1169
1170        // 3. Create appropriate allocation based on type
1171        if is_smart_pointer {
1172            // For smart pointers, create specialized allocation
1173            let ref_count = var.get_ref_count();
1174            let data_ptr = var.get_data_ptr();
1175
1176            let _ = tracker.create_smart_pointer_allocation(
1177                ptr_val,
1178                var.get_size_estimate(),
1179                var_name.to_string(),
1180                type_name.clone(),
1181                creation_time,
1182                ref_count,
1183                data_ptr,
1184            );
1185
1186            tracing::debug!(
1187                "🎯 Created smart pointer tracking for '{}' at ptr 0x{:x}, ref_count={}",
1188                var_name,
1189                ptr_val,
1190                ref_count
1191            );
1192        } else if ptr_val >= 0x8000_0000 {
1193            // For synthetic pointers, create synthetic allocation
1194            let _ = tracker.create_synthetic_allocation(
1195                ptr_val,
1196                var.get_size_estimate(),
1197                var_name.to_string(),
1198                type_name.clone(),
1199                creation_time,
1200            );
1201
1202            tracing::debug!(
1203                "🎯 Created synthetic tracking for '{}' at ptr 0x{:x}",
1204                var_name,
1205                ptr_val
1206            );
1207        } else {
1208            // For real heap pointers, use association
1209            tracker.associate_var(ptr_val, var_name.to_string(), type_name.clone())?;
1210
1211            tracing::debug!(
1212                "🎯 Associated variable '{}' of type '{}' at ptr 0x{:x}",
1213                var_name,
1214                type_name,
1215                ptr_val
1216            );
1217        }
1218    } else {
1219        // This should not happen with our new logic, but keep as fallback
1220        tracing::debug!(
1221            "Variable '{}' could not be tracked (no pointer generated)",
1222            var_name
1223        );
1224    }
1225    Ok(())
1226}
1227
1228impl MemoryTracker {
1229    /// Export tracking data with complex type optimization (separate files for better performance)
1230    pub fn export_to_json_optimized<P: AsRef<std::path::Path>>(
1231        &self,
1232        path: P,
1233    ) -> TrackingResult<crate::export::complex_type_export::ComplexTypeExportResult> {
1234        use crate::export::complex_type_export::{
1235            export_comprehensive_analysis_optimized, ComplexTypeExportConfig,
1236        };
1237
1238        let path = path.as_ref();
1239        println!("🚀 Using optimized complex type export for maximum performance...");
1240
1241        let start_time = std::time::Instant::now();
1242
1243        // Get all necessary data
1244        let allocations = self.get_active_allocations()?;
1245        let stats = self.get_stats()?;
1246
1247        // Perform comprehensive analysis
1248        let analysis_manager = crate::analysis::AnalysisManager::new();
1249        let comprehensive_report =
1250            analysis_manager.perform_comprehensive_analysis(&allocations, &stats);
1251
1252        // Use optimized export configuration
1253        let config = ComplexTypeExportConfig {
1254            separate_complex_types: true,
1255            compress_data: false,
1256            chunk_size: 1000,
1257            pretty_format: false, // Disable for performance
1258        };
1259
1260        // Export with complex type separation
1261        let export_result = export_comprehensive_analysis_optimized(
1262            &comprehensive_report,
1263            &allocations,
1264            path,
1265            &config,
1266        )?;
1267
1268        let export_time = start_time.elapsed();
1269
1270        // Performance reporting
1271        println!(
1272            "✅ Optimized export completed in {:.2}ms",
1273            export_time.as_millis()
1274        );
1275        println!(
1276            "📊 Performance improvement: {:.1}%",
1277            export_result.export_stats.performance_improvement
1278        );
1279        println!(
1280            "📁 Main file: {} ({} bytes)",
1281            export_result.main_file, export_result.export_stats.main_file_size
1282        );
1283
1284        if export_result.export_stats.complex_files_size > 0 {
1285            println!(
1286                "📁 Complex type files: {} bytes total",
1287                export_result.export_stats.complex_files_size
1288            );
1289
1290            if let Some(ref file) = export_result.complex_types_file {
1291                println!("   - Complex types: {}", file);
1292            }
1293            if let Some(ref file) = export_result.borrow_analysis_file {
1294                println!("   - Borrow analysis: {}", file);
1295            }
1296            if let Some(ref file) = export_result.async_analysis_file {
1297                println!("   - Async analysis: {}", file);
1298            }
1299            if let Some(ref file) = export_result.closure_analysis_file {
1300                println!("   - Closure analysis: {}", file);
1301            }
1302            if let Some(ref file) = export_result.lifecycle_analysis_file {
1303                println!("   - Lifecycle analysis: {}", file);
1304            }
1305        }
1306
1307        Ok(export_result)
1308    }
1309}
1310
1311/// Internal implementation for smart tracking that chooses optimal strategy.
1312/// This function should not be called directly.
1313#[doc(hidden)]
1314pub fn _smart_track_var_impl<T: Trackable + 'static>(var: T, var_name: &str) -> TrackingResult<T> {
1315    use std::any::TypeId;
1316
1317    let type_id = TypeId::of::<T>();
1318    let type_name = std::any::type_name::<T>();
1319
1320    // Check if it's a Copy type by attempting to get TypeId of common Copy types
1321    let is_copy_type = type_id == TypeId::of::<i8>()
1322        || type_id == TypeId::of::<i16>()
1323        || type_id == TypeId::of::<i32>()
1324        || type_id == TypeId::of::<i64>()
1325        || type_id == TypeId::of::<i128>()
1326        || type_id == TypeId::of::<isize>()
1327        || type_id == TypeId::of::<u8>()
1328        || type_id == TypeId::of::<u16>()
1329        || type_id == TypeId::of::<u32>()
1330        || type_id == TypeId::of::<u64>()
1331        || type_id == TypeId::of::<u128>()
1332        || type_id == TypeId::of::<usize>()
1333        || type_id == TypeId::of::<f32>()
1334        || type_id == TypeId::of::<f64>()
1335        || type_id == TypeId::of::<bool>()
1336        || type_id == TypeId::of::<char>();
1337
1338    let is_smart_pointer = type_name.contains("::Rc<")
1339        || type_name.contains("::Arc<")
1340        || type_name.contains("::Weak<");
1341
1342    if is_copy_type {
1343        // For Copy types, we can safely track by reference and return the value
1344        let _ = _track_var_impl(&var, var_name);
1345        tracing::debug!(
1346            "🧠 Smart tracking: Copy type '{}' tracked by reference",
1347            var_name
1348        );
1349        Ok(var)
1350    } else if is_smart_pointer {
1351        // For smart pointers, track by reference and return the value
1352        let _ = _track_var_impl(&var, var_name);
1353        tracing::debug!(
1354            "🧠 Smart tracking: Smart pointer '{}' tracked by reference",
1355            var_name
1356        );
1357        Ok(var)
1358    } else {
1359        // For other types, track by reference and return the value
1360        let _ = _track_var_impl(&var, var_name);
1361        tracing::debug!(
1362            "🧠 Smart tracking: Non-Copy type '{}' tracked by reference",
1363            var_name
1364        );
1365        Ok(var)
1366    }
1367}
1368
1369/// Initialize the memory tracking system.
1370///
1371/// This function sets up the tracing subscriber and prepares the global tracker.
1372/// Call this early in your application, typically in main().
1373///
1374/// # Example
1375/// ```rust
1376/// memscope_rs::init();
1377/// // Your application code here
1378/// ```
1379pub fn init() {
1380    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
1381
1382    // Check if we're in test mode to reduce log noise
1383    let default_level = if cfg!(test) || std::env::var("MEMSCOPE_TEST_MODE").is_ok() {
1384        "memscope_rs=error" // Only show errors during tests
1385    } else {
1386        "memscope_rs=info" // Normal info level for regular use
1387    };
1388
1389    tracing_subscriber::registry()
1390        .with(
1391            tracing_subscriber::EnvFilter::try_from_default_env()
1392                .unwrap_or_else(|_| default_level.into()),
1393        )
1394        .with(tracing_subscriber::fmt::layer())
1395        .init();
1396
1397    tracing::info!("memscope-rs initialized");
1398}
1399
1400/// Initialize memscope-rs with optimized settings for testing
1401/// This reduces logging and disables expensive features for faster test execution
1402pub fn init_for_testing() {
1403    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
1404
1405    // Set test mode environment variables
1406    std::env::set_var("MEMSCOPE_TEST_MODE", "1");
1407
1408    // Initialize with minimal logging
1409    tracing_subscriber::registry()
1410        .with(
1411            tracing_subscriber::EnvFilter::try_from_default_env()
1412                .unwrap_or_else(|_| "memscope_rs=error".into()),
1413        )
1414        .with(tracing_subscriber::fmt::layer())
1415        .init();
1416
1417    tracing::debug!("memscope-rs initialized for testing");
1418}
1419
1420/// Testing utilities and helpers
1421pub mod test_utils {
1422    /// Initialize memscope-rs for testing with minimal overhead
1423    pub fn init_test() {
1424        std::env::set_var("MEMSCOPE_TEST_MODE", "1");
1425        std::env::set_var("RUST_LOG", "error");
1426
1427        // Only initialize once
1428        static INIT: std::sync::Once = std::sync::Once::new();
1429        INIT.call_once(|| {
1430            super::init_for_testing();
1431        });
1432
1433        // Enable fast mode on the global tracker
1434        let tracker = super::get_global_tracker();
1435        tracker.enable_fast_mode();
1436    }
1437
1438    /// Reset global tracker state for clean tests
1439    pub fn reset_tracker() {
1440        // This is a placeholder - in practice, we might need to implement
1441        // a way to reset the global tracker state between tests
1442    }
1443}
1444
1445/// Macro for quick test initialization
1446#[macro_export]
1447macro_rules! init_test {
1448    () => {
1449        $crate::test_utils::init_test();
1450    };
1451}
1452
1453/// Enable automatic JSON export when program ends
1454/// Call this at the beginning of your program to enable auto-export
1455pub fn enable_auto_export(export_path: Option<&str>) {
1456    std::env::set_var("MEMSCOPE_AUTO_EXPORT", "1");
1457    if let Some(path) = export_path {
1458        std::env::set_var("MEMSCOPE_EXPORT_PATH", path);
1459    }
1460
1461    // Install exit hook for automatic export
1462    install_exit_hook();
1463
1464    println!(
1465        "📋 Auto-export enabled - JSON will be exported to: {}",
1466        export_path.unwrap_or("memscope_final_snapshot.json")
1467    );
1468}
1469
1470/// Install program exit hook for automatic data export
1471fn install_exit_hook() {
1472    use std::sync::Once;
1473    static HOOK_INSTALLED: Once = Once::new();
1474
1475    HOOK_INSTALLED.call_once(|| {
1476        // Install panic hook
1477        let original_hook = std::panic::take_hook();
1478        std::panic::set_hook(Box::new(move |panic_info| {
1479            eprintln!("🚨 Program panicked, attempting to export memory data...");
1480            let _ = export_final_snapshot("memscope_panic_snapshot");
1481            original_hook(panic_info);
1482        }));
1483
1484        // Use libc atexit for reliable program exit handling
1485        extern "C" fn exit_handler() {
1486            if std::env::var("MEMSCOPE_AUTO_EXPORT").is_ok() {
1487                println!("🔄 Program ending, exporting final memory snapshot...");
1488                let export_path = std::env::var("MEMSCOPE_EXPORT_PATH")
1489                    .unwrap_or_else(|_| "memscope_final_snapshot".to_string());
1490
1491                if let Err(e) = export_final_snapshot(&export_path) {
1492                    eprintln!("❌ Failed to export final snapshot: {}", e);
1493                } else {
1494                    println!("✅ Final memory snapshot exported successfully");
1495                }
1496            }
1497        }
1498
1499        unsafe {
1500            libc::atexit(exit_handler);
1501        }
1502
1503        tracing::debug!("📌 Exit hooks installed for automatic memory export");
1504    });
1505}
1506
1507/// Export final memory snapshot with complete lifecycle data
1508fn export_final_snapshot(base_path: &str) -> TrackingResult<()> {
1509    let tracker = get_global_tracker();
1510
1511    // Force a final garbage collection attempt to capture any remaining deallocations
1512    std::thread::sleep(std::time::Duration::from_millis(10));
1513
1514    let json_path = format!("{}.json", base_path);
1515    tracker.export_to_json(&json_path)?;
1516
1517    // Also export HTML if requested
1518    let export_format =
1519        std::env::var("MEMSCOPE_EXPORT_FORMAT").unwrap_or_else(|_| "json".to_string());
1520    if export_format == "html" || export_format == "both" {
1521        let html_path = format!("{}.html", base_path);
1522        let _ = tracker.export_interactive_dashboard(&html_path);
1523    }
1524
1525    Ok(())
1526}