1#![allow(missing_docs)]
9#![allow(clippy::manual_is_multiple_of)] pub mod advanced_trackable_macro;
13pub mod advanced_types;
15pub mod analysis;
17pub mod async_memory;
18pub mod classification;
20pub mod cli;
22pub mod core;
24
25pub use crate::core::performance_optimizer::{
27 OptimizationRecommendations, PerformanceMetrics, PerformanceOptimizer,
28};
29pub use crate::core::ultra_fast_tracker::{
30 SamplingStats, UltraFastSamplingConfig, UltraFastTracker,
31};
32pub mod error;
34pub mod estimation;
36pub mod export;
38pub mod lockfree;
40pub mod memory;
42pub mod metrics;
44pub mod platform;
46pub mod quality;
48pub mod smart_pointers;
50pub mod stack_trace;
52pub mod tracking;
54pub mod unified;
56pub mod utils;
58pub mod variable_registry;
60
61pub mod enhanced_types;
64pub use advanced_types::*;
65pub use analysis::*;
66
67pub use export::{
72 export_user_variables_binary, export_user_variables_json, };
75
76pub use export::{
78 export_lifecycle_data, LifecycleExportConfig, LifecycleExporter, };
82
83pub use export::{
85 binary::detect_binary_type, binary::BinaryParser, };
88
89pub use analysis::enhanced_memory_analysis::EnhancedMemoryAnalyzer;
91pub use analysis::unsafe_ffi_tracker::{get_global_unsafe_ffi_tracker, UnsafeFFITracker};
92pub use core::allocator::TrackingAllocator;
93pub use core::tracker::memory_tracker::BinaryExportMode;
94pub use core::tracker::{get_tracker, ExportOptions, MemoryTracker};
95pub use core::types::{AllocationInfo, TrackingError, TrackingResult};
96pub use utils::{format_bytes, get_simple_type, simplify_type_name};
97
98#[cfg(feature = "derive")]
100pub use memscope_derive::Trackable;
101
102#[cfg(feature = "tracking-allocator")]
106#[global_allocator]
107pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
108
109pub trait Trackable {
111 fn get_heap_ptr(&self) -> Option<usize>;
113
114 fn get_type_name(&self) -> &'static str;
116
117 fn get_size_estimate(&self) -> usize;
119
120 fn get_ref_count(&self) -> usize {
122 1
123 }
124
125 fn get_data_ptr(&self) -> usize {
127 self.get_heap_ptr().unwrap_or(0)
128 }
129
130 fn get_internal_allocations(&self, _var_name: &str) -> Vec<(usize, String)> {
132 Vec::new()
133 }
134
135 fn track_clone_relationship(&self, _clone_ptr: usize, _source_ptr: usize) {
137 }
139
140 fn update_ref_count_tracking(&self, _ptr: usize) {
142 }
144
145 fn get_advanced_type_info(&self) -> Option<crate::advanced_types::AdvancedTypeInfo> {
147 let type_name = self.get_type_name();
149 if crate::advanced_types::is_advanced_type(type_name) {
150 let allocation = crate::core::types::AllocationInfo {
152 ptr: self.get_heap_ptr().unwrap_or(0),
153 size: self.get_size_estimate(),
154 var_name: None,
155 type_name: Some(type_name.to_string()),
156 scope_name: None,
157 timestamp_alloc: std::time::SystemTime::now()
158 .duration_since(std::time::UNIX_EPOCH)
159 .unwrap_or_default()
160 .as_nanos() as u64,
161 timestamp_dealloc: None,
162 thread_id: format!("{:?}", std::thread::current().id()),
163 borrow_count: 0,
164 stack_trace: None,
165 is_leaked: false,
166 lifetime_ms: None,
167 borrow_info: None,
168 clone_info: None,
169 ownership_history_available: false,
170 smart_pointer_info: None,
171 memory_layout: None,
172 generic_info: None,
173 dynamic_type_info: None,
174 runtime_state: None,
175 stack_allocation: None,
176 temporary_object: None,
177 fragmentation_analysis: None,
178 generic_instantiation: None,
179 type_relationships: None,
180 type_usage: None,
181 function_call_tracking: None,
182 lifecycle_tracking: None,
183 access_tracking: None,
184 drop_chain_analysis: None,
185 };
186
187 Some(
188 crate::advanced_types::GenericAdvancedTypeAnalyzer::analyze_by_type_name(
189 type_name,
190 &allocation,
191 ),
192 )
193 } else {
194 None
195 }
196 }
197}
198
199impl<T> Trackable for Vec<T> {
201 fn get_heap_ptr(&self) -> Option<usize> {
202 if self.capacity() > 0 {
203 Some(self.as_ptr() as usize)
204 } else {
205 None
206 }
207 }
208
209 fn get_type_name(&self) -> &'static str {
210 std::any::type_name::<Vec<T>>()
211 }
212
213 fn get_size_estimate(&self) -> usize {
214 self.capacity() * std::mem::size_of::<T>()
215 }
216}
217
218impl Trackable for String {
219 fn get_heap_ptr(&self) -> Option<usize> {
220 if self.capacity() > 0 {
221 Some(self.as_ptr() as usize)
222 } else {
223 None
224 }
225 }
226
227 fn get_type_name(&self) -> &'static str {
228 "String"
229 }
230
231 fn get_size_estimate(&self) -> usize {
232 self.capacity()
233 }
234}
235
236impl<T> Trackable for Box<T> {
237 fn get_heap_ptr(&self) -> Option<usize> {
238 Some(self.as_ref() as *const T as usize)
239 }
240
241 fn get_type_name(&self) -> &'static str {
242 std::any::type_name::<Box<T>>()
243 }
244
245 fn get_size_estimate(&self) -> usize {
246 std::mem::size_of::<T>()
247 }
248}
249
250impl<T> Trackable for std::rc::Rc<T> {
251 fn get_heap_ptr(&self) -> Option<usize> {
252 let instance_ptr = self as *const _ as usize;
255
256 Some(0x5000_0000 + (instance_ptr % 0x0FFF_FFFF))
259 }
260
261 fn get_type_name(&self) -> &'static str {
262 std::any::type_name::<std::rc::Rc<T>>()
263 }
264
265 fn get_size_estimate(&self) -> usize {
266 std::mem::size_of::<T>() + std::mem::size_of::<usize>() * 2 }
268
269 fn get_ref_count(&self) -> usize {
271 std::rc::Rc::strong_count(self)
272 }
273
274 fn get_data_ptr(&self) -> usize {
276 std::rc::Rc::as_ptr(self) as usize
277 }
278
279 fn track_clone_relationship(&self, clone_ptr: usize, source_ptr: usize) {
280 let tracker = crate::core::tracker::get_tracker();
281 let _data_ptr = self.get_data_ptr();
282 let _strong_count = std::rc::Rc::strong_count(self);
283 let weak_count = std::rc::Rc::weak_count(self);
284
285 if let Err(e) = tracker.track_smart_pointer_clone(
286 clone_ptr, source_ptr, clone_ptr, 1, weak_count,
289 ) {
290 tracing::warn!("Failed to track Rc clone relationship: {}", e);
291 }
292 }
293
294 fn update_ref_count_tracking(&self, ptr: usize) {
295 let tracker = crate::core::tracker::get_tracker();
296 let strong_count = std::rc::Rc::strong_count(self);
297 let weak_count = std::rc::Rc::weak_count(self);
298
299 if let Err(e) = tracker.update_smart_pointer_ref_count(ptr, strong_count, weak_count) {
300 tracing::warn!("Failed to update Rc ref count: {}", e);
301 }
302 }
303}
304
305impl<T> Trackable for std::sync::Arc<T> {
306 fn get_heap_ptr(&self) -> Option<usize> {
307 let instance_ptr = self as *const _ as usize;
310
311 Some(0x6000_0000 + (instance_ptr % 0x0FFF_FFFF))
314 }
315
316 fn get_type_name(&self) -> &'static str {
317 std::any::type_name::<std::sync::Arc<T>>()
318 }
319
320 fn get_size_estimate(&self) -> usize {
321 std::mem::size_of::<T>() + std::mem::size_of::<std::sync::atomic::AtomicUsize>() * 2
322 }
324
325 fn get_ref_count(&self) -> usize {
327 std::sync::Arc::strong_count(self)
328 }
329
330 fn get_data_ptr(&self) -> usize {
332 std::sync::Arc::as_ptr(self) as usize
333 }
334
335 fn track_clone_relationship(&self, clone_ptr: usize, source_ptr: usize) {
336 let tracker = crate::core::tracker::get_tracker();
337 let data_ptr = self.get_data_ptr();
338 let strong_count = std::sync::Arc::strong_count(self);
339 let weak_count = std::sync::Arc::weak_count(self);
340
341 if let Err(e) = tracker.track_smart_pointer_clone(
342 clone_ptr,
343 source_ptr,
344 data_ptr,
345 strong_count,
346 weak_count,
347 ) {
348 tracing::warn!("Failed to track Arc clone relationship: {}", e);
349 }
350 }
351
352 fn update_ref_count_tracking(&self, ptr: usize) {
353 let tracker = crate::core::tracker::get_tracker();
354 let strong_count = std::sync::Arc::strong_count(self);
355 let weak_count = std::sync::Arc::weak_count(self);
356
357 if let Err(e) = tracker.update_smart_pointer_ref_count(ptr, strong_count, weak_count) {
358 tracing::warn!("Failed to update Arc ref count: {}", e);
359 }
360 }
361}
362
363impl<K, V, S> Trackable for std::collections::HashMap<K, V, S> {
364 fn get_heap_ptr(&self) -> Option<usize> {
365 Some(self as *const _ as usize)
368 }
369
370 fn get_type_name(&self) -> &'static str {
371 std::any::type_name::<std::collections::HashMap<K, V, S>>()
372 }
373
374 fn get_size_estimate(&self) -> usize {
375 self.capacity() * (std::mem::size_of::<K>() + std::mem::size_of::<V>() + 16)
377 }
378}
379
380impl<K, V> Trackable for std::collections::BTreeMap<K, V> {
381 fn get_heap_ptr(&self) -> Option<usize> {
382 if self.is_empty() {
383 None
384 } else {
385 Some(self as *const _ as usize)
386 }
387 }
388
389 fn get_type_name(&self) -> &'static str {
390 std::any::type_name::<std::collections::BTreeMap<K, V>>()
391 }
392
393 fn get_size_estimate(&self) -> usize {
394 self.len() * (std::mem::size_of::<K>() + std::mem::size_of::<V>() + 32)
396 }
397}
398
399impl<T> Trackable for std::collections::HashSet<T> {
400 fn get_heap_ptr(&self) -> Option<usize> {
401 if self.is_empty() {
402 None
403 } else {
404 Some(self as *const _ as usize)
405 }
406 }
407
408 fn get_type_name(&self) -> &'static str {
409 std::any::type_name::<std::collections::HashSet<T>>()
410 }
411
412 fn get_size_estimate(&self) -> usize {
413 self.capacity() * (std::mem::size_of::<T>() + 8) }
415}
416
417impl<T> Trackable for std::collections::BTreeSet<T> {
418 fn get_heap_ptr(&self) -> Option<usize> {
419 if self.is_empty() {
420 None
421 } else {
422 Some(self as *const _ as usize)
423 }
424 }
425
426 fn get_type_name(&self) -> &'static str {
427 std::any::type_name::<std::collections::BTreeSet<T>>()
428 }
429
430 fn get_size_estimate(&self) -> usize {
431 self.len() * (std::mem::size_of::<T>() + 24) }
433}
434
435impl<T> Trackable for std::collections::VecDeque<T> {
436 fn get_heap_ptr(&self) -> Option<usize> {
437 if self.capacity() > 0 {
438 Some(self.as_slices().0.as_ptr() as usize)
439 } else {
440 None
441 }
442 }
443
444 fn get_type_name(&self) -> &'static str {
445 std::any::type_name::<std::collections::VecDeque<T>>()
446 }
447
448 fn get_size_estimate(&self) -> usize {
449 self.capacity() * std::mem::size_of::<T>()
450 }
451}
452
453impl<T> Trackable for std::collections::LinkedList<T> {
454 fn get_heap_ptr(&self) -> Option<usize> {
455 if self.is_empty() {
456 None
457 } else {
458 Some(self as *const _ as usize)
459 }
460 }
461
462 fn get_type_name(&self) -> &'static str {
463 std::any::type_name::<std::collections::LinkedList<T>>()
464 }
465
466 fn get_size_estimate(&self) -> usize {
467 self.len() * (std::mem::size_of::<T>() + std::mem::size_of::<usize>() * 2)
468 }
470}
471
472impl<T> Trackable for std::collections::BinaryHeap<T> {
473 fn get_heap_ptr(&self) -> Option<usize> {
474 if self.capacity() > 0 {
475 Some(self as *const _ as usize)
476 } else {
477 None
478 }
479 }
480
481 fn get_type_name(&self) -> &'static str {
482 std::any::type_name::<std::collections::BinaryHeap<T>>()
483 }
484
485 fn get_size_estimate(&self) -> usize {
486 self.capacity() * std::mem::size_of::<T>()
487 }
488}
489
490impl<T> Trackable for std::rc::Weak<T> {
491 fn get_heap_ptr(&self) -> Option<usize> {
492 let instance_ptr = self as *const _ as usize;
494 Some(0x7000_0000 + (instance_ptr % 0x0FFF_FFFF))
495 }
496
497 fn get_type_name(&self) -> &'static str {
498 std::any::type_name::<std::rc::Weak<T>>()
499 }
500
501 fn get_size_estimate(&self) -> usize {
502 std::mem::size_of::<std::rc::Weak<T>>()
503 }
504
505 fn get_ref_count(&self) -> usize {
506 self.weak_count()
507 }
508
509 fn get_data_ptr(&self) -> usize {
510 if let Some(upgraded) = self.upgrade() {
512 std::rc::Rc::as_ptr(&upgraded) as usize
513 } else {
514 0 }
516 }
517}
518
519impl<T> Trackable for std::sync::Weak<T> {
520 fn get_heap_ptr(&self) -> Option<usize> {
521 let instance_ptr = self as *const _ as usize;
523 Some(0x8000_0000 + (instance_ptr % 0x0FFF_FFFF))
524 }
525
526 fn get_type_name(&self) -> &'static str {
527 std::any::type_name::<std::sync::Weak<T>>()
528 }
529
530 fn get_size_estimate(&self) -> usize {
531 std::mem::size_of::<std::sync::Weak<T>>()
532 }
533
534 fn get_ref_count(&self) -> usize {
535 self.weak_count()
536 }
537
538 fn get_data_ptr(&self) -> usize {
539 if let Some(upgraded) = self.upgrade() {
541 std::sync::Arc::as_ptr(&upgraded) as usize
542 } else {
543 0 }
545 }
546}
547
548impl_advanced_trackable!(std::cell::RefCell<T>, 0xA000_0000);
550impl_advanced_trackable!(std::sync::Mutex<T>, 0xB000_0000);
551impl_advanced_trackable!(std::sync::RwLock<T>, 0xC000_0000);
552
553impl_advanced_trackable!(std::cell::Cell<T>, 0xA100_0000);
555impl_advanced_trackable!(std::sync::mpsc::Sender<T>, 0xD000_0000);
556impl_advanced_trackable!(std::sync::mpsc::Receiver<T>, 0xD100_0000);
557impl_advanced_trackable!(std::sync::atomic::AtomicBool, 0xE000_0000, no_generics);
558impl_advanced_trackable!(std::sync::atomic::AtomicUsize, 0xE100_0000, no_generics);
559impl_advanced_trackable!(std::sync::atomic::AtomicIsize, 0xE200_0000, no_generics);
560impl_advanced_trackable!(std::sync::atomic::AtomicU8, 0xE300_0000, no_generics);
561impl_advanced_trackable!(std::sync::atomic::AtomicU16, 0xE400_0000, no_generics);
562impl_advanced_trackable!(std::sync::atomic::AtomicU32, 0xE500_0000, no_generics);
563impl_advanced_trackable!(std::sync::atomic::AtomicU64, 0xE600_0000, no_generics);
564impl_advanced_trackable!(std::sync::atomic::AtomicI8, 0xE700_0000, no_generics);
565impl_advanced_trackable!(std::sync::atomic::AtomicI16, 0xE800_0000, no_generics);
566impl_advanced_trackable!(std::sync::atomic::AtomicI32, 0xE900_0000, no_generics);
567impl_advanced_trackable!(std::sync::atomic::AtomicI64, 0xEA00_0000, no_generics);
568impl_advanced_trackable!(std::mem::ManuallyDrop<T>, 0xF000_0000);
569impl_advanced_trackable!(std::mem::MaybeUninit<T>, 0xF100_0000);
570impl_advanced_trackable!(std::pin::Pin<T>, 0xF200_0000);
571
572impl_advanced_trackable!(std::ffi::CString, 0xF300_0000, no_generics);
574impl_advanced_trackable!(std::hash::RandomState, 0xF400_0000, no_generics);
575
576macro_rules! impl_primitive_trackable {
578 ($type:ty, $base_ptr:expr) => {
579 impl Trackable for $type {
580 fn get_heap_ptr(&self) -> Option<usize> {
581 Some($base_ptr + (self as *const _ as usize % 0x0FFF_FFFF))
583 }
584
585 fn get_type_name(&self) -> &'static str {
586 std::any::type_name::<$type>()
587 }
588
589 fn get_size_estimate(&self) -> usize {
590 std::mem::size_of::<$type>()
591 }
592 }
593 };
594}
595
596impl_primitive_trackable!(i8, 0x1000_0000);
598impl_primitive_trackable!(i16, 0x1100_0000);
599impl_primitive_trackable!(i32, 0x1200_0000);
600impl_primitive_trackable!(i64, 0x1300_0000);
601impl_primitive_trackable!(i128, 0x1400_0000);
602impl_primitive_trackable!(isize, 0x1500_0000);
603impl_primitive_trackable!(u8, 0x1600_0000);
604impl_primitive_trackable!(u16, 0x1700_0000);
605impl_primitive_trackable!(u32, 0x1800_0000);
606impl_primitive_trackable!(u64, 0x1900_0000);
607impl_primitive_trackable!(u128, 0x1A00_0000);
608impl_primitive_trackable!(usize, 0x1B00_0000);
609impl_primitive_trackable!(f32, 0x1C00_0000);
610impl_primitive_trackable!(f64, 0x1D00_0000);
611impl_primitive_trackable!(bool, 0x1E00_0000);
612impl_primitive_trackable!(char, 0x1F00_0000);
613
614impl<T1: Trackable, T2: Trackable, T3: Trackable> Trackable for (T1, T2, T3) {
616 fn get_heap_ptr(&self) -> Option<usize> {
617 if let Some(ptr1) = self.0.get_heap_ptr() {
619 Some(0xF500_0000 + (ptr1 % 0x0FFF_FFFF))
620 } else if let Some(ptr2) = self.1.get_heap_ptr() {
621 Some(0xF500_0000 + (ptr2 % 0x0FFF_FFFF))
622 } else if let Some(ptr3) = self.2.get_heap_ptr() {
623 Some(0xF500_0000 + (ptr3 % 0x0FFF_FFFF))
624 } else {
625 Some(0xF500_0000 + (self as *const _ as usize % 0x0FFF_FFFF))
627 }
628 }
629
630 fn get_type_name(&self) -> &'static str {
631 std::any::type_name::<(T1, T2, T3)>()
632 }
633
634 fn get_size_estimate(&self) -> usize {
635 self.0.get_size_estimate() + self.1.get_size_estimate() + self.2.get_size_estimate()
636 }
637}
638
639impl<T: Trackable> Trackable for Option<T> {
641 fn get_heap_ptr(&self) -> Option<usize> {
642 match self {
643 Some(value) => value.get_heap_ptr(),
644 None => None,
645 }
646 }
647
648 fn get_type_name(&self) -> &'static str {
649 std::any::type_name::<Option<T>>()
650 }
651
652 fn get_size_estimate(&self) -> usize {
653 match self {
654 Some(value) => std::mem::size_of::<Option<T>>() + value.get_size_estimate(),
655 None => std::mem::size_of::<Option<T>>(),
656 }
657 }
658
659 fn get_internal_allocations(&self, var_name: &str) -> Vec<(usize, String)> {
660 match self {
661 Some(value) => value.get_internal_allocations(&format!("{var_name}::Some")),
662 None => Vec::new(),
663 }
664 }
665}
666
667impl<T: Trackable, E: Trackable> Trackable for Result<T, E> {
669 fn get_heap_ptr(&self) -> Option<usize> {
670 match self {
671 Ok(value) => value.get_heap_ptr(),
672 Err(error) => error.get_heap_ptr(),
673 }
674 }
675
676 fn get_type_name(&self) -> &'static str {
677 std::any::type_name::<Result<T, E>>()
678 }
679
680 fn get_size_estimate(&self) -> usize {
681 match self {
682 Ok(value) => std::mem::size_of::<Result<T, E>>() + value.get_size_estimate(),
683 Err(error) => std::mem::size_of::<Result<T, E>>() + error.get_size_estimate(),
684 }
685 }
686
687 fn get_internal_allocations(&self, var_name: &str) -> Vec<(usize, String)> {
688 match self {
689 Ok(value) => value.get_internal_allocations(&format!("{var_name}::Ok")),
690 Err(error) => error.get_internal_allocations(&format!("{var_name}::Err")),
691 }
692 }
693}
694
695#[macro_export]
719macro_rules! track_var {
720 ($var:expr) => {{
721 let var_name = stringify!($var);
722 let _ = $crate::_track_var_impl(&$var, var_name);
723 }};
725}
726
727#[macro_export]
768macro_rules! track_var_owned {
769 ($var:expr) => {{
770 let var_name = stringify!($var);
771 $crate::TrackedVariable::new($var, var_name.to_string())
772 }};
773}
774
775#[macro_export]
809macro_rules! track_var_smart {
810 ($var:expr) => {{
811 let var_name = stringify!($var);
812 $crate::_smart_track_var_impl($var, var_name)
813 }};
814}
815
816static TRACKED_VARIABLE_COUNTER: std::sync::atomic::AtomicUsize =
818 std::sync::atomic::AtomicUsize::new(1);
819
820pub mod smart_pointer_utils {
826 #[derive(Debug, Clone, PartialEq)]
828 pub enum SmartPointerType {
829 Rc,
831 Arc,
833 Box,
835 None,
837 }
838
839 pub fn detect_smart_pointer_type(type_name: &str) -> SmartPointerType {
841 if type_name.contains("::Rc<") || type_name.contains("std::rc::Rc<") {
842 SmartPointerType::Rc
843 } else if type_name.contains("::Arc<") || type_name.contains("std::sync::Arc<") {
844 SmartPointerType::Arc
845 } else if type_name.contains("::Box<") || type_name.contains("std::boxed::Box<") {
846 SmartPointerType::Box
847 } else {
848 SmartPointerType::None
849 }
850 }
851
852 pub fn is_smart_pointer(type_name: &str) -> bool {
854 detect_smart_pointer_type(type_name) != SmartPointerType::None
855 }
856
857 pub fn generate_synthetic_pointer(
859 smart_pointer_type: SmartPointerType,
860 unique_id: usize,
861 ) -> usize {
862 match smart_pointer_type {
863 SmartPointerType::Rc => 0x5000_0000 + unique_id,
864 SmartPointerType::Arc => 0x6000_0000 + unique_id,
865 SmartPointerType::Box => 0x7000_0000 + unique_id,
866 SmartPointerType::None => unique_id, }
868 }
869}
870
871pub struct TrackedVariable<T: Trackable> {
888 inner: T,
889 var_name: String,
890 ptr: Option<usize>,
891 creation_time: u64,
892 unique_id: usize, destruction_tracked: std::sync::atomic::AtomicBool, }
895
896impl<T: Trackable> TrackedVariable<T> {
897 pub fn new(value: T, var_name: String) -> Self {
899 let creation_time = std::time::SystemTime::now()
900 .duration_since(std::time::UNIX_EPOCH)
901 .unwrap_or_default()
902 .as_nanos() as u64;
903
904 let unique_id = TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
905 let type_name = value.get_type_name().to_string();
906 let smart_pointer_type = smart_pointer_utils::detect_smart_pointer_type(&type_name);
907 let is_smart_pointer = smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
908
909 let ptr = if is_smart_pointer {
912 Some(smart_pointer_utils::generate_synthetic_pointer(
913 smart_pointer_type,
914 unique_id,
915 ))
916 } else {
917 value.get_heap_ptr().or_else(|| {
919 Some(0x8000_0000 + unique_id)
921 })
922 };
923
924 if let Some(ptr_val) = ptr {
926 let tracker = crate::core::tracker::get_tracker();
927
928 let _ = crate::variable_registry::VariableRegistry::register_variable(
930 ptr_val,
931 var_name.clone(),
932 type_name.clone(),
933 value.get_size_estimate(),
934 );
935
936 let scope_tracker = crate::core::scope_tracker::get_global_scope_tracker();
938 let _ = scope_tracker.associate_variable(var_name.clone(), value.get_size_estimate());
939
940 if is_smart_pointer {
942 let ref_count = value.get_ref_count();
944 let data_ptr = value.get_data_ptr();
945
946 let _ = tracker.create_smart_pointer_allocation(
947 ptr_val,
948 value.get_size_estimate(),
949 var_name.clone(),
950 type_name.clone(),
951 creation_time,
952 ref_count,
953 data_ptr,
954 );
955
956 tracing::debug!(
957 "🎯 Created smart pointer tracking for '{}' at ptr 0x{:x}, ref_count={}",
958 var_name,
959 ptr_val,
960 ref_count
961 );
962 } else if ptr_val >= 0x8000_0000 {
963 let _ = tracker.create_synthetic_allocation(
965 ptr_val,
966 value.get_size_estimate(),
967 var_name.clone(),
968 type_name.clone(),
969 creation_time,
970 );
971
972 tracing::debug!(
973 "🎯 Created synthetic tracking for '{}' at ptr 0x{:x}",
974 var_name,
975 ptr_val
976 );
977 } else {
978 let _ = tracker.associate_var(ptr_val, var_name.clone(), type_name.clone());
980
981 tracing::debug!(
982 "🎯 Associated variable '{}' of type '{}' at ptr 0x{:x}",
983 var_name,
984 type_name,
985 ptr_val
986 );
987 }
988 }
989
990 Self {
991 inner: value,
992 var_name,
993 ptr,
994 creation_time,
995 unique_id,
996 destruction_tracked: std::sync::atomic::AtomicBool::new(false),
997 }
998 }
999
1000 pub fn get(&self) -> &T {
1002 &self.inner
1003 }
1004
1005 pub fn get_mut(&mut self) -> &mut T {
1007 &mut self.inner
1008 }
1009
1010 pub fn into_inner(self) -> T {
1023 let mut manual_drop_self = std::mem::ManuallyDrop::new(self);
1025
1026 if let Some(ptr_val) = manual_drop_self.ptr.take() {
1028 if !manual_drop_self
1030 .destruction_tracked
1031 .swap(true, std::sync::atomic::Ordering::Relaxed)
1032 {
1033 let type_name = manual_drop_self.inner.get_type_name();
1034 let smart_pointer_type = smart_pointer_utils::detect_smart_pointer_type(type_name);
1035 let is_smart_pointer =
1036 smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
1037
1038 if is_smart_pointer {
1039 let final_ref_count = manual_drop_self.inner.get_ref_count();
1040 if let Err(e) = Self::track_smart_pointer_destruction(
1041 &manual_drop_self.var_name,
1042 ptr_val,
1043 manual_drop_self.creation_time,
1044 final_ref_count,
1045 ) {
1046 tracing::warn!(
1047 "Failed to track smart pointer destruction in into_inner(): {}",
1048 e
1049 );
1050 }
1051 } else if let Err(e) = Self::track_destruction(
1052 &manual_drop_self.var_name,
1053 ptr_val,
1054 manual_drop_self.creation_time,
1055 ) {
1056 tracing::warn!("Failed to track destruction in into_inner(): {}", e);
1057 }
1058 }
1059 }
1060
1061 unsafe { std::ptr::read(&manual_drop_self.inner) }
1064 }
1065
1066 fn track_destruction(var_name: &str, ptr: usize, creation_time: u64) -> TrackingResult<()> {
1068 let destruction_time = std::time::SystemTime::now()
1069 .duration_since(std::time::UNIX_EPOCH)
1070 .unwrap_or_default()
1071 .as_nanos() as u64;
1072
1073 let lifetime_ms = (destruction_time.saturating_sub(creation_time)) / 1_000_000;
1074
1075 if let Err(e) = crate::variable_registry::VariableRegistry::mark_variable_destroyed(
1077 ptr,
1078 destruction_time,
1079 ) {
1080 tracing::warn!("Failed to mark variable destroyed in registry: {}", e);
1081 }
1082
1083 let tracker = crate::core::tracker::get_tracker();
1085 tracker.track_deallocation_with_lifetime(ptr, lifetime_ms)?;
1086
1087 tracing::debug!(
1088 "Destroyed tracked variable '{}' at ptr 0x{:x}, lifetime: {}ms",
1089 var_name,
1090 ptr,
1091 lifetime_ms
1092 );
1093
1094 Ok(())
1095 }
1096
1097 fn track_smart_pointer_destruction(
1099 var_name: &str,
1100 ptr: usize,
1101 creation_time: u64,
1102 final_ref_count: usize,
1103 ) -> TrackingResult<()> {
1104 let destruction_time = std::time::SystemTime::now()
1105 .duration_since(std::time::UNIX_EPOCH)
1106 .unwrap_or_default()
1107 .as_nanos() as u64;
1108
1109 let lifetime_ms = (destruction_time.saturating_sub(creation_time)) / 1_000_000;
1110
1111 if let Err(e) = crate::variable_registry::VariableRegistry::mark_variable_destroyed(
1113 ptr,
1114 destruction_time,
1115 ) {
1116 tracing::warn!("Failed to mark smart pointer destroyed in registry: {}", e);
1117 }
1118
1119 let tracker = crate::core::tracker::get_tracker();
1121 tracker.track_smart_pointer_deallocation(ptr, lifetime_ms, final_ref_count)?;
1122
1123 tracing::debug!(
1124 "Destroyed smart pointer '{}' at ptr 0x{:x}, lifetime: {}ms, final_ref_count: {}",
1125 var_name,
1126 ptr,
1127 lifetime_ms,
1128 final_ref_count
1129 );
1130
1131 Ok(())
1132 }
1133}
1134
1135impl<T: Trackable> Drop for TrackedVariable<T> {
1136 fn drop(&mut self) {
1137 if let Some(ptr_val) = self.ptr.take() {
1139 if !self
1141 .destruction_tracked
1142 .swap(true, std::sync::atomic::Ordering::Relaxed)
1143 {
1144 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1146 let tracker = crate::core::tracker::get_tracker();
1148 if tracker.is_fast_mode() {
1149 return;
1150 }
1151
1152 let type_name = self.inner.get_type_name();
1153 let smart_pointer_type =
1154 smart_pointer_utils::detect_smart_pointer_type(type_name);
1155 let is_smart_pointer =
1156 smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
1157
1158 if is_smart_pointer {
1159 let final_ref_count = self.inner.get_ref_count();
1161 if let Err(e) = Self::track_smart_pointer_destruction(
1162 &self.var_name,
1163 ptr_val,
1164 self.creation_time,
1165 final_ref_count,
1166 ) {
1167 tracing::error!(
1168 "Failed to track smart pointer destruction in drop: {}",
1169 e
1170 );
1171 }
1172 } else {
1173 if let Err(e) =
1175 Self::track_destruction(&self.var_name, ptr_val, self.creation_time)
1176 {
1177 tracing::error!("Failed to track destruction in drop: {}", e);
1178 }
1179 }
1180 }));
1181 }
1182 }
1183 }
1184}
1185
1186impl<T: Trackable> std::ops::Deref for TrackedVariable<T> {
1188 type Target = T;
1189
1190 fn deref(&self) -> &Self::Target {
1191 &self.inner
1192 }
1193}
1194
1195impl<T: Trackable> std::ops::DerefMut for TrackedVariable<T> {
1196 fn deref_mut(&mut self) -> &mut Self::Target {
1197 &mut self.inner
1198 }
1199}
1200
1201impl<T: Trackable + std::fmt::Debug> std::fmt::Debug for TrackedVariable<T> {
1203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1204 write!(f, "TrackedVariable({:?})", self.inner)
1205 }
1206}
1207
1208impl<T: Trackable + std::fmt::Display> std::fmt::Display for TrackedVariable<T> {
1209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1210 write!(f, "{}", self.inner)
1211 }
1212}
1213
1214impl<T: Trackable + Clone> Clone for TrackedVariable<T> {
1215 fn clone(&self) -> Self {
1216 let clone_name = format!("{}_clone_{}", self.var_name, self.unique_id);
1218 Self::new(self.inner.clone(), clone_name)
1219 }
1220}
1221
1222#[doc(hidden)]
1227pub fn _track_var_impl<T: Trackable>(var: &T, var_name: &str) -> TrackingResult<()> {
1228 let tracker = crate::core::tracker::get_tracker();
1229
1230 if tracker.is_fast_mode() {
1232 let unique_id = TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1233 let synthetic_ptr = 0x8000_0000 + unique_id;
1234 return tracker.fast_track_allocation(
1235 synthetic_ptr,
1236 var.get_size_estimate(),
1237 var_name.to_string(),
1238 );
1239 }
1240
1241 let type_name = var.get_type_name().to_string();
1242 let smart_pointer_type = smart_pointer_utils::detect_smart_pointer_type(&type_name);
1243 let is_smart_pointer = smart_pointer_type != smart_pointer_utils::SmartPointerType::None;
1244
1245 let ptr = if is_smart_pointer {
1247 let unique_id = TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1249 Some(smart_pointer_utils::generate_synthetic_pointer(
1250 smart_pointer_type,
1251 unique_id,
1252 ))
1253 } else {
1254 var.get_heap_ptr().or_else(|| {
1256 let unique_id =
1258 TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1259 Some(0x8000_0000 + unique_id)
1260 })
1261 };
1262
1263 if let Some(ptr_val) = ptr {
1264 let creation_time = std::time::SystemTime::now()
1265 .duration_since(std::time::UNIX_EPOCH)
1266 .unwrap_or_default()
1267 .as_nanos() as u64;
1268
1269 let _ = crate::variable_registry::VariableRegistry::register_variable(
1271 ptr_val,
1272 var_name.to_string(),
1273 type_name.clone(),
1274 var.get_size_estimate(),
1275 );
1276
1277 let scope_tracker = crate::core::scope_tracker::get_global_scope_tracker();
1279 let _ = scope_tracker.associate_variable(var_name.to_string(), var.get_size_estimate());
1280
1281 if is_smart_pointer {
1283 let ref_count = var.get_ref_count();
1285 let data_ptr = var.get_data_ptr();
1286
1287 let _ = tracker.create_smart_pointer_allocation(
1288 ptr_val,
1289 var.get_size_estimate(),
1290 var_name.to_string(),
1291 type_name.clone(),
1292 creation_time,
1293 ref_count,
1294 data_ptr,
1295 );
1296 tracing::debug!(
1297 "🎯 Created smart pointer tracking for '{}' at ptr 0x{:x}, ref_count={}",
1298 var_name,
1299 ptr_val,
1300 ref_count
1301 );
1302 } else if ptr_val >= 0x8000_0000 {
1303 let _ = tracker.create_synthetic_allocation(
1306 ptr_val,
1307 var.get_size_estimate(),
1308 var_name.to_string(),
1309 type_name.clone(),
1310 creation_time,
1311 );
1312
1313 tracing::debug!(
1314 "🎯 Created synthetic tracking for '{}' at ptr 0x{:x}",
1315 var_name,
1316 ptr_val
1317 );
1318 } else {
1319 tracker.associate_var(ptr_val, var_name.to_string(), type_name.clone())?;
1321
1322 tracing::debug!(
1323 "🎯 Associated variable '{}' of type '{}' at ptr 0x{:x}",
1324 var_name,
1325 type_name,
1326 ptr_val
1327 );
1328 }
1329 } else {
1330 tracing::debug!(
1332 "Variable '{}' could not be tracked (no pointer generated)",
1333 var_name
1334 );
1335 }
1336 Ok(())
1337}
1338
1339impl MemoryTracker {
1340 pub fn export_to_json_optimized<P: AsRef<std::path::Path>>(
1342 &self,
1343 path: P,
1344 ) -> TrackingResult<crate::export::complex_type_export::ComplexTypeExportResult> {
1345 use crate::export::complex_type_export::{
1346 export_comprehensive_analysis_optimized, ComplexTypeExportConfig,
1347 };
1348
1349 let path = path.as_ref();
1350 tracing::info!("🚀 Using optimized complex type export for maximum performance...");
1351
1352 let start_time = std::time::Instant::now();
1353
1354 let allocations = self.get_active_allocations()?;
1356 let stats = self.get_stats()?;
1357
1358 let analysis_manager = crate::analysis::AnalysisManager::new();
1360 let comprehensive_report =
1361 analysis_manager.perform_comprehensive_analysis(&allocations, &stats);
1362
1363 let config = ComplexTypeExportConfig {
1365 separate_complex_types: true,
1366 compress_data: false,
1367 chunk_size: 1000,
1368 pretty_format: false, };
1370
1371 let export_result = export_comprehensive_analysis_optimized(
1373 &comprehensive_report,
1374 &allocations,
1375 path,
1376 &config,
1377 )?;
1378
1379 let export_time = start_time.elapsed();
1380
1381 tracing::info!(
1383 "✅ Optimized export completed in {:.2}ms",
1384 export_time.as_millis()
1385 );
1386 tracing::info!(
1387 "📊 Performance improvement: {:.1}%",
1388 export_result.export_stats.performance_improvement
1389 );
1390 tracing::info!(
1391 "📁 Main file: {} ({} bytes)",
1392 export_result.main_file,
1393 export_result.export_stats.main_file_size
1394 );
1395
1396 if export_result.export_stats.complex_files_size > 0 {
1397 tracing::info!(
1398 "📁 Complex type files: {} bytes total",
1399 export_result.export_stats.complex_files_size
1400 );
1401
1402 if let Some(ref file) = export_result.complex_types_file {
1403 tracing::info!(" - Complex types: {}", file);
1404 }
1405 if let Some(ref file) = export_result.borrow_analysis_file {
1406 tracing::info!(" - Borrow analysis: {}", file);
1407 }
1408 if let Some(ref file) = export_result.async_analysis_file {
1409 tracing::info!(" - Async analysis: {}", file);
1410 }
1411 if let Some(ref file) = export_result.closure_analysis_file {
1412 tracing::info!(" - Closure analysis: {}", file);
1413 }
1414 if let Some(ref file) = export_result.lifecycle_analysis_file {
1415 tracing::info!(" - Lifecycle analysis: {}", file);
1416 }
1417 }
1418
1419 Ok(export_result)
1420 }
1421}
1422
1423#[doc(hidden)]
1426pub fn _smart_track_var_impl<T: Trackable + 'static>(var: T, var_name: &str) -> TrackingResult<T> {
1427 use std::any::TypeId;
1428
1429 let type_id = TypeId::of::<T>();
1430 let type_name = std::any::type_name::<T>();
1431
1432 let is_copy_type = type_id == TypeId::of::<i8>()
1434 || type_id == TypeId::of::<i16>()
1435 || type_id == TypeId::of::<i32>()
1436 || type_id == TypeId::of::<i64>()
1437 || type_id == TypeId::of::<i128>()
1438 || type_id == TypeId::of::<isize>()
1439 || type_id == TypeId::of::<u8>()
1440 || type_id == TypeId::of::<u16>()
1441 || type_id == TypeId::of::<u32>()
1442 || type_id == TypeId::of::<u64>()
1443 || type_id == TypeId::of::<u128>()
1444 || type_id == TypeId::of::<usize>()
1445 || type_id == TypeId::of::<f32>()
1446 || type_id == TypeId::of::<f64>()
1447 || type_id == TypeId::of::<bool>()
1448 || type_id == TypeId::of::<char>();
1449
1450 let is_smart_pointer = type_name.contains("::Rc<")
1451 || type_name.contains("::Arc<")
1452 || type_name.contains("::Weak<");
1453
1454 if is_copy_type {
1455 let _ = _track_var_impl(&var, var_name);
1457 tracing::debug!(
1458 "🧠 Smart tracking: Copy type '{}' tracked by reference",
1459 var_name
1460 );
1461 Ok(var)
1462 } else if is_smart_pointer {
1463 let _ = _track_var_impl(&var, var_name);
1465 tracing::debug!(
1466 "🧠 Smart tracking: Smart pointer '{}' tracked by reference",
1467 var_name
1468 );
1469 Ok(var)
1470 } else {
1471 let _ = _track_var_impl(&var, var_name);
1473 tracing::debug!(
1474 "🧠 Smart tracking: Non-Copy type '{}' tracked by reference",
1475 var_name
1476 );
1477 Ok(var)
1478 }
1479}
1480
1481pub fn init() {
1492 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
1493
1494 let default_level = if cfg!(test) || std::env::var("MEMSCOPE_TEST_MODE").is_ok() {
1496 "memscope_rs=error" } else {
1498 "memscope_rs=info" };
1500
1501 tracing_subscriber::registry()
1502 .with(
1503 tracing_subscriber::EnvFilter::try_from_default_env()
1504 .unwrap_or_else(|_| default_level.into()),
1505 )
1506 .with(tracing_subscriber::fmt::layer())
1507 .init();
1508
1509 tracing::info!("memscope-rs initialized");
1510}
1511
1512pub fn init_for_testing() {
1515 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
1516
1517 std::env::set_var("MEMSCOPE_TEST_MODE", "1");
1519
1520 tracing_subscriber::registry()
1522 .with(
1523 tracing_subscriber::EnvFilter::try_from_default_env()
1524 .unwrap_or_else(|_| "memscope_rs=error".into()),
1525 )
1526 .with(tracing_subscriber::fmt::layer())
1527 .init();
1528
1529 tracing::debug!("memscope-rs initialized for testing");
1530}
1531
1532pub mod test_utils {
1534 pub fn init_test() {
1536 std::env::set_var("MEMSCOPE_TEST_MODE", "1");
1537 std::env::set_var("RUST_LOG", "error");
1538
1539 static INIT: std::sync::Once = std::sync::Once::new();
1541 INIT.call_once(|| {
1542 super::init_for_testing();
1543 });
1544
1545 let tracker = crate::core::tracker::get_tracker();
1547 tracker.enable_fast_mode();
1548 }
1549
1550 pub fn reset_tracker() {
1552 }
1555}
1556
1557#[macro_export]
1559macro_rules! init_test {
1560 () => {
1561 $crate::test_utils::init_test();
1562 };
1563}
1564
1565pub fn enable_auto_export(export_path: Option<&str>) {
1568 std::env::set_var("MEMSCOPE_AUTO_EXPORT", "1");
1569 if let Some(path) = export_path {
1570 std::env::set_var("MEMSCOPE_EXPORT_PATH", path);
1571 }
1572
1573 install_exit_hook();
1575
1576 tracing::info!(
1577 "📋 Auto-export enabled - JSON will be exported to: {}",
1578 export_path.unwrap_or("memscope_final_snapshot.json")
1579 );
1580}
1581
1582fn install_exit_hook() {
1584 use std::sync::Once;
1585 static HOOK_INSTALLED: Once = Once::new();
1586
1587 HOOK_INSTALLED.call_once(|| {
1588 let original_hook = std::panic::take_hook();
1590 std::panic::set_hook(Box::new(move |panic_info| {
1591 original_hook(panic_info);
1594 }));
1595
1596 extern "C" fn exit_handler() {
1598 }
1605
1606 unsafe {
1607 libc::atexit(exit_handler);
1608 }
1609
1610 tracing::debug!("📌 Exit hooks installed for automatic memory export");
1611 });
1612}
1613
1614#[cfg(test)]
1615mod test_unified_tracking;
1616
1617#[cfg(test)]
1618mod test_high_concurrency;
1619
1620#[cfg(test)]
1621mod tests {
1622 use super::*;
1623 use std::cell::{Cell, RefCell};
1624 use std::collections::{
1625 BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque,
1626 };
1627 use std::rc::{Rc, Weak as RcWeak};
1628 use std::sync::{Arc, Weak as ArcWeak};
1629 use std::sync::{Mutex, RwLock};
1630
1631 fn setup_test() {
1632 static INIT: std::sync::Once = std::sync::Once::new();
1634 INIT.call_once(|| {
1635 std::env::set_var("MEMSCOPE_TEST_MODE", "1");
1636 std::env::set_var("RUST_LOG", "error");
1637
1638 let _ = tracing_subscriber::fmt()
1640 .with_env_filter("error")
1641 .try_init();
1642 });
1643
1644 }
1646
1647 #[test]
1648 fn test_trackable_vec() {
1649 setup_test();
1650 let vec = vec![1, 2, 3, 4, 5];
1651
1652 assert!(vec.get_heap_ptr().is_some());
1654 assert_eq!(vec.get_type_name(), std::any::type_name::<Vec<i32>>());
1655 assert_eq!(
1656 vec.get_size_estimate(),
1657 vec.capacity() * std::mem::size_of::<i32>()
1658 );
1659 assert_eq!(vec.get_ref_count(), 1);
1660 assert_eq!(vec.get_data_ptr(), vec.get_heap_ptr().unwrap_or(0));
1661 assert!(vec.get_internal_allocations("test").is_empty());
1662 }
1663
1664 #[test]
1665 fn test_trackable_string() {
1666 setup_test();
1667 let s = String::from("Hello, World!");
1668
1669 assert!(s.get_heap_ptr().is_some());
1670 assert_eq!(s.get_type_name(), "String");
1671 assert_eq!(s.get_size_estimate(), s.capacity());
1672 assert_eq!(s.get_ref_count(), 1);
1673 }
1674
1675 #[test]
1676 fn test_trackable_box() {
1677 setup_test();
1678 let boxed = Box::new(42);
1679
1680 assert!(boxed.get_heap_ptr().is_some());
1681 assert_eq!(boxed.get_type_name(), std::any::type_name::<Box<i32>>());
1682 assert_eq!(boxed.get_size_estimate(), std::mem::size_of::<i32>());
1683 }
1684
1685 #[test]
1686 fn test_trackable_rc() {
1687 setup_test();
1688 let rc = Rc::new(vec![1, 2, 3]);
1689 let rc_clone = rc.clone();
1690
1691 assert!(rc.get_heap_ptr().is_some());
1692 assert_eq!(rc.get_type_name(), std::any::type_name::<Rc<Vec<i32>>>());
1693 assert_eq!(rc.get_ref_count(), 2); assert_eq!(rc.get_data_ptr(), Rc::as_ptr(&rc) as usize);
1695
1696 assert_eq!(rc.get_data_ptr(), rc_clone.get_data_ptr());
1698 }
1699
1700 #[test]
1701 fn test_trackable_arc() {
1702 setup_test();
1703 let arc = Arc::new(vec![1, 2, 3]);
1704 let arc_clone = arc.clone();
1705
1706 assert!(arc.get_heap_ptr().is_some());
1707 assert_eq!(arc.get_type_name(), std::any::type_name::<Arc<Vec<i32>>>());
1708 assert_eq!(arc.get_ref_count(), 2); assert_eq!(arc.get_data_ptr(), Arc::as_ptr(&arc) as usize);
1710
1711 assert_eq!(arc.get_data_ptr(), arc_clone.get_data_ptr());
1713 }
1714
1715 #[test]
1716 fn test_trackable_collections() {
1717 setup_test();
1718
1719 let mut map = HashMap::new();
1721 map.insert("key", "value");
1722 assert!(map.get_heap_ptr().is_some());
1723 assert_eq!(
1724 map.get_type_name(),
1725 std::any::type_name::<HashMap<&str, &str>>()
1726 );
1727
1728 let mut btree = BTreeMap::new();
1730 btree.insert(1, "one");
1731 assert!(btree.get_heap_ptr().is_some());
1732
1733 let mut set = HashSet::new();
1735 set.insert(42);
1736 assert!(set.get_heap_ptr().is_some());
1737
1738 let mut btree_set = BTreeSet::new();
1740 btree_set.insert(42);
1741 assert!(btree_set.get_heap_ptr().is_some());
1742
1743 let mut deque = VecDeque::new();
1745 deque.push_back(1);
1746 assert!(deque.get_heap_ptr().is_some());
1747
1748 let mut list = LinkedList::new();
1750 list.push_back(1);
1751 assert!(list.get_heap_ptr().is_some());
1752
1753 let mut heap = BinaryHeap::new();
1755 heap.push(1);
1756 assert!(heap.get_heap_ptr().is_some());
1757 }
1758
1759 #[test]
1760 fn test_trackable_weak_pointers() {
1761 setup_test();
1762
1763 let rc = Rc::new(42);
1765 let weak: RcWeak<i32> = Rc::downgrade(&rc);
1766 assert!(weak.get_heap_ptr().is_some());
1767 assert_eq!(weak.get_ref_count(), 1); assert_eq!(weak.get_data_ptr(), Rc::as_ptr(&rc) as usize);
1769
1770 let arc = Arc::new(42);
1772 let weak: ArcWeak<i32> = Arc::downgrade(&arc);
1773 assert!(weak.get_heap_ptr().is_some());
1774 assert_eq!(weak.get_ref_count(), 1); assert_eq!(weak.get_data_ptr(), Arc::as_ptr(&arc) as usize);
1776 }
1777
1778 #[test]
1779 fn test_trackable_option() {
1780 setup_test();
1781
1782 let some_vec = Some(vec![1, 2, 3]);
1783 let none_vec: Option<Vec<i32>> = None;
1784
1785 assert!(some_vec.get_heap_ptr().is_some());
1786 assert!(none_vec.get_heap_ptr().is_none());
1787
1788 assert_eq!(
1789 some_vec.get_type_name(),
1790 std::any::type_name::<Option<Vec<i32>>>()
1791 );
1792 assert_eq!(
1793 none_vec.get_type_name(),
1794 std::any::type_name::<Option<Vec<i32>>>()
1795 );
1796
1797 let allocations = some_vec.get_internal_allocations("test_var");
1799 assert_eq!(allocations.len(), 0); }
1802
1803 #[test]
1804 fn test_trackable_result() {
1805 setup_test();
1806
1807 let ok_result: Result<Vec<i32>, String> = Ok(vec![1, 2, 3]);
1808 let err_result: Result<Vec<i32>, String> = Err("error".to_string());
1809
1810 assert!(ok_result.get_heap_ptr().is_some());
1811 assert!(err_result.get_heap_ptr().is_some());
1812
1813 assert_eq!(
1814 ok_result.get_type_name(),
1815 std::any::type_name::<Result<Vec<i32>, String>>()
1816 );
1817 assert_eq!(
1818 err_result.get_type_name(),
1819 std::any::type_name::<Result<Vec<i32>, String>>()
1820 );
1821 }
1822
1823 #[test]
1824 fn test_trackable_tuple() {
1825 setup_test();
1826
1827 let tuple = (vec![1, 2, 3], String::from("hello"), Box::new(42));
1828
1829 assert!(tuple.get_heap_ptr().is_some());
1830 assert_eq!(
1831 tuple.get_type_name(),
1832 std::any::type_name::<(Vec<i32>, String, Box<i32>)>()
1833 );
1834
1835 let expected_size =
1837 tuple.0.get_size_estimate() + tuple.1.get_size_estimate() + tuple.2.get_size_estimate();
1838 assert_eq!(tuple.get_size_estimate(), expected_size);
1839 }
1840
1841 #[test]
1842 fn test_smart_pointer_utils() {
1843 use smart_pointer_utils::*;
1844
1845 assert_eq!(
1847 detect_smart_pointer_type("std::rc::Rc<i32>"),
1848 SmartPointerType::Rc
1849 );
1850 assert_eq!(
1851 detect_smart_pointer_type("std::sync::Arc<String>"),
1852 SmartPointerType::Arc
1853 );
1854 assert_eq!(
1855 detect_smart_pointer_type("std::boxed::Box<Vec<i32>>"),
1856 SmartPointerType::Box
1857 );
1858 assert_eq!(
1859 detect_smart_pointer_type("Vec<i32>"),
1860 SmartPointerType::None
1861 );
1862
1863 assert!(is_smart_pointer("std::rc::Rc<i32>"));
1865 assert!(is_smart_pointer("std::sync::Arc<String>"));
1866 assert!(is_smart_pointer("std::boxed::Box<Vec<i32>>"));
1867 assert!(!is_smart_pointer("Vec<i32>"));
1868
1869 assert_eq!(
1871 generate_synthetic_pointer(SmartPointerType::Rc, 123),
1872 0x5000_0000 + 123
1873 );
1874 assert_eq!(
1875 generate_synthetic_pointer(SmartPointerType::Arc, 456),
1876 0x6000_0000 + 456
1877 );
1878 assert_eq!(
1879 generate_synthetic_pointer(SmartPointerType::Box, 789),
1880 0x7000_0000 + 789
1881 );
1882 }
1883
1884 #[test]
1885 fn test_tracked_variable_basic() {
1886 setup_test();
1887
1888 let vec = vec![1, 2, 3, 4, 5];
1890
1891 assert_eq!(vec.len(), 5);
1894 assert_eq!(vec[0], 1);
1895 assert!(vec.get_heap_ptr().is_some());
1896 assert_eq!(vec.get_type_name(), std::any::type_name::<Vec<i32>>());
1897 }
1898
1899 #[test]
1900 fn test_tracked_variable_smart_pointer() {
1901 setup_test();
1902
1903 let rc = Rc::new(vec![1, 2, 3]);
1905
1906 assert_eq!(rc.len(), 3);
1907 assert_eq!(rc[0], 1);
1908 assert!(rc.get_heap_ptr().is_some());
1909 assert_eq!(rc.get_type_name(), std::any::type_name::<Rc<Vec<i32>>>());
1910 assert_eq!(rc.get_ref_count(), 1);
1911 }
1912
1913 #[test]
1914 fn test_tracked_variable_into_inner() {
1915 setup_test();
1916
1917 let vec = vec![1, 2, 3, 4, 5];
1919
1920 assert_eq!(vec.len(), 5);
1922 assert_eq!(vec[0], 1);
1923
1924 let moved_vec = vec;
1926 assert_eq!(moved_vec.len(), 5);
1927 assert_eq!(moved_vec[0], 1);
1928 }
1929
1930 #[test]
1931 fn test_tracked_variable_clone() {
1932 setup_test();
1933
1934 let vec = vec![1, 2, 3];
1936 let cloned_vec = vec.clone();
1937
1938 assert_eq!(vec.len(), cloned_vec.len());
1939 assert_eq!(vec[0], cloned_vec[0]);
1940
1941 assert!(vec.get_heap_ptr().is_some());
1943 assert!(cloned_vec.get_heap_ptr().is_some());
1944 }
1945
1946 #[test]
1947 fn test_track_var_macro() {
1948 setup_test();
1949
1950 let vec = vec![1, 2, 3, 4, 5];
1951
1952 assert_eq!(vec.len(), 5);
1955 assert_eq!(vec[0], 1);
1956
1957 assert!(vec.get_heap_ptr().is_some());
1959 assert_eq!(vec.get_type_name(), std::any::type_name::<Vec<i32>>());
1960 }
1961
1962 #[test]
1963 fn test_track_var_owned_macro() {
1964 setup_test();
1965
1966 let vec = vec![1, 2, 3, 4, 5];
1968
1969 assert_eq!(vec.len(), 5);
1971 assert_eq!(vec[0], 1);
1972 assert!(vec.get_heap_ptr().is_some());
1973 assert_eq!(vec.get_type_name(), std::any::type_name::<Vec<i32>>());
1974 }
1975
1976 #[test]
1977 fn test_track_var_smart_macro() {
1978 setup_test();
1979
1980 let number = 42i32;
1982 assert_eq!(number, 42);
1983 assert!(number.get_heap_ptr().is_some());
1984
1985 let vec = vec![1, 2, 3];
1987 assert_eq!(vec.len(), 3);
1988 assert!(vec.get_heap_ptr().is_some());
1989
1990 let rc = Rc::new(vec![1, 2, 3]);
1992 assert_eq!(rc.len(), 3);
1993 assert!(rc.get_heap_ptr().is_some());
1994 assert_eq!(rc.get_ref_count(), 1);
1995 }
1996
1997 #[test]
1998 fn test_init_functions() {
1999 std::env::set_var("MEMSCOPE_TEST_MODE", "1");
2001 std::env::set_var("RUST_LOG", "error");
2002
2003 assert_eq!(std::env::var("MEMSCOPE_TEST_MODE").unwrap(), "1");
2004 assert_eq!(std::env::var("RUST_LOG").unwrap(), "error");
2005
2006 let _ = std::panic::catch_unwind(|| {
2009 });
2011 }
2012
2013 #[test]
2014 fn test_enable_auto_export() {
2015 setup_test();
2016
2017 std::env::set_var("MEMSCOPE_TEST_MODE", "1");
2019
2020 enable_auto_export(Some("test_export"));
2022 assert_eq!(std::env::var("MEMSCOPE_AUTO_EXPORT").unwrap(), "1");
2023 assert_eq!(
2024 std::env::var("MEMSCOPE_EXPORT_PATH").unwrap(),
2025 "test_export"
2026 );
2027
2028 std::env::remove_var("MEMSCOPE_EXPORT_PATH");
2030 enable_auto_export(None);
2031 assert_eq!(std::env::var("MEMSCOPE_AUTO_EXPORT").unwrap(), "1");
2032 assert!(std::env::var("MEMSCOPE_EXPORT_PATH").is_err());
2033
2034 std::env::remove_var("MEMSCOPE_TEST_MODE");
2036 std::env::remove_var("MEMSCOPE_AUTO_EXPORT");
2037 }
2038
2039 #[test]
2040 fn test_export_final_snapshot() {
2041 setup_test();
2042
2043 let temp_path = "tmp_rovodev_test_export";
2045
2046 assert!(!temp_path.is_empty());
2048 assert!(!temp_path.is_empty());
2049
2050 let json_path = format!("{temp_path}.json");
2052 let html_path = format!("{temp_path}.html");
2053
2054 assert!(json_path.ends_with(".json"));
2055 assert!(html_path.ends_with(".html"));
2056
2057 }
2059
2060 #[test]
2061 fn test_advanced_type_implementations() {
2062 setup_test();
2063
2064 let cell = RefCell::new(42);
2066 assert!(cell.get_heap_ptr().is_some());
2067 assert_eq!(cell.get_type_name(), std::any::type_name::<RefCell<i32>>());
2068
2069 let cell = Cell::new(42);
2071 assert!(cell.get_heap_ptr().is_some());
2072 assert_eq!(cell.get_type_name(), std::any::type_name::<Cell<i32>>());
2073
2074 let mutex = Mutex::new(42);
2076 assert!(mutex.get_heap_ptr().is_some());
2077 assert_eq!(mutex.get_type_name(), std::any::type_name::<Mutex<i32>>());
2078
2079 let rwlock = RwLock::new(42);
2081 assert!(rwlock.get_heap_ptr().is_some());
2082 assert_eq!(rwlock.get_type_name(), std::any::type_name::<RwLock<i32>>());
2083 }
2084
2085 #[test]
2086 fn test_memory_tracker_optimized_export() {
2087 setup_test();
2088
2089 let temp_path = std::path::Path::new("tmp_rovodev_optimized_export.json");
2094 assert!(temp_path.to_str().is_some());
2095
2096 }
2099
2100 #[test]
2101 fn test_smart_track_var_impl_copy_types() {
2102 setup_test();
2103
2104 let i32_val = 42i32;
2106 let u32_val = 42u32;
2107 let f64_val = std::f64::consts::PI;
2108 let bool_val = true;
2109 let char_val = 'a';
2110
2111 assert!(i32_val.get_heap_ptr().is_some());
2112 assert!(u32_val.get_heap_ptr().is_some());
2113 assert!(f64_val.get_heap_ptr().is_some());
2114 assert!(bool_val.get_heap_ptr().is_some());
2115 assert!(char_val.get_heap_ptr().is_some());
2116
2117 assert_eq!(i32_val.get_type_name(), "i32");
2118 assert_eq!(u32_val.get_type_name(), "u32");
2119 assert_eq!(f64_val.get_type_name(), "f64");
2120 assert_eq!(bool_val.get_type_name(), "bool");
2121 assert_eq!(char_val.get_type_name(), "char");
2122 }
2123
2124 #[test]
2125 fn test_trackable_advanced_type_info() {
2126 setup_test();
2127
2128 let vec = vec![1, 2, 3];
2129 let type_info = vec.get_advanced_type_info();
2130
2131 assert!(type_info.is_none());
2134 }
2135
2136 #[test]
2137 fn test_trackable_default_methods() {
2138 setup_test();
2139
2140 let vec = vec![1, 2, 3];
2141
2142 vec.track_clone_relationship(0x1000, 0x2000); vec.update_ref_count_tracking(0x1000); }
2148
2149 #[test]
2150 fn test_init_test_macro() {
2151 std::env::set_var("MEMSCOPE_TEST_MODE", "1");
2156 std::env::set_var("RUST_LOG", "error");
2157
2158 assert_eq!(std::env::var("MEMSCOPE_TEST_MODE").unwrap(), "1");
2159 assert_eq!(std::env::var("RUST_LOG").unwrap(), "error");
2160 }
2161
2162 #[test]
2163 fn test_tracked_variable_counter() {
2164 setup_test();
2165
2166 let initial_count = TRACKED_VARIABLE_COUNTER.load(std::sync::atomic::Ordering::Relaxed);
2168
2169 TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2171 TRACKED_VARIABLE_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2172
2173 let final_count = TRACKED_VARIABLE_COUNTER.load(std::sync::atomic::Ordering::Relaxed);
2174
2175 assert!(final_count >= initial_count + 2);
2177 }
2178
2179 #[test]
2180 fn test_empty_collections() {
2181 setup_test();
2182
2183 let empty_vec: Vec<i32> = Vec::new();
2185 assert!(empty_vec.get_heap_ptr().is_none());
2186
2187 let empty_map: HashMap<i32, String> = HashMap::new();
2188 assert!(empty_map.get_heap_ptr().is_some()); let empty_btree: BTreeMap<i32, String> = BTreeMap::new();
2191 assert!(empty_btree.get_heap_ptr().is_none());
2192
2193 let empty_set: HashSet<i32> = HashSet::new();
2194 assert!(empty_set.get_heap_ptr().is_none());
2195
2196 let empty_btree_set: BTreeSet<i32> = BTreeSet::new();
2197 assert!(empty_btree_set.get_heap_ptr().is_none());
2198
2199 let empty_list: LinkedList<i32> = LinkedList::new();
2200 assert!(empty_list.get_heap_ptr().is_none());
2201
2202 let empty_heap: BinaryHeap<i32> = BinaryHeap::new();
2203 assert!(empty_heap.get_heap_ptr().is_none());
2204 }
2205}