1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum MemoryEventType {
12 Allocate,
14 Deallocate,
16 Reallocate,
18 Move,
20 Borrow,
22 Return,
24 Metadata,
26 Clone,
28}
29
30impl fmt::Display for MemoryEventType {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 MemoryEventType::Allocate => write!(f, "Allocate"),
34 MemoryEventType::Deallocate => write!(f, "Deallocate"),
35 MemoryEventType::Reallocate => write!(f, "Reallocate"),
36 MemoryEventType::Move => write!(f, "Move"),
37 MemoryEventType::Borrow => write!(f, "Borrow"),
38 MemoryEventType::Return => write!(f, "Return"),
39 MemoryEventType::Metadata => write!(f, "Metadata"),
40 MemoryEventType::Clone => write!(f, "Clone"),
41 }
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct MemoryEvent {
51 pub timestamp: u64,
53 pub event_type: MemoryEventType,
55 pub ptr: usize,
57 pub size: usize,
59 pub old_size: Option<usize>,
61 pub thread_id: u64,
63 pub var_name: Option<String>,
65 pub type_name: Option<String>,
67 pub call_stack_hash: Option<u64>,
69 pub thread_name: Option<String>,
71 pub source_file: Option<String>,
73 pub source_line: Option<u32>,
75 pub module_path: Option<String>,
77 pub clone_source_ptr: Option<usize>,
79 pub clone_target_ptr: Option<usize>,
81 pub stack_ptr: Option<usize>,
83 pub task_id: Option<u64>,
85}
86
87impl MemoryEvent {
88 pub fn allocate(ptr: usize, size: usize, thread_id: u64) -> Self {
90 crate::task_registry::global_registry().record_allocation(size);
92
93 Self {
94 timestamp: Self::now(),
95 event_type: MemoryEventType::Allocate,
96 ptr,
97 size,
98 old_size: None,
99 thread_id,
100 var_name: None,
101 type_name: None,
102 call_stack_hash: None,
103 thread_name: None,
104 source_file: None,
105 source_line: None,
106 module_path: None,
107 clone_source_ptr: None,
108 clone_target_ptr: None,
109 stack_ptr: None,
110 task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
111 }
112 }
113
114 pub fn deallocate(ptr: usize, size: usize, thread_id: u64) -> Self {
116 Self {
117 timestamp: Self::now(),
118 event_type: MemoryEventType::Deallocate,
119 ptr,
120 size,
121 old_size: None,
122 thread_id,
123 var_name: None,
124 type_name: None,
125 call_stack_hash: None,
126 thread_name: None,
127 source_file: None,
128 source_line: None,
129 module_path: None,
130 clone_source_ptr: None,
131 clone_target_ptr: None,
132 stack_ptr: None,
133 task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
134 }
135 }
136
137 pub fn reallocate(ptr: usize, old_size: usize, new_size: usize, thread_id: u64) -> Self {
139 Self {
140 timestamp: Self::now(),
141 event_type: MemoryEventType::Reallocate,
142 ptr,
143 size: new_size,
144 old_size: Some(old_size),
145 thread_id,
146 var_name: None,
147 type_name: None,
148 call_stack_hash: None,
149 thread_name: None,
150 source_file: None,
151 source_line: None,
152 module_path: None,
153 clone_source_ptr: None,
154 clone_target_ptr: None,
155 stack_ptr: None,
156 task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
157 }
158 }
159
160 pub fn metadata(var_name: String, type_name: String, thread_id: u64, size: usize) -> Self {
162 Self {
163 timestamp: Self::now(),
164 event_type: MemoryEventType::Metadata,
165 ptr: 0, size,
167 old_size: None,
168 thread_id,
169 var_name: Some(var_name),
170 type_name: Some(type_name),
171 call_stack_hash: None,
172 thread_name: None,
173 source_file: None,
174 source_line: None,
175 module_path: None,
176 clone_source_ptr: None,
177 clone_target_ptr: None,
178 stack_ptr: None,
179 task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
180 }
181 }
182
183 pub fn clone_event(
185 source_ptr: usize,
186 target_ptr: usize,
187 size: usize,
188 thread_id: u64,
189 var_name: Option<String>,
190 type_name: Option<String>,
191 ) -> Self {
192 Self {
193 timestamp: Self::now(),
194 event_type: MemoryEventType::Clone,
195 ptr: target_ptr,
196 size,
197 old_size: None,
198 thread_id,
199 var_name,
200 type_name,
201 call_stack_hash: None,
202 thread_name: None,
203 source_file: None,
204 source_line: None,
205 module_path: None,
206 clone_source_ptr: Some(source_ptr),
207 clone_target_ptr: Some(target_ptr),
208 stack_ptr: None,
209 task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
210 }
211 }
212
213 pub fn borrow(ptr: usize, size: usize, thread_id: u64, is_mutable: bool) -> Self {
215 Self {
216 timestamp: Self::now(),
217 event_type: MemoryEventType::Borrow,
218 ptr,
219 size,
220 old_size: None,
221 thread_id,
222 var_name: None,
223 type_name: Some(if is_mutable {
224 "mutable borrow".to_string()
225 } else {
226 "immutable borrow".to_string()
227 }),
228 call_stack_hash: None,
229 thread_name: None,
230 source_file: None,
231 source_line: None,
232 module_path: None,
233 clone_source_ptr: None,
234 clone_target_ptr: None,
235 stack_ptr: None,
236 task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
237 }
238 }
239
240 pub fn now() -> u64 {
243 use std::time::{SystemTime, UNIX_EPOCH};
244 SystemTime::now()
245 .duration_since(UNIX_EPOCH)
246 .map(|d| d.as_nanos() as u64)
247 .unwrap_or_default()
248 }
249
250 pub fn with_var_name(mut self, name: String) -> Self {
252 self.var_name = Some(name);
253 self
254 }
255
256 pub fn with_type_name(mut self, name: String) -> Self {
258 self.type_name = Some(name);
259 self
260 }
261
262 pub fn with_source_file(mut self, file: String) -> Self {
264 self.source_file = Some(file);
265 self
266 }
267
268 pub fn with_source_line(mut self, line: u32) -> Self {
270 self.source_line = Some(line);
271 self
272 }
273
274 pub fn with_call_stack_hash(mut self, hash: u64) -> Self {
276 self.call_stack_hash = Some(hash);
277 self
278 }
279
280 pub fn with_thread_name(mut self, name: String) -> Self {
282 self.thread_name = Some(name);
283 self
284 }
285
286 pub fn is_allocation(&self) -> bool {
288 matches!(
289 self.event_type,
290 MemoryEventType::Allocate | MemoryEventType::Reallocate | MemoryEventType::Metadata
291 )
292 }
293
294 pub fn is_deallocation(&self) -> bool {
296 matches!(self.event_type, MemoryEventType::Deallocate)
297 }
298
299 pub fn is_move(&self) -> bool {
301 matches!(self.event_type, MemoryEventType::Move)
302 }
303
304 pub fn is_borrow(&self) -> bool {
306 matches!(self.event_type, MemoryEventType::Borrow)
307 }
308
309 pub fn is_return(&self) -> bool {
311 matches!(self.event_type, MemoryEventType::Return)
312 }
313}