1use serde::{Deserialize, Serialize};
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21#[serde(tag = "type")]
22pub enum Event {
23 New {
25 timestamp: u64,
26 var_name: String,
27 var_id: String,
28 type_name: String,
29 },
30
31 Borrow {
33 timestamp: u64,
34 borrower_name: String,
35 borrower_id: String,
36 owner_id: String,
37 mutable: bool,
38 },
39
40 Move {
42 timestamp: u64,
43 from_id: String,
44 to_name: String,
45 to_id: String,
46 },
47
48 Drop { timestamp: u64, var_id: String },
50
51 RcNew {
53 timestamp: u64,
54 var_name: String,
55 var_id: String,
56 type_name: String,
57 strong_count: usize,
58 weak_count: usize,
59 },
60
61 RcClone {
63 timestamp: u64,
64 var_name: String,
65 var_id: String,
66 source_id: String,
67 strong_count: usize,
68 weak_count: usize,
69 },
70
71 ArcNew {
73 timestamp: u64,
74 var_name: String,
75 var_id: String,
76 type_name: String,
77 strong_count: usize,
78 weak_count: usize,
79 },
80
81 ArcClone {
83 timestamp: u64,
84 var_name: String,
85 var_id: String,
86 source_id: String,
87 strong_count: usize,
88 weak_count: usize,
89 },
90
91 RefCellNew {
93 timestamp: u64,
94 var_name: String,
95 var_id: String,
96 type_name: String,
97 },
98
99 RefCellBorrow {
101 timestamp: u64,
102 borrow_id: String,
103 refcell_id: String,
104 is_mutable: bool,
105 location: String,
106 },
107
108 RefCellDrop {
110 timestamp: u64,
111 borrow_id: String,
112 location: String,
113 },
114
115 CellNew {
117 timestamp: u64,
118 var_name: String,
119 var_id: String,
120 type_name: String,
121 },
122
123 CellGet {
125 timestamp: u64,
126 cell_id: String,
127 location: String,
128 },
129
130 CellSet {
132 timestamp: u64,
133 cell_id: String,
134 location: String,
135 },
136
137 StaticInit {
139 timestamp: u64,
140 var_name: String,
141 var_id: String,
142 type_name: String,
143 is_mutable: bool,
144 },
145
146 StaticAccess {
148 timestamp: u64,
149 var_id: String,
150 var_name: String,
151 is_write: bool,
152 location: String,
153 },
154
155 ConstEval {
157 timestamp: u64,
158 const_name: String,
159 const_id: String,
160 type_name: String,
161 location: String,
162 },
163
164 RawPtrCreated {
166 timestamp: u64,
167 var_name: String,
168 var_id: String,
169 ptr_type: String,
170 address: usize,
171 location: String,
172 },
173
174 RawPtrDeref {
176 timestamp: u64,
177 ptr_id: String,
178 location: String,
179 is_write: bool,
180 },
181
182 UnsafeBlockEnter {
184 timestamp: u64,
185 block_id: String,
186 location: String,
187 },
188
189 UnsafeBlockExit {
191 timestamp: u64,
192 block_id: String,
193 location: String,
194 },
195
196 UnsafeFnCall {
198 timestamp: u64,
199 fn_name: String,
200 location: String,
201 },
202
203 FfiCall {
205 timestamp: u64,
206 fn_name: String,
207 location: String,
208 },
209
210 Transmute {
212 timestamp: u64,
213 from_type: String,
214 to_type: String,
215 location: String,
216 },
217
218 UnionFieldAccess {
220 timestamp: u64,
221 union_name: String,
222 field_name: String,
223 location: String,
224 },
225}
226
227impl Event {
228 pub fn timestamp(&self) -> u64 {
230 match self {
231 Event::New { timestamp, .. }
232 | Event::Borrow { timestamp, .. }
233 | Event::Move { timestamp, .. }
234 | Event::Drop { timestamp, .. }
235 | Event::RcNew { timestamp, .. }
236 | Event::RcClone { timestamp, .. }
237 | Event::ArcNew { timestamp, .. }
238 | Event::ArcClone { timestamp, .. }
239 | Event::RefCellNew { timestamp, .. }
240 | Event::RefCellBorrow { timestamp, .. }
241 | Event::RefCellDrop { timestamp, .. }
242 | Event::CellNew { timestamp, .. }
243 | Event::CellGet { timestamp, .. }
244 | Event::CellSet { timestamp, .. }
245 | Event::StaticInit { timestamp, .. }
246 | Event::StaticAccess { timestamp, .. }
247 | Event::ConstEval { timestamp, .. }
248 | Event::RawPtrCreated { timestamp, .. }
249 | Event::RawPtrDeref { timestamp, .. }
250 | Event::UnsafeBlockEnter { timestamp, .. }
251 | Event::UnsafeBlockExit { timestamp, .. }
252 | Event::UnsafeFnCall { timestamp, .. }
253 | Event::FfiCall { timestamp, .. }
254 | Event::Transmute { timestamp, .. }
255 | Event::UnionFieldAccess { timestamp, .. } => *timestamp,
256 }
257 }
258
259 pub fn var_name(&self) -> Option<&str> {
261 match self {
262 Event::New { var_name, .. }
263 | Event::RcNew { var_name, .. }
264 | Event::RcClone { var_name, .. }
265 | Event::ArcNew { var_name, .. }
266 | Event::ArcClone { var_name, .. }
267 | Event::RefCellNew { var_name, .. }
268 | Event::CellNew { var_name, .. }
269 | Event::StaticInit { var_name, .. }
270 | Event::StaticAccess { var_name, .. }
271 | Event::RawPtrCreated { var_name, .. }
272 | Event::ConstEval {
273 const_name: var_name,
274 ..
275 } => Some(var_name),
276 Event::Borrow { borrower_name, .. } => Some(borrower_name),
277 Event::Move { to_name, .. } => Some(to_name),
278 Event::Drop { var_id, .. } => Some(var_id),
279 Event::RefCellBorrow { .. }
280 | Event::RefCellDrop { .. }
281 | Event::CellGet { .. }
282 | Event::CellSet { .. }
283 | Event::RawPtrDeref { .. }
284 | Event::UnsafeBlockEnter { .. }
285 | Event::UnsafeBlockExit { .. }
286 | Event::UnsafeFnCall { .. }
287 | Event::FfiCall { .. }
288 | Event::Transmute { .. }
289 | Event::UnionFieldAccess { .. } => None,
290 }
291 }
292
293 pub fn is_new(&self) -> bool {
295 matches!(self, Event::New { .. })
296 }
297
298 pub fn is_borrow(&self) -> bool {
300 matches!(self, Event::Borrow { .. })
301 }
302
303 pub fn is_move(&self) -> bool {
305 matches!(self, Event::Move { .. })
306 }
307
308 pub fn is_drop(&self) -> bool {
310 matches!(self, Event::Drop { .. })
311 }
312
313 pub fn is_rc(&self) -> bool {
315 matches!(self, Event::RcNew { .. } | Event::RcClone { .. })
316 }
317
318 pub fn is_arc(&self) -> bool {
320 matches!(self, Event::ArcNew { .. } | Event::ArcClone { .. })
321 }
322
323 pub fn is_refcounted(&self) -> bool {
325 self.is_rc() || self.is_arc()
326 }
327
328 pub fn is_refcell(&self) -> bool {
330 matches!(
331 self,
332 Event::RefCellNew { .. } | Event::RefCellBorrow { .. } | Event::RefCellDrop { .. }
333 )
334 }
335
336 pub fn is_cell(&self) -> bool {
338 matches!(
339 self,
340 Event::CellNew { .. } | Event::CellGet { .. } | Event::CellSet { .. }
341 )
342 }
343
344 pub fn is_interior_mutability(&self) -> bool {
346 self.is_refcell() || self.is_cell()
347 }
348
349 pub fn is_static(&self) -> bool {
351 matches!(self, Event::StaticInit { .. } | Event::StaticAccess { .. })
352 }
353
354 pub fn is_const(&self) -> bool {
356 matches!(self, Event::ConstEval { .. })
357 }
358
359 pub fn is_global(&self) -> bool {
361 self.is_static() || self.is_const()
362 }
363
364 pub fn is_unsafe(&self) -> bool {
366 matches!(
367 self,
368 Event::RawPtrCreated { .. }
369 | Event::RawPtrDeref { .. }
370 | Event::UnsafeBlockEnter { .. }
371 | Event::UnsafeBlockExit { .. }
372 | Event::UnsafeFnCall { .. }
373 | Event::FfiCall { .. }
374 | Event::Transmute { .. }
375 | Event::UnionFieldAccess { .. }
376 )
377 }
378
379 pub fn is_raw_ptr(&self) -> bool {
381 matches!(
382 self,
383 Event::RawPtrCreated { .. } | Event::RawPtrDeref { .. }
384 )
385 }
386
387 pub fn is_ffi(&self) -> bool {
389 matches!(self, Event::FfiCall { .. })
390 }
391
392 pub fn strong_count(&self) -> Option<usize> {
394 match self {
395 Event::RcNew { strong_count, .. }
396 | Event::RcClone { strong_count, .. }
397 | Event::ArcNew { strong_count, .. }
398 | Event::ArcClone { strong_count, .. } => Some(*strong_count),
399 _ => None,
400 }
401 }
402
403 pub fn weak_count(&self) -> Option<usize> {
405 match self {
406 Event::RcNew { weak_count, .. }
407 | Event::RcClone { weak_count, .. }
408 | Event::ArcNew { weak_count, .. }
409 | Event::ArcClone { weak_count, .. } => Some(*weak_count),
410 _ => None,
411 }
412 }
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418
419 #[test]
420 fn test_event_new() {
421 let event = Event::New {
422 timestamp: 1,
423 var_name: "x".to_string(),
424 var_id: "x_0".to_string(),
425 type_name: "i32".to_string(),
426 };
427
428 assert_eq!(event.timestamp(), 1);
429 assert_eq!(event.var_name(), Some("x"));
430 assert!(event.is_new());
431 assert!(!event.is_borrow());
432 assert!(!event.is_move());
433 assert!(!event.is_drop());
434 }
435
436 #[test]
437 fn test_event_borrow() {
438 let event = Event::Borrow {
439 timestamp: 2,
440 borrower_name: "r".to_string(),
441 borrower_id: "r_1".to_string(),
442 owner_id: "x_0".to_string(),
443 mutable: false,
444 };
445
446 assert_eq!(event.timestamp(), 2);
447 assert_eq!(event.var_name(), Some("r"));
448 assert!(event.is_borrow());
449 assert!(!event.is_new());
450 }
451
452 #[test]
453 fn test_event_move() {
454 let event = Event::Move {
455 timestamp: 3,
456 from_id: "x_0".to_string(),
457 to_name: "y".to_string(),
458 to_id: "y_1".to_string(),
459 };
460
461 assert_eq!(event.timestamp(), 3);
462 assert_eq!(event.var_name(), Some("y"));
463 assert!(event.is_move());
464 }
465
466 #[test]
467 fn test_event_drop() {
468 let event = Event::Drop {
469 timestamp: 4,
470 var_id: "x_0".to_string(),
471 };
472
473 assert_eq!(event.timestamp(), 4);
474 assert!(event.is_drop());
475 }
476
477 #[test]
478 fn test_event_serialization() {
479 let event = Event::New {
480 timestamp: 1,
481 var_name: "x".to_string(),
482 var_id: "x_0".to_string(),
483 type_name: "i32".to_string(),
484 };
485
486 let json = serde_json::to_string(&event).unwrap();
487 let deserialized: Event = serde_json::from_str(&json).unwrap();
488
489 assert_eq!(event, deserialized);
490 }
491
492 #[test]
493 fn test_borrow_mutable_flag() {
494 let immut = Event::Borrow {
495 timestamp: 1,
496 borrower_name: "r".to_string(),
497 borrower_id: "r_0".to_string(),
498 owner_id: "x_0".to_string(),
499 mutable: false,
500 };
501
502 let mut_borrow = Event::Borrow {
503 timestamp: 2,
504 borrower_name: "r".to_string(),
505 borrower_id: "r_1".to_string(),
506 owner_id: "x_0".to_string(),
507 mutable: true,
508 };
509
510 assert_ne!(immut, mut_borrow);
511 }
512}