1#![warn(missing_docs)]
9
10pub mod allocator;
11pub mod export_enhanced;
12pub mod tracker;
13pub mod types;
14pub mod utils;
15pub mod visualization;
16
17pub use allocator::TrackingAllocator;
19pub use tracker::{get_global_tracker, MemoryTracker};
20pub use types::{AllocationInfo, TrackingError, TrackingResult};
21pub use utils::{format_bytes, get_simple_type, simplify_type_name};
22pub use visualization::{export_lifecycle_timeline, export_memory_analysis};
23
24#[cfg(feature = "tracking-allocator")]
26#[global_allocator]
27pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
29
30pub trait Trackable {
32 fn get_heap_ptr(&self) -> Option<usize>;
34
35 fn get_type_name(&self) -> &'static str;
37}
38
39impl<T> Trackable for Vec<T> {
41 fn get_heap_ptr(&self) -> Option<usize> {
42 if self.capacity() > 0 {
43 Some(self.as_ptr() as usize)
44 } else {
45 None
46 }
47 }
48
49 fn get_type_name(&self) -> &'static str {
50 std::any::type_name::<Vec<T>>()
51 }
52}
53
54impl Trackable for String {
55 fn get_heap_ptr(&self) -> Option<usize> {
56 if self.capacity() > 0 {
57 Some(self.as_ptr() as usize)
58 } else {
59 None
60 }
61 }
62
63 fn get_type_name(&self) -> &'static str {
64 "String"
65 }
66}
67
68impl<T> Trackable for Box<T> {
69 fn get_heap_ptr(&self) -> Option<usize> {
70 Some(self.as_ref() as *const T as usize)
71 }
72
73 fn get_type_name(&self) -> &'static str {
74 std::any::type_name::<Box<T>>()
75 }
76}
77
78impl<T> Trackable for std::rc::Rc<T> {
79 fn get_heap_ptr(&self) -> Option<usize> {
80 Some(std::rc::Rc::as_ptr(self) as usize)
83 }
84
85 fn get_type_name(&self) -> &'static str {
86 std::any::type_name::<std::rc::Rc<T>>()
87 }
88}
89
90impl<T> Trackable for std::sync::Arc<T> {
91 fn get_heap_ptr(&self) -> Option<usize> {
92 Some(std::sync::Arc::as_ptr(self) as usize)
95 }
96
97 fn get_type_name(&self) -> &'static str {
98 std::any::type_name::<std::sync::Arc<T>>()
99 }
100}
101
102#[macro_export]
115macro_rules! track_var {
116 ($var:ident) => {
117 $crate::_track_var_impl(&$var, stringify!($var))
118 };
119}
120
121#[doc(hidden)]
124pub fn _track_var_impl<T: Trackable>(var: &T, var_name: &str) -> TrackingResult<()> {
125 if let Some(ptr) = var.get_heap_ptr() {
126 let tracker = get_global_tracker();
127 let type_name = var.get_type_name().to_string();
128
129 tracker.associate_var(ptr, var_name.to_string(), type_name)
138 } else {
139 Ok(())
142 }
143}
144
145pub fn init() {
156 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
157
158 tracing_subscriber::registry()
159 .with(
160 tracing_subscriber::EnvFilter::try_from_default_env()
161 .unwrap_or_else(|_| "memscope_rs=info".into()),
162 )
163 .with(tracing_subscriber::fmt::layer())
164 .init();
165
166 tracing::info!("memscope-rs initialized");
167}