borrowscope_runtime/
event.rs

1//! Event types for tracking ownership operations.
2//!
3//! This module defines the [`Event`] enum which represents all possible
4//! ownership and borrowing events that can be tracked at runtime.
5//!
6//! # Event Categories
7//!
8//! - **Basic ownership**: `New`, `Borrow`, `Move`, `Drop`
9//! - **Smart pointers**: `RcNew`, `RcClone`, `ArcNew`, `ArcClone`
10//! - **Box**: `BoxNew`, `BoxIntoRaw`, `BoxFromRaw`
11//! - **Weak references**: `WeakNew`, `WeakClone`, `WeakUpgrade`
12//! - **Pin**: `PinNew`, `PinIntoInner`
13//! - **Cow**: `CowBorrowed`, `CowOwned`, `CowToMut`
14//! - **Interior mutability**: `RefCellNew`, `RefCellBorrow`, `RefCellDrop`, `CellNew`, `CellGet`, `CellSet`
15//! - **OnceCell/OnceLock**: `OnceCellNew`, `OnceCellSet`, `OnceCellGet`, `OnceCellGetOrInit`
16//! - **MaybeUninit**: `MaybeUninitNew`, `MaybeUninitWrite`, `MaybeUninitAssumeInit`, `MaybeUninitAssumeInitRead`, `MaybeUninitAssumeInitDrop`
17//! - **Threads**: `ThreadSpawn`, `ThreadJoin`
18//! - **Channels**: `ChannelNew`, `ChannelSend`, `ChannelRecv`
19//! - **Lock guards**: `LockGuardNew`, `LockGuardDrop`
20//! - **Unsafe operations**: `RawPtrCreated`, `RawPtrDeref`, `UnsafeBlockEnter`, `UnsafeBlockExit`
21//!
22//! # Serialization
23//!
24//! All events serialize to JSON with a `type` tag for easy filtering.
25//!
26//! # Helper Methods
27//!
28//! Events provide helper methods for filtering by category:
29//!
30//! ```rust
31//! use borrowscope_runtime::*;
32//!
33//! reset();
34//! // ... tracking code ...
35//!
36//! for event in get_events() {
37//!     if event.is_box() { /* Box event */ }
38//!     if event.is_weak() { /* Weak reference event */ }
39//!     if event.is_pin() { /* Pin event */ }
40//!     if event.is_cow() { /* Cow event */ }
41//!     if event.is_thread() { /* Thread event */ }
42//!     if event.is_channel() { /* Channel event */ }
43//!     if event.is_once_cell() { /* OnceCell/OnceLock event */ }
44//!     if event.is_maybe_uninit() { /* MaybeUninit event */ }
45//!     if event.is_lock_guard() { /* Lock guard event */ }
46//! }
47//! ```
48
49use serde::{Deserialize, Serialize};
50
51/// An ownership or borrowing event recorded at runtime.
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53#[serde(tag = "type")]
54pub enum Event {
55    /// Variable created via [`track_new`](crate::track_new).
56    New {
57        timestamp: u64,
58        var_name: String,
59        var_id: String,
60        type_name: String,
61    },
62
63    /// Variable borrowed via [`track_borrow`](crate::track_borrow).
64    Borrow {
65        timestamp: u64,
66        borrower_name: String,
67        borrower_id: String,
68        owner_id: String,
69        mutable: bool,
70    },
71
72    /// Ownership moved via [`track_move`](crate::track_move).
73    Move {
74        timestamp: u64,
75        from_id: String,
76        to_name: String,
77        to_id: String,
78    },
79
80    /// Variable dropped via [`track_drop`](crate::track_drop).
81    Drop { timestamp: u64, var_id: String },
82
83    /// `Rc::new` allocation with reference counting.
84    RcNew {
85        timestamp: u64,
86        var_name: String,
87        var_id: String,
88        type_name: String,
89        strong_count: usize,
90        weak_count: usize,
91    },
92
93    /// `Rc::clone` operation (shared ownership).
94    RcClone {
95        timestamp: u64,
96        var_name: String,
97        var_id: String,
98        source_id: String,
99        strong_count: usize,
100        weak_count: usize,
101    },
102
103    /// Arc::new allocation with atomic reference counting
104    ArcNew {
105        timestamp: u64,
106        var_name: String,
107        var_id: String,
108        type_name: String,
109        strong_count: usize,
110        weak_count: usize,
111    },
112
113    /// Arc::clone operation (thread-safe shared ownership)
114    ArcClone {
115        timestamp: u64,
116        var_name: String,
117        var_id: String,
118        source_id: String,
119        strong_count: usize,
120        weak_count: usize,
121    },
122
123    /// RefCell::new allocation
124    RefCellNew {
125        timestamp: u64,
126        var_name: String,
127        var_id: String,
128        type_name: String,
129    },
130
131    /// RefCell::borrow or borrow_mut operation
132    RefCellBorrow {
133        timestamp: u64,
134        borrow_id: String,
135        refcell_id: String,
136        is_mutable: bool,
137        location: String,
138    },
139
140    /// RefCell borrow dropped (Ref/RefMut dropped)
141    RefCellDrop {
142        timestamp: u64,
143        borrow_id: String,
144        location: String,
145    },
146
147    /// Cell::new allocation
148    CellNew {
149        timestamp: u64,
150        var_name: String,
151        var_id: String,
152        type_name: String,
153    },
154
155    /// Cell::get operation
156    CellGet {
157        timestamp: u64,
158        cell_id: String,
159        location: String,
160    },
161
162    /// Cell::set operation
163    CellSet {
164        timestamp: u64,
165        cell_id: String,
166        location: String,
167    },
168
169    /// Static variable initialization
170    StaticInit {
171        timestamp: u64,
172        var_name: String,
173        var_id: String,
174        type_name: String,
175        is_mutable: bool,
176    },
177
178    /// Static variable access (read or write)
179    StaticAccess {
180        timestamp: u64,
181        var_id: String,
182        var_name: String,
183        is_write: bool,
184        location: String,
185    },
186
187    /// Const evaluation (compile-time constant)
188    ConstEval {
189        timestamp: u64,
190        const_name: String,
191        const_id: String,
192        type_name: String,
193        location: String,
194    },
195
196    /// Raw pointer created
197    RawPtrCreated {
198        timestamp: u64,
199        var_name: String,
200        var_id: String,
201        ptr_type: String,
202        address: usize,
203        location: String,
204    },
205
206    /// Raw pointer dereferenced
207    RawPtrDeref {
208        timestamp: u64,
209        ptr_id: String,
210        location: String,
211        is_write: bool,
212    },
213
214    /// Unsafe block entered
215    UnsafeBlockEnter {
216        timestamp: u64,
217        block_id: String,
218        location: String,
219    },
220
221    /// Unsafe block exited
222    UnsafeBlockExit {
223        timestamp: u64,
224        block_id: String,
225        location: String,
226    },
227
228    /// Unsafe function called
229    UnsafeFnCall {
230        timestamp: u64,
231        fn_name: String,
232        location: String,
233    },
234
235    /// FFI (Foreign Function Interface) call
236    FfiCall {
237        timestamp: u64,
238        fn_name: String,
239        location: String,
240    },
241
242    /// Transmute operation
243    Transmute {
244        timestamp: u64,
245        from_type: String,
246        to_type: String,
247        location: String,
248    },
249
250    /// Union field access
251    UnionFieldAccess {
252        timestamp: u64,
253        union_name: String,
254        field_name: String,
255        location: String,
256    },
257
258    /// Async block entered
259    AsyncBlockEnter {
260        timestamp: u64,
261        block_id: String,
262        location: String,
263    },
264
265    /// Async block exited
266    AsyncBlockExit {
267        timestamp: u64,
268        block_id: String,
269        location: String,
270    },
271
272    /// Await expression started
273    AwaitStart {
274        timestamp: u64,
275        await_id: String,
276        future_name: String,
277        location: String,
278    },
279
280    /// Await expression completed
281    AwaitEnd {
282        timestamp: u64,
283        await_id: String,
284        location: String,
285    },
286
287    // ========== Phase 5: Extended Tracking ==========
288
289    /// Loop entered (for, while, loop)
290    LoopEnter {
291        timestamp: u64,
292        loop_id: String,
293        loop_type: String,
294        location: String,
295    },
296
297    /// Loop iteration
298    LoopIteration {
299        timestamp: u64,
300        loop_id: String,
301        iteration: usize,
302        location: String,
303    },
304
305    /// Loop exited
306    LoopExit {
307        timestamp: u64,
308        loop_id: String,
309        location: String,
310    },
311
312    /// Match expression entered
313    MatchEnter {
314        timestamp: u64,
315        match_id: String,
316        location: String,
317    },
318
319    /// Match arm taken
320    MatchArm {
321        timestamp: u64,
322        match_id: String,
323        arm_index: usize,
324        pattern: String,
325        location: String,
326    },
327
328    /// Match expression exited
329    MatchExit {
330        timestamp: u64,
331        match_id: String,
332        location: String,
333    },
334
335    /// Branch taken (if/else)
336    Branch {
337        timestamp: u64,
338        branch_id: String,
339        branch_type: String,
340        location: String,
341    },
342
343    /// Return statement
344    Return {
345        timestamp: u64,
346        return_id: String,
347        has_value: bool,
348        location: String,
349    },
350
351    /// Try/? operator
352    Try {
353        timestamp: u64,
354        try_id: String,
355        location: String,
356    },
357
358    /// Index access (arr\[i\])
359    IndexAccess {
360        timestamp: u64,
361        access_id: String,
362        container: String,
363        location: String,
364    },
365
366    /// Field access (obj.field)
367    FieldAccess {
368        timestamp: u64,
369        access_id: String,
370        base: String,
371        field: String,
372        location: String,
373    },
374
375    /// Function call
376    Call {
377        timestamp: u64,
378        call_id: String,
379        fn_name: String,
380        location: String,
381    },
382
383    /// Lock acquired (Mutex/RwLock)
384    Lock {
385        timestamp: u64,
386        lock_id: String,
387        lock_type: String,
388        var_name: String,
389        location: String,
390    },
391
392    /// Unwrap called (Option/Result)
393    Unwrap {
394        timestamp: u64,
395        unwrap_id: String,
396        method: String,
397        var_name: String,
398        location: String,
399    },
400
401    /// Clone called
402    Clone {
403        timestamp: u64,
404        clone_id: String,
405        var_name: String,
406        location: String,
407    },
408
409    /// Dereference operation
410    Deref {
411        timestamp: u64,
412        deref_id: String,
413        var_name: String,
414        location: String,
415    },
416
417    // ========== Phase 6: Additional Tracking ==========
418
419    /// Break statement
420    Break {
421        timestamp: u64,
422        break_id: String,
423        loop_label: Option<String>,
424        location: String,
425    },
426
427    /// Continue statement
428    Continue {
429        timestamp: u64,
430        continue_id: String,
431        loop_label: Option<String>,
432        location: String,
433    },
434
435    /// Closure creation
436    ClosureCreate {
437        timestamp: u64,
438        closure_id: String,
439        capture_mode: String,
440        location: String,
441    },
442
443    /// Struct construction
444    StructCreate {
445        timestamp: u64,
446        struct_id: String,
447        type_name: String,
448        location: String,
449    },
450
451    /// Tuple construction
452    TupleCreate {
453        timestamp: u64,
454        tuple_id: String,
455        len: usize,
456        location: String,
457    },
458
459    /// Let-else pattern
460    LetElse {
461        timestamp: u64,
462        let_id: String,
463        pattern: String,
464        location: String,
465    },
466
467    /// Range expression
468    Range {
469        timestamp: u64,
470        range_id: String,
471        range_type: String,
472        location: String,
473    },
474
475    /// Binary operation
476    BinaryOp {
477        timestamp: u64,
478        op_id: String,
479        operator: String,
480        location: String,
481    },
482
483    /// Array creation
484    ArrayCreate {
485        timestamp: u64,
486        array_id: String,
487        len: usize,
488        location: String,
489    },
490
491    /// Type cast (non-pointer)
492    TypeCast {
493        timestamp: u64,
494        cast_id: String,
495        to_type: String,
496        location: String,
497    },
498
499    /// Region enter
500    RegionEnter {
501        timestamp: u64,
502        region_id: String,
503        name: String,
504        location: String,
505    },
506
507    /// Region exit
508    RegionExit {
509        timestamp: u64,
510        region_id: String,
511        location: String,
512    },
513
514    // =========================================================================
515    // Phase 8: Enhanced Tracking Events
516    // =========================================================================
517
518    /// Function entry
519    FnEnter {
520        timestamp: u64,
521        fn_id: String,
522        fn_name: String,
523        location: String,
524    },
525
526    /// Function exit
527    FnExit {
528        timestamp: u64,
529        fn_id: String,
530        fn_name: String,
531        location: String,
532    },
533
534    /// Closure variable capture
535    ClosureCapture {
536        timestamp: u64,
537        closure_id: String,
538        var_name: String,
539        capture_mode: String,
540        location: String,
541    },
542
543    // =========================================================================
544    // Phase 9: Extended Smart Pointer & Concurrency Tracking
545    // =========================================================================
546
547    /// Weak::new or Rc::downgrade
548    WeakNew {
549        timestamp: u64,
550        var_name: String,
551        var_id: String,
552        source_id: String,
553        weak_count: usize,
554        location: String,
555    },
556
557    /// Weak::clone
558    WeakClone {
559        timestamp: u64,
560        var_name: String,
561        var_id: String,
562        source_id: String,
563        weak_count: usize,
564        location: String,
565    },
566
567    /// Weak::upgrade attempt
568    WeakUpgrade {
569        timestamp: u64,
570        weak_id: String,
571        success: bool,
572        location: String,
573    },
574
575    /// Box::new allocation
576    BoxNew {
577        timestamp: u64,
578        var_name: String,
579        var_id: String,
580        type_name: String,
581        location: String,
582    },
583
584    /// Box::into_raw
585    BoxIntoRaw {
586        timestamp: u64,
587        box_id: String,
588        location: String,
589    },
590
591    /// Box::from_raw
592    BoxFromRaw {
593        timestamp: u64,
594        var_name: String,
595        var_id: String,
596        location: String,
597    },
598
599    /// Mutex/RwLock guard acquired
600    LockGuardAcquire {
601        timestamp: u64,
602        guard_id: String,
603        lock_id: String,
604        lock_type: String,
605        location: String,
606    },
607
608    /// Mutex/RwLock guard dropped
609    LockGuardDrop {
610        timestamp: u64,
611        guard_id: String,
612        location: String,
613    },
614
615    /// Pin::new
616    PinNew {
617        timestamp: u64,
618        var_name: String,
619        var_id: String,
620        location: String,
621    },
622
623    /// Pin::into_inner
624    PinIntoInner {
625        timestamp: u64,
626        pin_id: String,
627        location: String,
628    },
629
630    /// Cow::Borrowed
631    CowBorrowed {
632        timestamp: u64,
633        var_name: String,
634        var_id: String,
635        location: String,
636    },
637
638    /// Cow::Owned
639    CowOwned {
640        timestamp: u64,
641        var_name: String,
642        var_id: String,
643        location: String,
644    },
645
646    /// Cow::to_mut (clone-on-write triggered)
647    CowToMut {
648        timestamp: u64,
649        cow_id: String,
650        cloned: bool,
651        location: String,
652    },
653
654    /// Thread spawn
655    ThreadSpawn {
656        timestamp: u64,
657        thread_id: String,
658        location: String,
659    },
660
661    /// Thread join
662    ThreadJoin {
663        timestamp: u64,
664        thread_id: String,
665        location: String,
666    },
667
668    /// Channel sender created
669    ChannelSenderNew {
670        timestamp: u64,
671        sender_id: String,
672        channel_id: String,
673        location: String,
674    },
675
676    /// Channel receiver created
677    ChannelReceiverNew {
678        timestamp: u64,
679        receiver_id: String,
680        channel_id: String,
681        location: String,
682    },
683
684    /// Channel send
685    ChannelSend {
686        timestamp: u64,
687        sender_id: String,
688        location: String,
689    },
690
691    /// Channel receive
692    ChannelRecv {
693        timestamp: u64,
694        receiver_id: String,
695        success: bool,
696        location: String,
697    },
698
699    // =========================================================================
700    // OnceCell / OnceLock Events
701    // =========================================================================
702
703    /// OnceCell::new or OnceLock::new
704    OnceCellNew {
705        timestamp: u64,
706        var_name: String,
707        var_id: String,
708        cell_type: String, // "OnceCell" or "OnceLock"
709        location: String,
710    },
711
712    /// OnceCell::set or OnceLock::set
713    OnceCellSet {
714        timestamp: u64,
715        cell_id: String,
716        success: bool,
717        location: String,
718    },
719
720    /// OnceCell::get or OnceLock::get
721    OnceCellGet {
722        timestamp: u64,
723        cell_id: String,
724        was_initialized: bool,
725        location: String,
726    },
727
728    /// OnceCell::get_or_init or OnceLock::get_or_init
729    OnceCellGetOrInit {
730        timestamp: u64,
731        cell_id: String,
732        was_initialized: bool,
733        location: String,
734    },
735
736    // =========================================================================
737    // MaybeUninit Events
738    // =========================================================================
739
740    /// MaybeUninit::uninit or MaybeUninit::new
741    MaybeUninitNew {
742        timestamp: u64,
743        var_name: String,
744        var_id: String,
745        initialized: bool,
746        location: String,
747    },
748
749    /// MaybeUninit::write
750    MaybeUninitWrite {
751        timestamp: u64,
752        var_id: String,
753        location: String,
754    },
755
756    /// MaybeUninit::assume_init (unsafe)
757    MaybeUninitAssumeInit {
758        timestamp: u64,
759        var_id: String,
760        location: String,
761    },
762
763    /// MaybeUninit::assume_init_read (unsafe)
764    MaybeUninitAssumeInitRead {
765        timestamp: u64,
766        var_id: String,
767        location: String,
768    },
769
770    /// MaybeUninit::assume_init_drop (unsafe)
771    MaybeUninitAssumeInitDrop {
772        timestamp: u64,
773        var_id: String,
774        location: String,
775    },
776}
777
778impl Event {
779    /// Get the timestamp of this event
780    pub fn timestamp(&self) -> u64 {
781        match self {
782            Event::New { timestamp, .. }
783            | Event::Borrow { timestamp, .. }
784            | Event::Move { timestamp, .. }
785            | Event::Drop { timestamp, .. }
786            | Event::RcNew { timestamp, .. }
787            | Event::RcClone { timestamp, .. }
788            | Event::ArcNew { timestamp, .. }
789            | Event::ArcClone { timestamp, .. }
790            | Event::RefCellNew { timestamp, .. }
791            | Event::RefCellBorrow { timestamp, .. }
792            | Event::RefCellDrop { timestamp, .. }
793            | Event::CellNew { timestamp, .. }
794            | Event::CellGet { timestamp, .. }
795            | Event::CellSet { timestamp, .. }
796            | Event::StaticInit { timestamp, .. }
797            | Event::StaticAccess { timestamp, .. }
798            | Event::ConstEval { timestamp, .. }
799            | Event::RawPtrCreated { timestamp, .. }
800            | Event::RawPtrDeref { timestamp, .. }
801            | Event::UnsafeBlockEnter { timestamp, .. }
802            | Event::UnsafeBlockExit { timestamp, .. }
803            | Event::UnsafeFnCall { timestamp, .. }
804            | Event::FfiCall { timestamp, .. }
805            | Event::Transmute { timestamp, .. }
806            | Event::UnionFieldAccess { timestamp, .. }
807            | Event::AsyncBlockEnter { timestamp, .. }
808            | Event::AsyncBlockExit { timestamp, .. }
809            | Event::AwaitStart { timestamp, .. }
810            | Event::AwaitEnd { timestamp, .. }
811            | Event::LoopEnter { timestamp, .. }
812            | Event::LoopIteration { timestamp, .. }
813            | Event::LoopExit { timestamp, .. }
814            | Event::MatchEnter { timestamp, .. }
815            | Event::MatchArm { timestamp, .. }
816            | Event::MatchExit { timestamp, .. }
817            | Event::Branch { timestamp, .. }
818            | Event::Return { timestamp, .. }
819            | Event::Try { timestamp, .. }
820            | Event::IndexAccess { timestamp, .. }
821            | Event::FieldAccess { timestamp, .. }
822            | Event::Call { timestamp, .. }
823            | Event::Lock { timestamp, .. }
824            | Event::Unwrap { timestamp, .. }
825            | Event::Clone { timestamp, .. }
826            | Event::Deref { timestamp, .. }
827            | Event::Break { timestamp, .. }
828            | Event::Continue { timestamp, .. }
829            | Event::ClosureCreate { timestamp, .. }
830            | Event::StructCreate { timestamp, .. }
831            | Event::TupleCreate { timestamp, .. }
832            | Event::LetElse { timestamp, .. }
833            | Event::Range { timestamp, .. }
834            | Event::BinaryOp { timestamp, .. }
835            | Event::ArrayCreate { timestamp, .. }
836            | Event::TypeCast { timestamp, .. }
837            | Event::RegionEnter { timestamp, .. }
838            | Event::RegionExit { timestamp, .. }
839            | Event::FnEnter { timestamp, .. }
840            | Event::FnExit { timestamp, .. }
841            | Event::ClosureCapture { timestamp, .. }
842            | Event::WeakNew { timestamp, .. }
843            | Event::WeakClone { timestamp, .. }
844            | Event::WeakUpgrade { timestamp, .. }
845            | Event::BoxNew { timestamp, .. }
846            | Event::BoxIntoRaw { timestamp, .. }
847            | Event::BoxFromRaw { timestamp, .. }
848            | Event::LockGuardAcquire { timestamp, .. }
849            | Event::LockGuardDrop { timestamp, .. }
850            | Event::PinNew { timestamp, .. }
851            | Event::PinIntoInner { timestamp, .. }
852            | Event::CowBorrowed { timestamp, .. }
853            | Event::CowOwned { timestamp, .. }
854            | Event::CowToMut { timestamp, .. }
855            | Event::ThreadSpawn { timestamp, .. }
856            | Event::ThreadJoin { timestamp, .. }
857            | Event::ChannelSenderNew { timestamp, .. }
858            | Event::ChannelReceiverNew { timestamp, .. }
859            | Event::ChannelSend { timestamp, .. }
860            | Event::ChannelRecv { timestamp, .. }
861            | Event::OnceCellNew { timestamp, .. }
862            | Event::OnceCellSet { timestamp, .. }
863            | Event::OnceCellGet { timestamp, .. }
864            | Event::OnceCellGetOrInit { timestamp, .. }
865            | Event::MaybeUninitNew { timestamp, .. }
866            | Event::MaybeUninitWrite { timestamp, .. }
867            | Event::MaybeUninitAssumeInit { timestamp, .. }
868            | Event::MaybeUninitAssumeInitRead { timestamp, .. }
869            | Event::MaybeUninitAssumeInitDrop { timestamp, .. } => *timestamp,
870        }
871    }
872
873    /// Get the variable name (if applicable)
874    pub fn var_name(&self) -> Option<&str> {
875        match self {
876            Event::New { var_name, .. }
877            | Event::RcNew { var_name, .. }
878            | Event::RcClone { var_name, .. }
879            | Event::ArcNew { var_name, .. }
880            | Event::ArcClone { var_name, .. }
881            | Event::RefCellNew { var_name, .. }
882            | Event::CellNew { var_name, .. }
883            | Event::StaticInit { var_name, .. }
884            | Event::StaticAccess { var_name, .. }
885            | Event::RawPtrCreated { var_name, .. }
886            | Event::ConstEval {
887                const_name: var_name,
888                ..
889            } => Some(var_name),
890            Event::Borrow { borrower_name, .. } => Some(borrower_name),
891            Event::Move { to_name, .. } => Some(to_name),
892            Event::Drop { var_id, .. } => Some(var_id),
893            Event::RefCellBorrow { .. }
894            | Event::RefCellDrop { .. }
895            | Event::CellGet { .. }
896            | Event::CellSet { .. }
897            | Event::RawPtrDeref { .. }
898            | Event::UnsafeBlockEnter { .. }
899            | Event::UnsafeBlockExit { .. }
900            | Event::UnsafeFnCall { .. }
901            | Event::FfiCall { .. }
902            | Event::Transmute { .. }
903            | Event::UnionFieldAccess { .. }
904            | Event::AsyncBlockEnter { .. }
905            | Event::AsyncBlockExit { .. }
906            | Event::AwaitStart { .. }
907            | Event::AwaitEnd { .. }
908            | Event::LoopEnter { .. }
909            | Event::LoopIteration { .. }
910            | Event::LoopExit { .. }
911            | Event::MatchEnter { .. }
912            | Event::MatchArm { .. }
913            | Event::MatchExit { .. }
914            | Event::Branch { .. }
915            | Event::Return { .. }
916            | Event::Try { .. }
917            | Event::IndexAccess { .. }
918            | Event::FieldAccess { .. }
919            | Event::Call { .. }
920            | Event::Lock { .. }
921            | Event::Unwrap { .. }
922            | Event::Clone { .. }
923            | Event::Deref { .. }
924            | Event::Break { .. }
925            | Event::Continue { .. }
926            | Event::ClosureCreate { .. }
927            | Event::StructCreate { .. }
928            | Event::TupleCreate { .. }
929            | Event::LetElse { .. }
930            | Event::Range { .. }
931            | Event::BinaryOp { .. }
932            | Event::ArrayCreate { .. }
933            | Event::TypeCast { .. }
934            | Event::RegionEnter { .. }
935            | Event::RegionExit { .. }
936            | Event::FnEnter { .. }
937            | Event::FnExit { .. }
938            | Event::ClosureCapture { .. }
939            | Event::WeakUpgrade { .. }
940            | Event::BoxIntoRaw { .. }
941            | Event::LockGuardAcquire { .. }
942            | Event::LockGuardDrop { .. }
943            | Event::PinIntoInner { .. }
944            | Event::CowToMut { .. }
945            | Event::ThreadSpawn { .. }
946            | Event::ThreadJoin { .. }
947            | Event::ChannelSend { .. }
948            | Event::ChannelRecv { .. }
949            | Event::OnceCellSet { .. }
950            | Event::OnceCellGet { .. }
951            | Event::OnceCellGetOrInit { .. }
952            | Event::MaybeUninitWrite { .. }
953            | Event::MaybeUninitAssumeInit { .. }
954            | Event::MaybeUninitAssumeInitRead { .. }
955            | Event::MaybeUninitAssumeInitDrop { .. } => None,
956            Event::WeakNew { var_name, .. }
957            | Event::WeakClone { var_name, .. }
958            | Event::BoxNew { var_name, .. }
959            | Event::BoxFromRaw { var_name, .. }
960            | Event::PinNew { var_name, .. }
961            | Event::CowBorrowed { var_name, .. }
962            | Event::CowOwned { var_name, .. }
963            | Event::OnceCellNew { var_name, .. }
964            | Event::MaybeUninitNew { var_name, .. } => Some(var_name),
965            Event::ChannelSenderNew { sender_id, .. } => Some(sender_id),
966            Event::ChannelReceiverNew { receiver_id, .. } => Some(receiver_id),
967        }
968    }
969
970    /// Check if this is a New event
971    pub fn is_new(&self) -> bool {
972        matches!(self, Event::New { .. })
973    }
974
975    /// Check if this is a Borrow event
976    pub fn is_borrow(&self) -> bool {
977        matches!(self, Event::Borrow { .. })
978    }
979
980    /// Check if this is a Move event
981    pub fn is_move(&self) -> bool {
982        matches!(self, Event::Move { .. })
983    }
984
985    /// Check if this is a Drop event
986    pub fn is_drop(&self) -> bool {
987        matches!(self, Event::Drop { .. })
988    }
989
990    /// Check if this is an Rc event (new or clone)
991    pub fn is_rc(&self) -> bool {
992        matches!(self, Event::RcNew { .. } | Event::RcClone { .. })
993    }
994
995    /// Check if this is an Arc event (new or clone)
996    pub fn is_arc(&self) -> bool {
997        matches!(self, Event::ArcNew { .. } | Event::ArcClone { .. })
998    }
999
1000    /// Check if this is a reference-counted event
1001    pub fn is_refcounted(&self) -> bool {
1002        self.is_rc() || self.is_arc()
1003    }
1004
1005    /// Check if this is a RefCell event
1006    pub fn is_refcell(&self) -> bool {
1007        matches!(
1008            self,
1009            Event::RefCellNew { .. } | Event::RefCellBorrow { .. } | Event::RefCellDrop { .. }
1010        )
1011    }
1012
1013    /// Check if this is a Cell event
1014    pub fn is_cell(&self) -> bool {
1015        matches!(
1016            self,
1017            Event::CellNew { .. } | Event::CellGet { .. } | Event::CellSet { .. }
1018        )
1019    }
1020
1021    /// Check if this is an interior mutability event
1022    pub fn is_interior_mutability(&self) -> bool {
1023        self.is_refcell() || self.is_cell()
1024    }
1025
1026    /// Check if this is a static event
1027    pub fn is_static(&self) -> bool {
1028        matches!(self, Event::StaticInit { .. } | Event::StaticAccess { .. })
1029    }
1030
1031    /// Check if this is a const event
1032    pub fn is_const(&self) -> bool {
1033        matches!(self, Event::ConstEval { .. })
1034    }
1035
1036    /// Check if this is a global variable event (static or const)
1037    pub fn is_global(&self) -> bool {
1038        self.is_static() || self.is_const()
1039    }
1040
1041    /// Check if this is an unsafe event
1042    pub fn is_unsafe(&self) -> bool {
1043        matches!(
1044            self,
1045            Event::RawPtrCreated { .. }
1046                | Event::RawPtrDeref { .. }
1047                | Event::UnsafeBlockEnter { .. }
1048                | Event::UnsafeBlockExit { .. }
1049                | Event::UnsafeFnCall { .. }
1050                | Event::FfiCall { .. }
1051                | Event::Transmute { .. }
1052                | Event::UnionFieldAccess { .. }
1053        )
1054    }
1055
1056    /// Check if this is a raw pointer event
1057    pub fn is_raw_ptr(&self) -> bool {
1058        matches!(
1059            self,
1060            Event::RawPtrCreated { .. } | Event::RawPtrDeref { .. }
1061        )
1062    }
1063
1064    /// Check if this is an FFI event
1065    pub fn is_ffi(&self) -> bool {
1066        matches!(self, Event::FfiCall { .. })
1067    }
1068
1069    /// Get strong count if this is a reference-counted event
1070    pub fn strong_count(&self) -> Option<usize> {
1071        match self {
1072            Event::RcNew { strong_count, .. }
1073            | Event::RcClone { strong_count, .. }
1074            | Event::ArcNew { strong_count, .. }
1075            | Event::ArcClone { strong_count, .. } => Some(*strong_count),
1076            _ => None,
1077        }
1078    }
1079
1080    /// Get weak count if this is a reference-counted event
1081    pub fn weak_count(&self) -> Option<usize> {
1082        match self {
1083            Event::RcNew { weak_count, .. }
1084            | Event::RcClone { weak_count, .. }
1085            | Event::ArcNew { weak_count, .. }
1086            | Event::ArcClone { weak_count, .. }
1087            | Event::WeakNew { weak_count, .. }
1088            | Event::WeakClone { weak_count, .. } => Some(*weak_count),
1089            _ => None,
1090        }
1091    }
1092
1093    /// Check if this is a Weak reference event
1094    pub fn is_weak(&self) -> bool {
1095        matches!(
1096            self,
1097            Event::WeakNew { .. } | Event::WeakClone { .. } | Event::WeakUpgrade { .. }
1098        )
1099    }
1100
1101    /// Check if this is a Box event
1102    pub fn is_box(&self) -> bool {
1103        matches!(
1104            self,
1105            Event::BoxNew { .. } | Event::BoxIntoRaw { .. } | Event::BoxFromRaw { .. }
1106        )
1107    }
1108
1109    /// Check if this is a lock guard event
1110    pub fn is_lock_guard(&self) -> bool {
1111        matches!(
1112            self,
1113            Event::LockGuardAcquire { .. } | Event::LockGuardDrop { .. }
1114        )
1115    }
1116
1117    /// Check if this is a Pin event
1118    pub fn is_pin(&self) -> bool {
1119        matches!(self, Event::PinNew { .. } | Event::PinIntoInner { .. })
1120    }
1121
1122    /// Check if this is a Cow event
1123    pub fn is_cow(&self) -> bool {
1124        matches!(
1125            self,
1126            Event::CowBorrowed { .. } | Event::CowOwned { .. } | Event::CowToMut { .. }
1127        )
1128    }
1129
1130    /// Check if this is a thread event
1131    pub fn is_thread(&self) -> bool {
1132        matches!(self, Event::ThreadSpawn { .. } | Event::ThreadJoin { .. })
1133    }
1134
1135    /// Check if this is a channel event
1136    pub fn is_channel(&self) -> bool {
1137        matches!(
1138            self,
1139            Event::ChannelSenderNew { .. }
1140                | Event::ChannelReceiverNew { .. }
1141                | Event::ChannelSend { .. }
1142                | Event::ChannelRecv { .. }
1143        )
1144    }
1145
1146    /// Check if this is a OnceCell/OnceLock event
1147    pub fn is_once_cell(&self) -> bool {
1148        matches!(
1149            self,
1150            Event::OnceCellNew { .. }
1151                | Event::OnceCellSet { .. }
1152                | Event::OnceCellGet { .. }
1153                | Event::OnceCellGetOrInit { .. }
1154        )
1155    }
1156
1157    /// Check if this is a MaybeUninit event
1158    pub fn is_maybe_uninit(&self) -> bool {
1159        matches!(
1160            self,
1161            Event::MaybeUninitNew { .. }
1162                | Event::MaybeUninitWrite { .. }
1163                | Event::MaybeUninitAssumeInit { .. }
1164                | Event::MaybeUninitAssumeInitRead { .. }
1165                | Event::MaybeUninitAssumeInitDrop { .. }
1166        )
1167    }
1168}
1169
1170#[cfg(test)]
1171mod tests {
1172    use super::*;
1173
1174    #[test]
1175    fn test_event_new() {
1176        let event = Event::New {
1177            timestamp: 1,
1178            var_name: "x".to_string(),
1179            var_id: "x_0".to_string(),
1180            type_name: "i32".to_string(),
1181        };
1182
1183        assert_eq!(event.timestamp(), 1);
1184        assert_eq!(event.var_name(), Some("x"));
1185        assert!(event.is_new());
1186        assert!(!event.is_borrow());
1187        assert!(!event.is_move());
1188        assert!(!event.is_drop());
1189    }
1190
1191    #[test]
1192    fn test_event_borrow() {
1193        let event = Event::Borrow {
1194            timestamp: 2,
1195            borrower_name: "r".to_string(),
1196            borrower_id: "r_1".to_string(),
1197            owner_id: "x_0".to_string(),
1198            mutable: false,
1199        };
1200
1201        assert_eq!(event.timestamp(), 2);
1202        assert_eq!(event.var_name(), Some("r"));
1203        assert!(event.is_borrow());
1204        assert!(!event.is_new());
1205    }
1206
1207    #[test]
1208    fn test_event_move() {
1209        let event = Event::Move {
1210            timestamp: 3,
1211            from_id: "x_0".to_string(),
1212            to_name: "y".to_string(),
1213            to_id: "y_1".to_string(),
1214        };
1215
1216        assert_eq!(event.timestamp(), 3);
1217        assert_eq!(event.var_name(), Some("y"));
1218        assert!(event.is_move());
1219    }
1220
1221    #[test]
1222    fn test_event_drop() {
1223        let event = Event::Drop {
1224            timestamp: 4,
1225            var_id: "x_0".to_string(),
1226        };
1227
1228        assert_eq!(event.timestamp(), 4);
1229        assert!(event.is_drop());
1230    }
1231
1232    #[test]
1233    fn test_event_serialization() {
1234        let event = Event::New {
1235            timestamp: 1,
1236            var_name: "x".to_string(),
1237            var_id: "x_0".to_string(),
1238            type_name: "i32".to_string(),
1239        };
1240
1241        let json = serde_json::to_string(&event).unwrap();
1242        let deserialized: Event = serde_json::from_str(&json).unwrap();
1243
1244        assert_eq!(event, deserialized);
1245    }
1246
1247    #[test]
1248    fn test_borrow_mutable_flag() {
1249        let immut = Event::Borrow {
1250            timestamp: 1,
1251            borrower_name: "r".to_string(),
1252            borrower_id: "r_0".to_string(),
1253            owner_id: "x_0".to_string(),
1254            mutable: false,
1255        };
1256
1257        let mut_borrow = Event::Borrow {
1258            timestamp: 2,
1259            borrower_name: "r".to_string(),
1260            borrower_id: "r_1".to_string(),
1261            owner_id: "x_0".to_string(),
1262            mutable: true,
1263        };
1264
1265        assert_ne!(immut, mut_borrow);
1266    }
1267}