borrowscope_runtime/
tracker.rs

1//! Core tracking functionality for recording ownership and borrowing events.
2//!
3//! This module provides the public API for tracking Rust ownership operations at runtime.
4//! All tracking functions are designed to be zero-cost when the `track` feature is disabled.
5//!
6//! # Overview
7//!
8//! The tracker records events for:
9//! - **Basic ownership**: variable creation, borrowing, moves, and drops
10//! - **Smart pointers**: `Rc` and `Arc` creation and cloning
11//! - **Interior mutability**: `RefCell` and `Cell` operations
12//! - **Unsafe code**: raw pointers, unsafe blocks, FFI calls, transmute
13//! - **Static/const**: static variable access and const evaluation
14//!
15//! # Quick Start
16//!
17//! ```rust
18//! use borrowscope_runtime::*;
19//!
20//! // Always reset before tracking a new session
21//! reset();
22//!
23//! // Track variable creation - returns the value unchanged
24//! let data = track_new("data", vec![1, 2, 3]);
25//!
26//! // Track borrowing - returns the reference unchanged
27//! let r = track_borrow("r", &data);
28//! println!("{:?}", r);
29//!
30//! // Track drops explicitly
31//! track_drop("r");
32//! track_drop("data");
33//!
34//! // Retrieve all recorded events
35//! let events = get_events();
36//! assert_eq!(events.len(), 4); // New, Borrow, Drop, Drop
37//! ```
38//!
39//! # Feature Flags
40//!
41//! - `track` - Enables runtime tracking. Without this feature, all tracking
42//!   functions compile to no-ops that simply return their input values.
43//!
44//! # Thread Safety
45//!
46//! All tracking functions are thread-safe. The global tracker uses a mutex
47//! to ensure consistent event ordering across threads.
48//!
49//! # Performance
50//!
51//! With `track` enabled: ~75-80ns per tracking call.
52//! Without `track`: zero overhead (functions are inlined away).
53
54use crate::event::Event;
55use lazy_static::lazy_static;
56use parking_lot::Mutex;
57use std::sync::atomic::{AtomicU64, Ordering};
58
59lazy_static! {
60    /// Global tracker instance
61    static ref TRACKER: Mutex<Tracker> = Mutex::new(Tracker::new());
62}
63
64/// Global timestamp counter
65static TIMESTAMP: AtomicU64 = AtomicU64::new(0);
66
67/// The main tracker that records events
68pub struct Tracker {
69    /// All recorded events
70    events: Vec<Event>,
71
72    /// Counter for generating unique variable IDs
73    var_counter: u64,
74}
75
76impl Tracker {
77    /// Create a new tracker
78    pub fn new() -> Self {
79        Self {
80            events: Vec::new(),
81            var_counter: 0,
82        }
83    }
84
85    /// Generate next timestamp
86    fn next_timestamp() -> u64 {
87        TIMESTAMP.fetch_add(1, Ordering::Relaxed)
88    }
89
90    /// Generate unique variable ID
91    fn next_var_id(&mut self, name: &str) -> String {
92        let id = format!("{}_{}", name, self.var_counter);
93        self.var_counter += 1;
94        id
95    }
96
97    /// Record a New event
98    #[cfg_attr(not(feature = "track"), allow(dead_code))]
99    pub fn record_new(&mut self, var_name: &str, type_name: &str) -> String {
100        let timestamp = Self::next_timestamp();
101        let var_id = self.next_var_id(var_name);
102
103        self.events.push(Event::New {
104            timestamp,
105            var_name: var_name.to_string(),
106            var_id: var_id.clone(),
107            type_name: type_name.to_string(),
108        });
109
110        var_id
111    }
112
113    /// Record a Borrow event
114    #[cfg_attr(not(feature = "track"), allow(dead_code))]
115    pub fn record_borrow(&mut self, borrower_name: &str, owner_id: &str, mutable: bool) -> String {
116        let timestamp = Self::next_timestamp();
117        let borrower_id = self.next_var_id(borrower_name);
118
119        self.events.push(Event::Borrow {
120            timestamp,
121            borrower_name: borrower_name.to_string(),
122            borrower_id: borrower_id.clone(),
123            owner_id: owner_id.to_string(),
124            mutable,
125        });
126
127        borrower_id
128    }
129
130    /// Record a Move event
131    #[allow(dead_code)]
132    pub fn record_move(&mut self, from_id: &str, to_name: &str) -> String {
133        let timestamp = Self::next_timestamp();
134        let to_id = self.next_var_id(to_name);
135
136        self.events.push(Event::Move {
137            timestamp,
138            from_id: from_id.to_string(),
139            to_name: to_name.to_string(),
140            to_id: to_id.clone(),
141        });
142
143        to_id
144    }
145
146    /// Record a Drop event
147    #[cfg_attr(not(feature = "track"), allow(dead_code))]
148    pub fn record_drop(&mut self, var_id: &str) {
149        let timestamp = Self::next_timestamp();
150
151        self.events.push(Event::Drop {
152            timestamp,
153            var_id: var_id.to_string(),
154        });
155    }
156
157    /// Record an Rc::new event
158    #[cfg_attr(not(feature = "track"), allow(dead_code))]
159    pub fn record_rc_new(
160        &mut self,
161        var_name: &str,
162        strong_count: usize,
163        weak_count: usize,
164    ) -> String {
165        let timestamp = Self::next_timestamp();
166        let var_id = self.next_var_id(var_name);
167
168        self.events.push(Event::RcNew {
169            timestamp,
170            var_name: var_name.to_string(),
171            var_id: var_id.clone(),
172            type_name: "Rc<T>".to_string(),
173            strong_count,
174            weak_count,
175        });
176
177        var_id
178    }
179
180    /// Record an Rc::clone event
181    #[cfg_attr(not(feature = "track"), allow(dead_code))]
182    pub fn record_rc_clone(
183        &mut self,
184        var_name: &str,
185        source_name: &str,
186        strong_count: usize,
187        weak_count: usize,
188    ) -> String {
189        let timestamp = Self::next_timestamp();
190        let var_id = self.next_var_id(var_name);
191
192        self.events.push(Event::RcClone {
193            timestamp,
194            var_name: var_name.to_string(),
195            var_id: var_id.clone(),
196            source_id: source_name.to_string(),
197            strong_count,
198            weak_count,
199        });
200
201        var_id
202    }
203
204    /// Record an Arc::new event
205    #[cfg_attr(not(feature = "track"), allow(dead_code))]
206    pub fn record_arc_new(
207        &mut self,
208        var_name: &str,
209        strong_count: usize,
210        weak_count: usize,
211    ) -> String {
212        let timestamp = Self::next_timestamp();
213        let var_id = self.next_var_id(var_name);
214
215        self.events.push(Event::ArcNew {
216            timestamp,
217            var_name: var_name.to_string(),
218            var_id: var_id.clone(),
219            type_name: "Arc<T>".to_string(),
220            strong_count,
221            weak_count,
222        });
223
224        var_id
225    }
226
227    /// Record an Arc::clone event
228    #[cfg_attr(not(feature = "track"), allow(dead_code))]
229    pub fn record_arc_clone(
230        &mut self,
231        var_name: &str,
232        source_name: &str,
233        strong_count: usize,
234        weak_count: usize,
235    ) -> String {
236        let timestamp = Self::next_timestamp();
237        let var_id = self.next_var_id(var_name);
238
239        self.events.push(Event::ArcClone {
240            timestamp,
241            var_name: var_name.to_string(),
242            var_id: var_id.clone(),
243            source_id: source_name.to_string(),
244            strong_count,
245            weak_count,
246        });
247
248        var_id
249    }
250
251    /// Record a New event with explicit ID and location (advanced API)
252    #[cfg_attr(not(feature = "track"), allow(dead_code))]
253    pub fn record_new_with_id(
254        &mut self,
255        id: usize,
256        var_name: &str,
257        type_name: &str,
258        location: &str,
259    ) -> String {
260        let timestamp = Self::next_timestamp();
261        let var_id = format!("{}_{}", var_name, id);
262
263        self.events.push(Event::New {
264            timestamp,
265            var_name: var_name.to_string(),
266            var_id: var_id.clone(),
267            type_name: format!("{} @ {}", type_name, location),
268        });
269
270        var_id
271    }
272
273    /// Record a Borrow event with explicit IDs and location (advanced API)
274    #[cfg_attr(not(feature = "track"), allow(dead_code))]
275    pub fn record_borrow_with_id(
276        &mut self,
277        borrower_id: usize,
278        owner_id: usize,
279        borrower_name: &str,
280        location: &str,
281        mutable: bool,
282    ) -> String {
283        let timestamp = Self::next_timestamp();
284        let borrower_var_id = format!("{}_{}", borrower_name, borrower_id);
285        let owner_var_id = format!("owner_{}", owner_id);
286
287        self.events.push(Event::Borrow {
288            timestamp,
289            borrower_name: format!("{} @ {}", borrower_name, location),
290            borrower_id: borrower_var_id.clone(),
291            owner_id: owner_var_id,
292            mutable,
293        });
294
295        borrower_var_id
296    }
297
298    /// Record a Move event with explicit IDs and location (advanced API)
299    #[allow(dead_code)]
300    pub fn record_move_with_id(
301        &mut self,
302        from_id: usize,
303        to_id: usize,
304        to_name: &str,
305        location: &str,
306    ) -> String {
307        let timestamp = Self::next_timestamp();
308        let from_var_id = format!("var_{}", from_id);
309        let to_var_id = format!("{}_{}", to_name, to_id);
310
311        self.events.push(Event::Move {
312            timestamp,
313            from_id: from_var_id,
314            to_name: format!("{} @ {}", to_name, location),
315            to_id: to_var_id.clone(),
316        });
317
318        to_var_id
319    }
320
321    /// Record a Drop event with explicit ID and location (advanced API)
322    #[cfg_attr(not(feature = "track"), allow(dead_code))]
323    pub fn record_drop_with_id(&mut self, id: usize, location: &str) {
324        let timestamp = Self::next_timestamp();
325        let var_id = format!("var_{} @ {}", id, location);
326
327        self.events.push(Event::Drop { timestamp, var_id });
328    }
329
330    /// Record an Rc::new event with explicit ID and location (advanced API)
331    #[cfg_attr(not(feature = "track"), allow(dead_code))]
332    pub fn record_rc_new_with_id(
333        &mut self,
334        id: usize,
335        var_name: &str,
336        type_name: &str,
337        location: &str,
338        strong_count: usize,
339        weak_count: usize,
340    ) -> String {
341        let timestamp = Self::next_timestamp();
342        let var_id = format!("{}_{}", var_name, id);
343
344        self.events.push(Event::RcNew {
345            timestamp,
346            var_name: var_name.to_string(),
347            var_id: var_id.clone(),
348            type_name: format!("{} @ {}", type_name, location),
349            strong_count,
350            weak_count,
351        });
352
353        var_id
354    }
355
356    /// Record an Rc::clone event with explicit IDs and location (advanced API)
357    #[cfg_attr(not(feature = "track"), allow(dead_code))]
358    pub fn record_rc_clone_with_id(
359        &mut self,
360        new_id: usize,
361        source_id: usize,
362        var_name: &str,
363        location: &str,
364        strong_count: usize,
365        weak_count: usize,
366    ) -> String {
367        let timestamp = Self::next_timestamp();
368        let var_id = format!("{}_{}", var_name, new_id);
369        let source_var_id = format!("var_{}", source_id);
370
371        self.events.push(Event::RcClone {
372            timestamp,
373            var_name: format!("{} @ {}", var_name, location),
374            var_id: var_id.clone(),
375            source_id: source_var_id,
376            strong_count,
377            weak_count,
378        });
379
380        var_id
381    }
382
383    /// Record an Arc::new event with explicit ID and location (advanced API)
384    #[cfg_attr(not(feature = "track"), allow(dead_code))]
385    pub fn record_arc_new_with_id(
386        &mut self,
387        id: usize,
388        var_name: &str,
389        type_name: &str,
390        location: &str,
391        strong_count: usize,
392        weak_count: usize,
393    ) -> String {
394        let timestamp = Self::next_timestamp();
395        let var_id = format!("{}_{}", var_name, id);
396
397        self.events.push(Event::ArcNew {
398            timestamp,
399            var_name: var_name.to_string(),
400            var_id: var_id.clone(),
401            type_name: format!("{} @ {}", type_name, location),
402            strong_count,
403            weak_count,
404        });
405
406        var_id
407    }
408
409    /// Record an Arc::clone event with explicit IDs and location (advanced API)
410    #[cfg_attr(not(feature = "track"), allow(dead_code))]
411    pub fn record_arc_clone_with_id(
412        &mut self,
413        new_id: usize,
414        source_id: usize,
415        var_name: &str,
416        location: &str,
417        strong_count: usize,
418        weak_count: usize,
419    ) -> String {
420        let timestamp = Self::next_timestamp();
421        let var_id = format!("{}_{}", var_name, new_id);
422        let source_var_id = format!("var_{}", source_id);
423
424        self.events.push(Event::ArcClone {
425            timestamp,
426            var_name: format!("{} @ {}", var_name, location),
427            var_id: var_id.clone(),
428            source_id: source_var_id,
429            strong_count,
430            weak_count,
431        });
432
433        var_id
434    }
435
436    /// Record RefCell::new
437    pub fn record_refcell_new(&mut self, var_name: &str) -> String {
438        let timestamp = Self::next_timestamp();
439        let var_id = format!("refcell_{}", var_name);
440
441        self.events.push(Event::RefCellNew {
442            timestamp,
443            var_name: var_name.to_string(),
444            var_id: var_id.clone(),
445            type_name: "RefCell<T>".to_string(),
446        });
447
448        var_id
449    }
450
451    /// Record RefCell::borrow or borrow_mut
452    pub fn record_refcell_borrow(
453        &mut self,
454        borrow_id: &str,
455        refcell_id: &str,
456        is_mutable: bool,
457        location: &str,
458    ) {
459        let timestamp = Self::next_timestamp();
460
461        self.events.push(Event::RefCellBorrow {
462            timestamp,
463            borrow_id: borrow_id.to_string(),
464            refcell_id: refcell_id.to_string(),
465            is_mutable,
466            location: location.to_string(),
467        });
468    }
469
470    /// Record RefCell borrow drop
471    pub fn record_refcell_drop(&mut self, borrow_id: &str, location: &str) {
472        let timestamp = Self::next_timestamp();
473
474        self.events.push(Event::RefCellDrop {
475            timestamp,
476            borrow_id: borrow_id.to_string(),
477            location: location.to_string(),
478        });
479    }
480
481    /// Record Cell::new
482    pub fn record_cell_new(&mut self, var_name: &str) -> String {
483        let timestamp = Self::next_timestamp();
484        let var_id = format!("cell_{}", var_name);
485
486        self.events.push(Event::CellNew {
487            timestamp,
488            var_name: var_name.to_string(),
489            var_id: var_id.clone(),
490            type_name: "Cell<T>".to_string(),
491        });
492
493        var_id
494    }
495
496    /// Record Cell::get
497    pub fn record_cell_get(&mut self, cell_id: &str, location: &str) {
498        let timestamp = Self::next_timestamp();
499
500        self.events.push(Event::CellGet {
501            timestamp,
502            cell_id: cell_id.to_string(),
503            location: location.to_string(),
504        });
505    }
506
507    /// Record Cell::set
508    pub fn record_cell_set(&mut self, cell_id: &str, location: &str) {
509        let timestamp = Self::next_timestamp();
510
511        self.events.push(Event::CellSet {
512            timestamp,
513            cell_id: cell_id.to_string(),
514            location: location.to_string(),
515        });
516    }
517
518    /// Record static variable initialization
519    pub fn record_static_init(
520        &mut self,
521        var_name: &str,
522        var_id: usize,
523        type_name: &str,
524        is_mutable: bool,
525    ) {
526        let timestamp = Self::next_timestamp();
527
528        self.events.push(Event::StaticInit {
529            timestamp,
530            var_name: var_name.to_string(),
531            var_id: var_id.to_string(),
532            type_name: type_name.to_string(),
533            is_mutable,
534        });
535    }
536
537    /// Record static variable access
538    pub fn record_static_access(
539        &mut self,
540        var_id: usize,
541        var_name: &str,
542        is_write: bool,
543        location: &str,
544    ) {
545        let timestamp = Self::next_timestamp();
546
547        self.events.push(Event::StaticAccess {
548            timestamp,
549            var_id: var_id.to_string(),
550            var_name: var_name.to_string(),
551            is_write,
552            location: location.to_string(),
553        });
554    }
555
556    /// Record const evaluation
557    pub fn record_const_eval(
558        &mut self,
559        const_name: &str,
560        const_id: usize,
561        type_name: &str,
562        location: &str,
563    ) {
564        let timestamp = Self::next_timestamp();
565
566        self.events.push(Event::ConstEval {
567            timestamp,
568            const_name: const_name.to_string(),
569            const_id: const_id.to_string(),
570            type_name: type_name.to_string(),
571            location: location.to_string(),
572        });
573    }
574
575    /// Record raw pointer creation
576    pub fn record_raw_ptr_created(
577        &mut self,
578        var_name: &str,
579        var_id: usize,
580        ptr_type: &str,
581        address: usize,
582        location: &str,
583    ) {
584        let timestamp = Self::next_timestamp();
585
586        self.events.push(Event::RawPtrCreated {
587            timestamp,
588            var_name: var_name.to_string(),
589            var_id: var_id.to_string(),
590            ptr_type: ptr_type.to_string(),
591            address,
592            location: location.to_string(),
593        });
594    }
595
596    /// Record raw pointer dereference
597    pub fn record_raw_ptr_deref(&mut self, ptr_id: usize, location: &str, is_write: bool) {
598        let timestamp = Self::next_timestamp();
599
600        self.events.push(Event::RawPtrDeref {
601            timestamp,
602            ptr_id: ptr_id.to_string(),
603            location: location.to_string(),
604            is_write,
605        });
606    }
607
608    /// Record unsafe block entry
609    pub fn record_unsafe_block_enter(&mut self, block_id: usize, location: &str) {
610        let timestamp = Self::next_timestamp();
611
612        self.events.push(Event::UnsafeBlockEnter {
613            timestamp,
614            block_id: block_id.to_string(),
615            location: location.to_string(),
616        });
617    }
618
619    /// Record unsafe block exit
620    pub fn record_unsafe_block_exit(&mut self, block_id: usize, location: &str) {
621        let timestamp = Self::next_timestamp();
622
623        self.events.push(Event::UnsafeBlockExit {
624            timestamp,
625            block_id: block_id.to_string(),
626            location: location.to_string(),
627        });
628    }
629
630    /// Record unsafe function call
631    pub fn record_unsafe_fn_call(&mut self, fn_name: &str, location: &str) {
632        let timestamp = Self::next_timestamp();
633
634        self.events.push(Event::UnsafeFnCall {
635            timestamp,
636            fn_name: fn_name.to_string(),
637            location: location.to_string(),
638        });
639    }
640
641    /// Record FFI call
642    pub fn record_ffi_call(&mut self, fn_name: &str, location: &str) {
643        let timestamp = Self::next_timestamp();
644
645        self.events.push(Event::FfiCall {
646            timestamp,
647            fn_name: fn_name.to_string(),
648            location: location.to_string(),
649        });
650    }
651
652    /// Record transmute operation
653    pub fn record_transmute(&mut self, from_type: &str, to_type: &str, location: &str) {
654        let timestamp = Self::next_timestamp();
655
656        self.events.push(Event::Transmute {
657            timestamp,
658            from_type: from_type.to_string(),
659            to_type: to_type.to_string(),
660            location: location.to_string(),
661        });
662    }
663
664    /// Record union field access
665    pub fn record_union_field_access(
666        &mut self,
667        union_name: &str,
668        field_name: &str,
669        location: &str,
670    ) {
671        let timestamp = Self::next_timestamp();
672
673        self.events.push(Event::UnionFieldAccess {
674            timestamp,
675            union_name: union_name.to_string(),
676            field_name: field_name.to_string(),
677            location: location.to_string(),
678        });
679    }
680
681    /// Get all events
682    pub fn events(&self) -> &[Event] {
683        &self.events
684    }
685
686    /// Clear all events
687    pub fn clear(&mut self) {
688        self.events.clear();
689        self.var_counter = 0;
690        TIMESTAMP.store(0, Ordering::Relaxed);
691    }
692}
693
694impl Default for Tracker {
695    fn default() -> Self {
696        Self::new()
697    }
698}
699
700/// Track a new variable creation.
701///
702/// Records a `New` event and returns the value unchanged. Use this when
703/// a variable is first created or initialized.
704///
705/// # Arguments
706///
707/// * `name` - A descriptive name for the variable (used in event output)
708/// * `value` - The value being tracked (returned unchanged)
709///
710/// # Returns
711///
712/// The input `value`, unchanged. This allows chaining:
713/// ```rust
714/// # use borrowscope_runtime::*;
715/// # reset();
716/// let x = track_new("x", 42);
717/// assert_eq!(x, 42);
718/// ```
719///
720/// # Examples
721///
722/// Basic usage:
723/// ```rust
724/// # use borrowscope_runtime::*;
725/// # reset();
726/// let data = track_new("data", vec![1, 2, 3]);
727/// let events = get_events();
728/// assert!(events[0].is_new());
729/// ```
730///
731/// With structs:
732/// ```rust
733/// # use borrowscope_runtime::*;
734/// # reset();
735/// struct Point { x: i32, y: i32 }
736/// let p = track_new("point", Point { x: 10, y: 20 });
737/// ```
738#[inline(always)]
739pub fn track_new<T>(
740    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
741    value: T,
742) -> T {
743    #[cfg(feature = "track")]
744    {
745        let type_name = std::any::type_name::<T>();
746        let mut tracker = TRACKER.lock();
747        tracker.record_new(name, type_name);
748    }
749    value
750}
751
752/// Track an immutable borrow.
753///
754/// Records a `Borrow` event with `mutable: false` and returns the reference unchanged.
755/// Use this when creating a shared reference (`&T`).
756///
757/// # Arguments
758///
759/// * `name` - A descriptive name for the borrow
760/// * `value` - The reference being tracked (returned unchanged)
761///
762/// # Returns
763///
764/// The input reference, unchanged.
765///
766/// # Examples
767///
768/// ```rust
769/// # use borrowscope_runtime::*;
770/// # reset();
771/// let data = track_new("data", vec![1, 2, 3]);
772/// let r1 = track_borrow("r1", &data);
773/// let r2 = track_borrow("r2", &data); // Multiple immutable borrows OK
774/// println!("{:?}, {:?}", r1, r2);
775///
776/// let events = get_events();
777/// assert!(events[1].is_borrow());
778/// assert!(events[2].is_borrow());
779/// ```
780#[inline(always)]
781pub fn track_borrow<'a, T: ?Sized>(
782    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
783    value: &'a T,
784) -> &'a T {
785    #[cfg(feature = "track")]
786    {
787        let mut tracker = TRACKER.lock();
788        tracker.record_borrow(name, "unknown", false);
789    }
790    value
791}
792
793/// Track a mutable borrow.
794///
795/// Records a `Borrow` event with `mutable: true` and returns the reference unchanged.
796/// Use this when creating an exclusive reference (`&mut T`).
797///
798/// # Arguments
799///
800/// * `name` - A descriptive name for the borrow
801/// * `value` - The mutable reference being tracked (returned unchanged)
802///
803/// # Returns
804///
805/// The input mutable reference, unchanged.
806///
807/// # Examples
808///
809/// ```rust
810/// # use borrowscope_runtime::*;
811/// # reset();
812/// let mut data = track_new("data", vec![1, 2, 3]);
813/// {
814///     let r = track_borrow_mut("r", &mut data);
815///     r.push(4);
816/// }
817/// // Mutable borrow ended, can borrow again
818/// let events = get_events();
819/// assert!(events[1].is_borrow());
820/// ```
821#[inline(always)]
822pub fn track_borrow_mut<'a, T: ?Sized>(
823    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
824    value: &'a mut T,
825) -> &'a mut T {
826    #[cfg(feature = "track")]
827    {
828        let mut tracker = TRACKER.lock();
829        tracker.record_borrow(name, "unknown", true);
830    }
831    value
832}
833
834/// Track an ownership move.
835///
836/// Records a `Move` event and returns the value unchanged.
837/// Use this when ownership transfers from one variable to another.
838///
839/// # Arguments
840///
841/// * `from_name` - Name of the source variable (giving up ownership)
842/// * `to_name` - Name of the destination variable (receiving ownership)
843/// * `value` - The value being moved (returned unchanged)
844///
845/// # Returns
846///
847/// The input `value`, unchanged.
848///
849/// # Examples
850///
851/// ```rust
852/// # use borrowscope_runtime::*;
853/// # reset();
854/// let s1 = track_new("s1", String::from("hello"));
855/// let s2 = track_move("s1", "s2", s1);
856/// // s1 is no longer valid, s2 owns the String
857///
858/// let events = get_events();
859/// assert!(events[1].is_move());
860/// ```
861#[inline(always)]
862pub fn track_move<T>(
863    #[cfg_attr(not(feature = "track"), allow(unused_variables))] from_name: &str,
864    #[cfg_attr(not(feature = "track"), allow(unused_variables))] to_name: &str,
865    value: T,
866) -> T {
867    #[cfg(feature = "track")]
868    {
869        let mut tracker = TRACKER.lock();
870        tracker.record_move(from_name, to_name);
871    }
872    value
873}
874
875/// Track a variable going out of scope.
876///
877/// Records a `Drop` event. Call this when a variable's lifetime ends.
878/// Unlike other tracking functions, this doesn't return a value since
879/// the variable is being destroyed.
880///
881/// # Arguments
882///
883/// * `name` - Name of the variable being dropped
884///
885/// # Examples
886///
887/// ```rust
888/// # use borrowscope_runtime::*;
889/// # reset();
890/// {
891///     let x = track_new("x", 42);
892///     // x goes out of scope here
893///     track_drop("x");
894/// }
895///
896/// let events = get_events();
897/// assert!(events[1].is_drop());
898/// ```
899///
900/// # Note
901///
902/// For automatic drop tracking, consider using RAII guards or the
903/// future `borrowscope-macro` crate which will instrument drops automatically.
904#[inline(always)]
905pub fn track_drop(#[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str) {
906    #[cfg(feature = "track")]
907    {
908        let mut tracker = TRACKER.lock();
909        tracker.record_drop(name);
910    }
911}
912
913/// Track multiple drops in batch (optimized).
914///
915/// Records multiple `Drop` events efficiently with a single lock acquisition.
916/// Use this when multiple variables go out of scope simultaneously.
917///
918/// # Arguments
919///
920/// * `names` - Slice of variable names being dropped
921///
922/// # Examples
923///
924/// ```rust
925/// # use borrowscope_runtime::*;
926/// # reset();
927/// let a = track_new("a", 1);
928/// let b = track_new("b", 2);
929/// let c = track_new("c", 3);
930/// // All go out of scope together
931/// track_drop_batch(&["a", "b", "c"]);
932///
933/// let events = get_events();
934/// assert_eq!(events.len(), 6); // 3 New + 3 Drop
935/// ```
936#[inline(always)]
937pub fn track_drop_batch(
938    #[cfg_attr(not(feature = "track"), allow(unused_variables))] names: &[&str],
939) {
940    #[cfg(feature = "track")]
941    {
942        let mut tracker = TRACKER.lock();
943        for &name in names {
944            tracker.record_drop(name);
945        }
946    }
947}
948
949/// Reset tracking state.
950///
951/// Clears all recorded events and resets internal counters.
952/// Call this before starting a new tracking session.
953///
954/// # Examples
955///
956/// ```rust
957/// # use borrowscope_runtime::*;
958/// let _ = track_new("x", 1);
959/// assert!(!get_events().is_empty());
960///
961/// reset();
962/// assert!(get_events().is_empty());
963/// ```
964///
965/// # Thread Safety
966///
967/// This function is thread-safe but will clear events from all threads.
968/// In multi-threaded tests, use synchronization to ensure reset completes
969/// before other threads start tracking.
970pub fn reset() {
971    let mut tracker = TRACKER.lock();
972    tracker.clear();
973}
974
975/// Get all recorded events.
976///
977/// Returns a copy of all events recorded since the last [`reset()`].
978/// Events are ordered by timestamp (monotonically increasing).
979///
980/// # Returns
981///
982/// A `Vec<Event>` containing all recorded events.
983///
984/// # Examples
985///
986/// ```rust
987/// # use borrowscope_runtime::*;
988/// # reset();
989/// let x = track_new("x", 42);
990/// let r = track_borrow("r", &x);
991///
992/// let events = get_events();
993/// assert_eq!(events.len(), 2);
994/// assert!(events[0].is_new());
995/// assert!(events[1].is_borrow());
996/// ```
997///
998/// # Exporting to JSON
999///
1000/// ```rust
1001/// # use borrowscope_runtime::*;
1002/// # reset();
1003/// # let _ = track_new("x", 1);
1004/// let events = get_events();
1005/// let json = serde_json::to_string_pretty(&events).unwrap();
1006/// println!("{}", json);
1007/// ```
1008pub fn get_events() -> Vec<Event> {
1009    TRACKER.lock().events().to_vec()
1010}
1011
1012/// Get events filtered by a predicate.
1013///
1014/// # Examples
1015///
1016/// ```rust
1017/// # use borrowscope_runtime::*;
1018/// # reset();
1019/// let _ = track_new("x", 1);
1020/// let _ = track_borrow("r", &1);
1021/// let borrows = get_events_filtered(|e| e.is_borrow());
1022/// assert_eq!(borrows.len(), 1);
1023/// ```
1024pub fn get_events_filtered<F>(predicate: F) -> Vec<Event>
1025where
1026    F: Fn(&Event) -> bool,
1027{
1028    TRACKER.lock().events().iter().filter(|e| predicate(e)).cloned().collect()
1029}
1030
1031/// Get all `New` events.
1032pub fn get_new_events() -> Vec<Event> {
1033    get_events_filtered(|e| e.is_new())
1034}
1035
1036/// Get all `Borrow` events (both mutable and immutable).
1037pub fn get_borrow_events() -> Vec<Event> {
1038    get_events_filtered(|e| e.is_borrow())
1039}
1040
1041/// Get all `Drop` events.
1042pub fn get_drop_events() -> Vec<Event> {
1043    get_events_filtered(|e| e.is_drop())
1044}
1045
1046/// Get all `Move` events.
1047pub fn get_move_events() -> Vec<Event> {
1048    get_events_filtered(|e| e.is_move())
1049}
1050
1051/// Get events for a specific variable by name.
1052///
1053/// # Examples
1054///
1055/// ```rust
1056/// # use borrowscope_runtime::*;
1057/// # reset();
1058/// let _ = track_new("data", vec![1, 2, 3]);
1059/// let _ = track_new("other", 42);
1060/// let data_events = get_events_for_var("data");
1061/// assert_eq!(data_events.len(), 1);
1062/// ```
1063pub fn get_events_for_var(name: &str) -> Vec<Event> {
1064    get_events_filtered(|e| e.var_name().map(|n| n == name).unwrap_or(false))
1065}
1066
1067/// Get count of events by type.
1068///
1069/// Returns (new, borrow, move, drop) counts.
1070///
1071/// # Examples
1072///
1073/// ```rust
1074/// # use borrowscope_runtime::*;
1075/// # reset();
1076/// let x = track_new("x", 1);
1077/// let _ = track_borrow("r", &x);
1078/// track_drop("r");
1079/// track_drop("x");
1080/// let (new, borrow, mov, drop) = get_event_counts();
1081/// assert_eq!((new, borrow, mov, drop), (1, 1, 0, 2));
1082/// ```
1083pub fn get_event_counts() -> (usize, usize, usize, usize) {
1084    let events = TRACKER.lock();
1085    let events = events.events();
1086    (
1087        events.iter().filter(|e| e.is_new()).count(),
1088        events.iter().filter(|e| e.is_borrow()).count(),
1089        events.iter().filter(|e| e.is_move()).count(),
1090        events.iter().filter(|e| e.is_drop()).count(),
1091    )
1092}
1093
1094/// Summary statistics for tracked events.
1095#[derive(Debug, Clone, Default)]
1096pub struct TrackingSummary {
1097    /// Number of variables created
1098    pub variables_created: usize,
1099    /// Number of variables dropped
1100    pub variables_dropped: usize,
1101    /// Number of immutable borrows
1102    pub immutable_borrows: usize,
1103    /// Number of mutable borrows
1104    pub mutable_borrows: usize,
1105    /// Number of moves
1106    pub moves: usize,
1107    /// Number of Rc operations
1108    pub rc_operations: usize,
1109    /// Number of Arc operations
1110    pub arc_operations: usize,
1111    /// Number of RefCell operations
1112    pub refcell_operations: usize,
1113    /// Number of Cell operations
1114    pub cell_operations: usize,
1115    /// Number of unsafe operations
1116    pub unsafe_operations: usize,
1117}
1118
1119impl std::fmt::Display for TrackingSummary {
1120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1121        writeln!(f, "=== BorrowScope Summary ===")?;
1122        writeln!(
1123            f,
1124            "Variables: {} created, {} dropped",
1125            self.variables_created, self.variables_dropped
1126        )?;
1127        writeln!(
1128            f,
1129            "Borrows: {} immutable, {} mutable",
1130            self.immutable_borrows, self.mutable_borrows
1131        )?;
1132        if self.moves > 0 {
1133            writeln!(f, "Moves: {}", self.moves)?;
1134        }
1135        if self.rc_operations > 0 || self.arc_operations > 0 {
1136            writeln!(
1137                f,
1138                "Smart pointers: {} Rc, {} Arc",
1139                self.rc_operations, self.arc_operations
1140            )?;
1141        }
1142        if self.refcell_operations > 0 || self.cell_operations > 0 {
1143            writeln!(
1144                f,
1145                "Interior mutability: {} RefCell, {} Cell",
1146                self.refcell_operations, self.cell_operations
1147            )?;
1148        }
1149        if self.unsafe_operations > 0 {
1150            writeln!(f, "Unsafe operations: {}", self.unsafe_operations)?;
1151        }
1152        Ok(())
1153    }
1154}
1155
1156/// Get a summary of all tracked events.
1157///
1158/// # Examples
1159///
1160/// ```rust
1161/// # use borrowscope_runtime::*;
1162/// # reset();
1163/// let x = track_new("x", 42);
1164/// let r = track_borrow("r", &x);
1165/// track_drop("r");
1166/// track_drop("x");
1167///
1168/// let summary = get_summary();
1169/// assert_eq!(summary.variables_created, 1);
1170/// assert_eq!(summary.immutable_borrows, 1);
1171/// assert_eq!(summary.variables_dropped, 2);
1172/// ```
1173pub fn get_summary() -> TrackingSummary {
1174    let events = TRACKER.lock();
1175    let events = events.events();
1176    let mut summary = TrackingSummary::default();
1177
1178    for event in events {
1179        match event {
1180            Event::New { .. } => summary.variables_created += 1,
1181            Event::Drop { .. } => summary.variables_dropped += 1,
1182            Event::Borrow { mutable, .. } => {
1183                if *mutable {
1184                    summary.mutable_borrows += 1;
1185                } else {
1186                    summary.immutable_borrows += 1;
1187                }
1188            }
1189            Event::Move { .. } => summary.moves += 1,
1190            Event::RcNew { .. } | Event::RcClone { .. } => summary.rc_operations += 1,
1191            Event::ArcNew { .. } | Event::ArcClone { .. } => summary.arc_operations += 1,
1192            Event::RefCellNew { .. } | Event::RefCellBorrow { .. } | Event::RefCellDrop { .. } => {
1193                summary.refcell_operations += 1
1194            }
1195            Event::CellNew { .. } | Event::CellGet { .. } | Event::CellSet { .. } => {
1196                summary.cell_operations += 1
1197            }
1198            Event::RawPtrCreated { .. }
1199            | Event::RawPtrDeref { .. }
1200            | Event::UnsafeBlockEnter { .. }
1201            | Event::UnsafeBlockExit { .. }
1202            | Event::UnsafeFnCall { .. }
1203            | Event::FfiCall { .. }
1204            | Event::Transmute { .. }
1205            | Event::UnionFieldAccess { .. } => summary.unsafe_operations += 1,
1206            _ => {}
1207        }
1208    }
1209    summary
1210}
1211
1212/// Print a summary of tracked events to stdout.
1213///
1214/// # Examples
1215///
1216/// ```rust
1217/// # use borrowscope_runtime::*;
1218/// # reset();
1219/// let x = track_new("x", 42);
1220/// let r = track_borrow("r", &x);
1221/// track_drop("r");
1222/// track_drop("x");
1223///
1224/// print_summary();
1225/// // Output:
1226/// // === BorrowScope Summary ===
1227/// // Variables: 1 created, 2 dropped
1228/// // Borrows: 1 immutable, 0 mutable
1229/// ```
1230pub fn print_summary() {
1231    println!("{}", get_summary());
1232}
1233
1234/// Helper function for track_new_with_id that extracts type at runtime
1235#[inline(always)]
1236#[doc(hidden)]
1237pub fn __track_new_with_id_helper<T>(
1238    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
1239    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1240    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1241    value: T,
1242) -> T {
1243    #[cfg(feature = "track")]
1244    {
1245        let type_name = std::any::type_name::<T>();
1246        let mut tracker = TRACKER.lock();
1247        tracker.record_new_with_id(id, name, type_name, location);
1248    }
1249    value
1250}
1251
1252/// Track a new variable with explicit ID and location (advanced API)
1253#[inline(always)]
1254pub fn track_new_with_id<T>(
1255    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
1256    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1257    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
1258    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1259    value: T,
1260) -> T {
1261    #[cfg(feature = "track")]
1262    {
1263        let mut tracker = TRACKER.lock();
1264        tracker.record_new_with_id(id, name, type_name, location);
1265    }
1266    value
1267}
1268
1269/// Track an immutable borrow with full metadata (advanced API)
1270#[inline(always)]
1271pub fn track_borrow_with_id<'a, T: ?Sized>(
1272    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrower_id: usize,
1273    #[cfg_attr(not(feature = "track"), allow(unused_variables))] owner_id: usize,
1274    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1275    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1276    #[cfg_attr(not(feature = "track"), allow(unused_variables))] mutable: bool,
1277    value: &'a T,
1278) -> &'a T {
1279    #[cfg(feature = "track")]
1280    {
1281        let mut tracker = TRACKER.lock();
1282        tracker.record_borrow_with_id(borrower_id, owner_id, name, location, mutable);
1283    }
1284    value
1285}
1286
1287/// Track a mutable borrow with full metadata (advanced API)
1288#[inline(always)]
1289pub fn track_borrow_mut_with_id<'a, T: ?Sized>(
1290    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrower_id: usize,
1291    #[cfg_attr(not(feature = "track"), allow(unused_variables))] owner_id: usize,
1292    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1293    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1294    value: &'a mut T,
1295) -> &'a mut T {
1296    #[cfg(feature = "track")]
1297    {
1298        let mut tracker = TRACKER.lock();
1299        tracker.record_borrow_with_id(borrower_id, owner_id, name, location, true);
1300    }
1301    value
1302}
1303
1304/// Track a move with explicit IDs and location (advanced API)
1305#[inline(always)]
1306pub fn track_move_with_id<T>(
1307    #[cfg_attr(not(feature = "track"), allow(unused_variables))] from_id: usize,
1308    #[cfg_attr(not(feature = "track"), allow(unused_variables))] to_id: usize,
1309    #[cfg_attr(not(feature = "track"), allow(unused_variables))] to_name: &str,
1310    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1311    value: T,
1312) -> T {
1313    #[cfg(feature = "track")]
1314    {
1315        let mut tracker = TRACKER.lock();
1316        tracker.record_move_with_id(from_id, to_id, to_name, location);
1317    }
1318    value
1319}
1320
1321/// Track a drop with explicit ID and location (advanced API)
1322#[inline(always)]
1323pub fn track_drop_with_id(
1324    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
1325    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1326) {
1327    #[cfg(feature = "track")]
1328    {
1329        let mut tracker = TRACKER.lock();
1330        tracker.record_drop_with_id(id, location);
1331    }
1332}
1333
1334/// Track Rc::new with explicit ID and location (advanced API)
1335#[inline(always)]
1336pub fn track_rc_new_with_id<T: ?Sized>(
1337    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
1338    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1339    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
1340    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1341    value: std::rc::Rc<T>,
1342) -> std::rc::Rc<T> {
1343    #[cfg(feature = "track")]
1344    {
1345        let strong_count = std::rc::Rc::strong_count(&value);
1346        let weak_count = std::rc::Rc::weak_count(&value);
1347        let mut tracker = TRACKER.lock();
1348        tracker.record_rc_new_with_id(id, name, type_name, location, strong_count, weak_count);
1349    }
1350    value
1351}
1352
1353/// Track Rc::clone with explicit IDs and location (advanced API)
1354#[inline(always)]
1355pub fn track_rc_clone_with_id<T: ?Sized>(
1356    #[cfg_attr(not(feature = "track"), allow(unused_variables))] new_id: usize,
1357    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_id: usize,
1358    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1359    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1360    value: std::rc::Rc<T>,
1361) -> std::rc::Rc<T> {
1362    #[cfg(feature = "track")]
1363    {
1364        let strong_count = std::rc::Rc::strong_count(&value);
1365        let weak_count = std::rc::Rc::weak_count(&value);
1366        let mut tracker = TRACKER.lock();
1367        tracker.record_rc_clone_with_id(
1368            new_id,
1369            source_id,
1370            name,
1371            location,
1372            strong_count,
1373            weak_count,
1374        );
1375    }
1376    value
1377}
1378
1379/// Track Arc::new with explicit ID and location (advanced API)
1380#[inline(always)]
1381pub fn track_arc_new_with_id<T: ?Sized>(
1382    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
1383    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1384    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
1385    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1386    value: std::sync::Arc<T>,
1387) -> std::sync::Arc<T> {
1388    #[cfg(feature = "track")]
1389    {
1390        let strong_count = std::sync::Arc::strong_count(&value);
1391        let weak_count = std::sync::Arc::weak_count(&value);
1392        let mut tracker = TRACKER.lock();
1393        tracker.record_arc_new_with_id(id, name, type_name, location, strong_count, weak_count);
1394    }
1395    value
1396}
1397
1398/// Track Arc::clone with explicit IDs and location (advanced API)
1399#[inline(always)]
1400pub fn track_arc_clone_with_id<T: ?Sized>(
1401    #[cfg_attr(not(feature = "track"), allow(unused_variables))] new_id: usize,
1402    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_id: usize,
1403    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1404    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1405    value: std::sync::Arc<T>,
1406) -> std::sync::Arc<T> {
1407    #[cfg(feature = "track")]
1408    {
1409        let strong_count = std::sync::Arc::strong_count(&value);
1410        let weak_count = std::sync::Arc::weak_count(&value);
1411        let mut tracker = TRACKER.lock();
1412        tracker.record_arc_clone_with_id(
1413            new_id,
1414            source_id,
1415            name,
1416            location,
1417            strong_count,
1418            weak_count,
1419        );
1420    }
1421    value
1422}
1423
1424/// Track `Rc::new` allocation.
1425///
1426/// Records an `RcNew` event with the current strong and weak reference counts.
1427/// Use this when creating a new reference-counted pointer.
1428///
1429/// # Arguments
1430///
1431/// * `name` - A descriptive name for the Rc
1432/// * `value` - The Rc being tracked (returned unchanged)
1433///
1434/// # Returns
1435///
1436/// The input `Rc`, unchanged.
1437///
1438/// # Examples
1439///
1440/// ```rust
1441/// # use borrowscope_runtime::*;
1442/// use std::rc::Rc;
1443/// # reset();
1444///
1445/// let shared = track_rc_new("shared", Rc::new(vec![1, 2, 3]));
1446/// assert_eq!(Rc::strong_count(&shared), 1);
1447///
1448/// let events = get_events();
1449/// assert!(events[0].is_rc());
1450/// assert_eq!(events[0].strong_count(), Some(1));
1451/// ```
1452#[inline(always)]
1453pub fn track_rc_new<T: ?Sized>(
1454    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1455    value: std::rc::Rc<T>,
1456) -> std::rc::Rc<T> {
1457    #[cfg(feature = "track")]
1458    {
1459        let strong_count = std::rc::Rc::strong_count(&value);
1460        let weak_count = std::rc::Rc::weak_count(&value);
1461        let mut tracker = TRACKER.lock();
1462        tracker.record_rc_new(name, strong_count, weak_count);
1463    }
1464    value
1465}
1466
1467/// Track `Rc::clone` operation.
1468///
1469/// Records an `RcClone` event with the updated reference counts.
1470/// Use this when cloning an Rc to share ownership.
1471///
1472/// # Arguments
1473///
1474/// * `name` - A descriptive name for the new clone
1475/// * `source_name` - Name of the Rc being cloned from
1476/// * `value` - The cloned Rc (returned unchanged)
1477///
1478/// # Returns
1479///
1480/// The input `Rc`, unchanged.
1481///
1482/// # Examples
1483///
1484/// ```rust
1485/// # use borrowscope_runtime::*;
1486/// use std::rc::Rc;
1487/// # reset();
1488///
1489/// let original = track_rc_new("original", Rc::new(42));
1490/// let clone1 = track_rc_clone("clone1", "original", Rc::clone(&original));
1491/// let clone2 = track_rc_clone("clone2", "original", Rc::clone(&original));
1492///
1493/// assert_eq!(Rc::strong_count(&original), 3);
1494///
1495/// let events = get_events();
1496/// assert_eq!(events[1].strong_count(), Some(2)); // After first clone
1497/// assert_eq!(events[2].strong_count(), Some(3)); // After second clone
1498/// ```
1499#[inline(always)]
1500pub fn track_rc_clone<T: ?Sized>(
1501    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1502    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
1503    value: std::rc::Rc<T>,
1504) -> std::rc::Rc<T> {
1505    #[cfg(feature = "track")]
1506    {
1507        let strong_count = std::rc::Rc::strong_count(&value);
1508        let weak_count = std::rc::Rc::weak_count(&value);
1509        let mut tracker = TRACKER.lock();
1510        tracker.record_rc_clone(name, source_name, strong_count, weak_count);
1511    }
1512    value
1513}
1514
1515/// Track `Arc::new` allocation.
1516///
1517/// Records an `ArcNew` event with the current strong and weak reference counts.
1518/// Use this when creating a new thread-safe reference-counted pointer.
1519///
1520/// # Arguments
1521///
1522/// * `name` - A descriptive name for the Arc
1523/// * `value` - The Arc being tracked (returned unchanged)
1524///
1525/// # Returns
1526///
1527/// The input `Arc`, unchanged.
1528///
1529/// # Examples
1530///
1531/// ```rust
1532/// # use borrowscope_runtime::*;
1533/// use std::sync::Arc;
1534/// # reset();
1535///
1536/// let shared = track_arc_new("shared", Arc::new(vec![1, 2, 3]));
1537/// assert_eq!(Arc::strong_count(&shared), 1);
1538///
1539/// let events = get_events();
1540/// assert!(events[0].is_arc());
1541/// ```
1542#[inline(always)]
1543pub fn track_arc_new<T: ?Sized>(
1544    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1545    value: std::sync::Arc<T>,
1546) -> std::sync::Arc<T> {
1547    #[cfg(feature = "track")]
1548    {
1549        let strong_count = std::sync::Arc::strong_count(&value);
1550        let weak_count = std::sync::Arc::weak_count(&value);
1551        let mut tracker = TRACKER.lock();
1552        tracker.record_arc_new(name, strong_count, weak_count);
1553    }
1554    value
1555}
1556
1557/// Track `Arc::clone` operation.
1558///
1559/// Records an `ArcClone` event with the updated reference counts.
1560/// Use this when cloning an Arc for thread-safe shared ownership.
1561///
1562/// # Arguments
1563///
1564/// * `name` - A descriptive name for the new clone
1565/// * `source_name` - Name of the Arc being cloned from
1566/// * `value` - The cloned Arc (returned unchanged)
1567///
1568/// # Returns
1569///
1570/// The input `Arc`, unchanged.
1571///
1572/// # Examples
1573///
1574/// ```rust
1575/// # use borrowscope_runtime::*;
1576/// use std::sync::Arc;
1577/// use std::thread;
1578/// # reset();
1579///
1580/// let data = track_arc_new("data", Arc::new(42));
1581/// let data_clone = track_arc_clone("thread_copy", "data", Arc::clone(&data));
1582///
1583/// let handle = thread::spawn(move || {
1584///     println!("Value: {}", *data_clone);
1585/// });
1586/// handle.join().unwrap();
1587/// ```
1588#[inline(always)]
1589pub fn track_arc_clone<T: ?Sized>(
1590    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1591    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
1592    value: std::sync::Arc<T>,
1593) -> std::sync::Arc<T> {
1594    #[cfg(feature = "track")]
1595    {
1596        let strong_count = std::sync::Arc::strong_count(&value);
1597        let weak_count = std::sync::Arc::weak_count(&value);
1598        let mut tracker = TRACKER.lock();
1599        tracker.record_arc_clone(name, source_name, strong_count, weak_count);
1600    }
1601    value
1602}
1603
1604/// Track `RefCell::new` allocation.
1605///
1606/// Records a `RefCellNew` event. Use this when creating a new RefCell
1607/// for interior mutability.
1608///
1609/// # Arguments
1610///
1611/// * `name` - A descriptive name for the RefCell
1612/// * `value` - The RefCell being tracked (returned unchanged)
1613///
1614/// # Returns
1615///
1616/// The input `RefCell`, unchanged.
1617///
1618/// # Examples
1619///
1620/// ```rust
1621/// # use borrowscope_runtime::*;
1622/// use std::cell::RefCell;
1623/// # reset();
1624///
1625/// let cell = track_refcell_new("cell", RefCell::new(42));
1626///
1627/// let events = get_events();
1628/// assert!(events[0].is_refcell());
1629/// ```
1630#[inline(always)]
1631pub fn track_refcell_new<T>(
1632    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1633    value: std::cell::RefCell<T>,
1634) -> std::cell::RefCell<T> {
1635    #[cfg(feature = "track")]
1636    {
1637        let mut tracker = TRACKER.lock();
1638        tracker.record_refcell_new(name);
1639    }
1640    value
1641}
1642
1643/// Track `RefCell::borrow` operation.
1644///
1645/// Records a `RefCellBorrow` event with `is_mutable: false`.
1646/// Use this when obtaining a shared borrow from a RefCell.
1647///
1648/// # Arguments
1649///
1650/// * `borrow_id` - Unique identifier for this borrow
1651/// * `refcell_id` - Identifier of the RefCell being borrowed
1652/// * `location` - Source location (e.g., "file.rs:42")
1653/// * `value` - The Ref guard (returned unchanged)
1654///
1655/// # Returns
1656///
1657/// The input `Ref` guard, unchanged.
1658///
1659/// # Examples
1660///
1661/// ```rust
1662/// # use borrowscope_runtime::*;
1663/// use std::cell::RefCell;
1664/// # reset();
1665///
1666/// let cell = track_refcell_new("cell", RefCell::new(42));
1667/// {
1668///     let guard = track_refcell_borrow("borrow1", "cell", "main.rs:10", cell.borrow());
1669///     println!("Value: {}", *guard);
1670/// } // guard dropped here
1671/// ```
1672#[inline(always)]
1673pub fn track_refcell_borrow<'a, T>(
1674    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrow_id: &str,
1675    #[cfg_attr(not(feature = "track"), allow(unused_variables))] refcell_id: &str,
1676    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1677    value: std::cell::Ref<'a, T>,
1678) -> std::cell::Ref<'a, T> {
1679    #[cfg(feature = "track")]
1680    {
1681        let mut tracker = TRACKER.lock();
1682        tracker.record_refcell_borrow(borrow_id, refcell_id, false, location);
1683    }
1684    value
1685}
1686
1687/// Track `RefCell::borrow_mut` operation.
1688///
1689/// Records a `RefCellBorrow` event with `is_mutable: true`.
1690/// Use this when obtaining an exclusive borrow from a RefCell.
1691///
1692/// # Arguments
1693///
1694/// * `borrow_id` - Unique identifier for this borrow
1695/// * `refcell_id` - Identifier of the RefCell being borrowed
1696/// * `location` - Source location (e.g., "file.rs:42")
1697/// * `value` - The RefMut guard (returned unchanged)
1698///
1699/// # Returns
1700///
1701/// The input `RefMut` guard, unchanged.
1702///
1703/// # Examples
1704///
1705/// ```rust
1706/// # use borrowscope_runtime::*;
1707/// use std::cell::RefCell;
1708/// # reset();
1709///
1710/// let cell = track_refcell_new("cell", RefCell::new(42));
1711/// {
1712///     let mut guard = track_refcell_borrow_mut("borrow1", "cell", "main.rs:10", cell.borrow_mut());
1713///     *guard = 100;
1714/// }
1715/// assert_eq!(*cell.borrow(), 100);
1716/// ```
1717#[inline(always)]
1718pub fn track_refcell_borrow_mut<'a, T>(
1719    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrow_id: &str,
1720    #[cfg_attr(not(feature = "track"), allow(unused_variables))] refcell_id: &str,
1721    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1722    value: std::cell::RefMut<'a, T>,
1723) -> std::cell::RefMut<'a, T> {
1724    #[cfg(feature = "track")]
1725    {
1726        let mut tracker = TRACKER.lock();
1727        tracker.record_refcell_borrow(borrow_id, refcell_id, true, location);
1728    }
1729    value
1730}
1731
1732/// Track RefCell borrow drop (when Ref/RefMut is dropped).
1733///
1734/// Records a `RefCellDrop` event. Call this when a RefCell guard goes out of scope.
1735///
1736/// # Arguments
1737///
1738/// * `borrow_id` - The identifier used when the borrow was created
1739/// * `location` - Source location where the drop occurs
1740///
1741/// # Examples
1742///
1743/// ```rust
1744/// # use borrowscope_runtime::*;
1745/// use std::cell::RefCell;
1746/// # reset();
1747///
1748/// let cell = track_refcell_new("cell", RefCell::new(42));
1749/// {
1750///     let guard = track_refcell_borrow("b1", "cell", "main.rs:10", cell.borrow());
1751///     // use guard...
1752///     track_refcell_drop("b1", "main.rs:12");
1753/// }
1754/// ```
1755#[inline(always)]
1756pub fn track_refcell_drop(
1757    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrow_id: &str,
1758    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1759) {
1760    #[cfg(feature = "track")]
1761    {
1762        let mut tracker = TRACKER.lock();
1763        tracker.record_refcell_drop(borrow_id, location);
1764    }
1765}
1766
1767/// Track `Cell::new` allocation.
1768///
1769/// Records a `CellNew` event. Use this when creating a new Cell
1770/// for interior mutability with Copy types.
1771///
1772/// # Arguments
1773///
1774/// * `name` - A descriptive name for the Cell
1775/// * `value` - The Cell being tracked (returned unchanged)
1776///
1777/// # Returns
1778///
1779/// The input `Cell`, unchanged.
1780///
1781/// # Examples
1782///
1783/// ```rust
1784/// # use borrowscope_runtime::*;
1785/// use std::cell::Cell;
1786/// # reset();
1787///
1788/// let counter = track_cell_new("counter", Cell::new(0));
1789///
1790/// let events = get_events();
1791/// assert!(events[0].is_cell());
1792/// ```
1793#[inline(always)]
1794pub fn track_cell_new<T>(
1795    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
1796    value: std::cell::Cell<T>,
1797) -> std::cell::Cell<T> {
1798    #[cfg(feature = "track")]
1799    {
1800        let mut tracker = TRACKER.lock();
1801        tracker.record_cell_new(name);
1802    }
1803    value
1804}
1805
1806/// Track `Cell::get` operation.
1807///
1808/// Records a `CellGet` event. Use this when reading a value from a Cell.
1809///
1810/// # Arguments
1811///
1812/// * `cell_id` - Identifier of the Cell being read
1813/// * `location` - Source location (e.g., "file.rs:42")
1814/// * `value` - The value read from the Cell (returned unchanged)
1815///
1816/// # Returns
1817///
1818/// The input value, unchanged.
1819///
1820/// # Examples
1821///
1822/// ```rust
1823/// # use borrowscope_runtime::*;
1824/// use std::cell::Cell;
1825/// # reset();
1826///
1827/// let counter = track_cell_new("counter", Cell::new(42));
1828/// let value = track_cell_get("counter", "main.rs:5", counter.get());
1829/// assert_eq!(value, 42);
1830/// ```
1831#[inline(always)]
1832pub fn track_cell_get<T: Copy>(
1833    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
1834    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1835    value: T,
1836) -> T {
1837    #[cfg(feature = "track")]
1838    {
1839        let mut tracker = TRACKER.lock();
1840        tracker.record_cell_get(cell_id, location);
1841    }
1842    value
1843}
1844
1845/// Track `Cell::set` operation.
1846///
1847/// Records a `CellSet` event. Use this when writing a value to a Cell.
1848///
1849/// # Arguments
1850///
1851/// * `cell_id` - Identifier of the Cell being written
1852/// * `location` - Source location (e.g., "file.rs:42")
1853///
1854/// # Examples
1855///
1856/// ```rust
1857/// # use borrowscope_runtime::*;
1858/// use std::cell::Cell;
1859/// # reset();
1860///
1861/// let counter = track_cell_new("counter", Cell::new(0));
1862/// counter.set(1);
1863/// track_cell_set("counter", "main.rs:5");
1864/// counter.set(2);
1865/// track_cell_set("counter", "main.rs:6");
1866///
1867/// let events = get_events();
1868/// assert_eq!(events.iter().filter(|e| matches!(e, borrowscope_runtime::Event::CellSet { .. })).count(), 2);
1869/// ```
1870#[inline(always)]
1871pub fn track_cell_set(
1872    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
1873    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1874) {
1875    #[cfg(feature = "track")]
1876    {
1877        let mut tracker = TRACKER.lock();
1878        tracker.record_cell_set(cell_id, location);
1879    }
1880}
1881
1882/// Track static variable initialization.
1883///
1884/// Records a `StaticInit` event. Use this when a static variable is first initialized.
1885///
1886/// # Arguments
1887///
1888/// * `var_name` - Name of the static variable
1889/// * `var_id` - Unique identifier for the variable
1890/// * `type_name` - Type of the static variable
1891/// * `is_mutable` - Whether this is a `static mut`
1892/// * `value` - The initial value (returned unchanged)
1893///
1894/// # Returns
1895///
1896/// The input value, unchanged.
1897#[inline(always)]
1898pub fn track_static_init<T>(
1899    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_name: &str,
1900    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_id: usize,
1901    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
1902    #[cfg_attr(not(feature = "track"), allow(unused_variables))] is_mutable: bool,
1903    value: T,
1904) -> T {
1905    #[cfg(feature = "track")]
1906    {
1907        let mut tracker = TRACKER.lock();
1908        tracker.record_static_init(var_name, var_id, type_name, is_mutable);
1909    }
1910    value
1911}
1912
1913/// Track static variable access (read or write).
1914///
1915/// Records a `StaticAccess` event. Use this when reading from or writing to a static variable.
1916///
1917/// # Arguments
1918///
1919/// * `var_id` - Identifier of the static variable
1920/// * `var_name` - Name of the static variable
1921/// * `is_write` - `true` for writes, `false` for reads
1922/// * `location` - Source location (e.g., "file.rs:42")
1923#[inline(always)]
1924pub fn track_static_access(
1925    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_id: usize,
1926    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_name: &str,
1927    #[cfg_attr(not(feature = "track"), allow(unused_variables))] is_write: bool,
1928    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1929) {
1930    #[cfg(feature = "track")]
1931    {
1932        let mut tracker = TRACKER.lock();
1933        tracker.record_static_access(var_id, var_name, is_write, location);
1934    }
1935}
1936
1937/// Track const evaluation.
1938///
1939/// Records a `ConstEval` event. Use this when a const value is evaluated.
1940///
1941/// # Arguments
1942///
1943/// * `const_name` - Name of the const
1944/// * `const_id` - Unique identifier
1945/// * `type_name` - Type of the const
1946/// * `location` - Source location
1947/// * `value` - The const value (returned unchanged)
1948///
1949/// # Returns
1950///
1951/// The input value, unchanged.
1952#[inline(always)]
1953pub fn track_const_eval<T>(
1954    #[cfg_attr(not(feature = "track"), allow(unused_variables))] const_name: &str,
1955    #[cfg_attr(not(feature = "track"), allow(unused_variables))] const_id: usize,
1956    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
1957    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1958    value: T,
1959) -> T {
1960    #[cfg(feature = "track")]
1961    {
1962        let mut tracker = TRACKER.lock();
1963        tracker.record_const_eval(const_name, const_id, type_name, location);
1964    }
1965    value
1966}
1967
1968/// Track raw pointer creation.
1969///
1970/// Records a `RawPtrCreated` event. Use this when creating a `*const T` pointer.
1971///
1972/// # Arguments
1973///
1974/// * `var_name` - Name for the pointer variable
1975/// * `var_id` - Unique identifier
1976/// * `ptr_type` - Type description (e.g., "*const i32")
1977/// * `location` - Source location
1978/// * `ptr` - The raw pointer (returned unchanged)
1979///
1980/// # Returns
1981///
1982/// The input pointer, unchanged.
1983///
1984/// # Safety
1985///
1986/// This function is safe to call, but the pointer it tracks may be unsafe to dereference.
1987#[inline(always)]
1988pub fn track_raw_ptr<T: ?Sized>(
1989    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_name: &str,
1990    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_id: usize,
1991    #[cfg_attr(not(feature = "track"), allow(unused_variables))] ptr_type: &str,
1992    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
1993    ptr: *const T,
1994) -> *const T {
1995    #[cfg(feature = "track")]
1996    {
1997        let mut tracker = TRACKER.lock();
1998        tracker.record_raw_ptr_created(
1999            var_name,
2000            var_id,
2001            ptr_type,
2002            ptr as *const () as usize,
2003            location,
2004        );
2005    }
2006    ptr
2007}
2008
2009/// Track mutable raw pointer creation.
2010///
2011/// Records a `RawPtrCreated` event. Use this when creating a `*mut T` pointer.
2012///
2013/// # Arguments
2014///
2015/// * `var_name` - Name for the pointer variable
2016/// * `var_id` - Unique identifier
2017/// * `ptr_type` - Type description (e.g., "*mut i32")
2018/// * `location` - Source location
2019/// * `ptr` - The raw pointer (returned unchanged)
2020///
2021/// # Returns
2022///
2023/// The input pointer, unchanged.
2024///
2025/// # Safety
2026///
2027/// This function is safe to call, but the pointer it tracks may be unsafe to dereference.
2028#[inline(always)]
2029pub fn track_raw_ptr_mut<T: ?Sized>(
2030    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_name: &str,
2031    #[cfg_attr(not(feature = "track"), allow(unused_variables))] var_id: usize,
2032    #[cfg_attr(not(feature = "track"), allow(unused_variables))] ptr_type: &str,
2033    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2034    ptr: *mut T,
2035) -> *mut T {
2036    #[cfg(feature = "track")]
2037    {
2038        let mut tracker = TRACKER.lock();
2039        tracker.record_raw_ptr_created(
2040            var_name,
2041            var_id,
2042            ptr_type,
2043            ptr as *const () as usize,
2044            location,
2045        );
2046    }
2047    ptr
2048}
2049
2050/// Track raw pointer dereference.
2051///
2052/// Records a `RawPtrDeref` event. Use this when dereferencing a raw pointer.
2053///
2054/// # Arguments
2055///
2056/// * `ptr_id` - Identifier of the pointer being dereferenced
2057/// * `location` - Source location
2058/// * `is_write` - `true` if writing through the pointer, `false` if reading
2059#[inline(always)]
2060pub fn track_raw_ptr_deref(
2061    #[cfg_attr(not(feature = "track"), allow(unused_variables))] ptr_id: usize,
2062    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2063    #[cfg_attr(not(feature = "track"), allow(unused_variables))] is_write: bool,
2064) {
2065    #[cfg(feature = "track")]
2066    {
2067        let mut tracker = TRACKER.lock();
2068        tracker.record_raw_ptr_deref(ptr_id, location, is_write);
2069    }
2070}
2071
2072/// Track unsafe block entry.
2073///
2074/// Records an `UnsafeBlockEnter` event. Use this when entering an unsafe block.
2075///
2076/// # Arguments
2077///
2078/// * `block_id` - Unique identifier for this unsafe block
2079/// * `location` - Source location
2080#[inline(always)]
2081pub fn track_unsafe_block_enter(
2082    #[cfg_attr(not(feature = "track"), allow(unused_variables))] block_id: usize,
2083    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2084) {
2085    #[cfg(feature = "track")]
2086    {
2087        let mut tracker = TRACKER.lock();
2088        tracker.record_unsafe_block_enter(block_id, location);
2089    }
2090}
2091
2092/// Track unsafe block exit.
2093///
2094/// Records an `UnsafeBlockExit` event. Use this when exiting an unsafe block.
2095///
2096/// # Arguments
2097///
2098/// * `block_id` - Identifier matching the corresponding `track_unsafe_block_enter`
2099/// * `location` - Source location
2100#[inline(always)]
2101pub fn track_unsafe_block_exit(
2102    #[cfg_attr(not(feature = "track"), allow(unused_variables))] block_id: usize,
2103    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2104) {
2105    #[cfg(feature = "track")]
2106    {
2107        let mut tracker = TRACKER.lock();
2108        tracker.record_unsafe_block_exit(block_id, location);
2109    }
2110}
2111
2112/// Track unsafe function call.
2113///
2114/// Records an `UnsafeFnCall` event. Use this when calling an unsafe function.
2115///
2116/// # Arguments
2117///
2118/// * `fn_name` - Name of the unsafe function being called
2119/// * `location` - Source location
2120#[inline(always)]
2121pub fn track_unsafe_fn_call(
2122    #[cfg_attr(not(feature = "track"), allow(unused_variables))] fn_name: &str,
2123    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2124) {
2125    #[cfg(feature = "track")]
2126    {
2127        let mut tracker = TRACKER.lock();
2128        tracker.record_unsafe_fn_call(fn_name, location);
2129    }
2130}
2131
2132/// Track FFI call.
2133///
2134/// Records an `FfiCall` event. Use this when calling a foreign function.
2135///
2136/// # Arguments
2137///
2138/// * `fn_name` - Name of the foreign function being called
2139/// * `location` - Source location
2140#[inline(always)]
2141pub fn track_ffi_call(
2142    #[cfg_attr(not(feature = "track"), allow(unused_variables))] fn_name: &str,
2143    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2144) {
2145    #[cfg(feature = "track")]
2146    {
2147        let mut tracker = TRACKER.lock();
2148        tracker.record_ffi_call(fn_name, location);
2149    }
2150}
2151
2152/// Track transmute operation.
2153///
2154/// Records a `Transmute` event. Use this when using `std::mem::transmute`.
2155///
2156/// # Arguments
2157///
2158/// * `from_type` - Source type name
2159/// * `to_type` - Destination type name
2160/// * `location` - Source location
2161#[inline(always)]
2162pub fn track_transmute(
2163    #[cfg_attr(not(feature = "track"), allow(unused_variables))] from_type: &str,
2164    #[cfg_attr(not(feature = "track"), allow(unused_variables))] to_type: &str,
2165    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2166) {
2167    #[cfg(feature = "track")]
2168    {
2169        let mut tracker = TRACKER.lock();
2170        tracker.record_transmute(from_type, to_type, location);
2171    }
2172}
2173
2174/// Track union field access.
2175///
2176/// Records a `UnionFieldAccess` event. Use this when accessing a union field.
2177///
2178/// # Arguments
2179///
2180/// * `union_name` - Name of the union
2181/// * `field_name` - Name of the field being accessed
2182/// * `location` - Source location
2183#[inline(always)]
2184pub fn track_union_field_access(
2185    #[cfg_attr(not(feature = "track"), allow(unused_variables))] union_name: &str,
2186    #[cfg_attr(not(feature = "track"), allow(unused_variables))] field_name: &str,
2187    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
2188) {
2189    #[cfg(feature = "track")]
2190    {
2191        let mut tracker = TRACKER.lock();
2192        tracker.record_union_field_access(union_name, field_name, location);
2193    }
2194}
2195
2196#[cfg(test)]
2197mod tests {
2198    use super::*;
2199    use crate::test_utils::TEST_LOCK;
2200
2201    #[test]
2202    fn test_tracker_new() {
2203        let mut tracker = Tracker::new();
2204        let id = tracker.record_new("x", "i32");
2205
2206        assert_eq!(tracker.events().len(), 1);
2207        assert!(id.starts_with("x_"));
2208    }
2209
2210    #[test]
2211    fn test_tracker_borrow() {
2212        let mut tracker = Tracker::new();
2213        let owner_id = tracker.record_new("s", "String");
2214        let borrower_id = tracker.record_borrow("r", &owner_id, false);
2215
2216        assert_eq!(tracker.events().len(), 2);
2217        assert!(borrower_id.starts_with("r_"));
2218    }
2219
2220    #[test]
2221    fn test_tracker_move() {
2222        let mut tracker = Tracker::new();
2223        let from_id = tracker.record_new("x", "String");
2224        let to_id = tracker.record_move(&from_id, "y");
2225
2226        assert_eq!(tracker.events().len(), 2);
2227        assert!(to_id.starts_with("y_"));
2228    }
2229
2230    #[test]
2231    fn test_tracker_drop() {
2232        let mut tracker = Tracker::new();
2233        let id = tracker.record_new("x", "i32");
2234        tracker.record_drop(&id);
2235
2236        assert_eq!(tracker.events().len(), 2);
2237        assert!(tracker.events()[1].is_drop());
2238    }
2239
2240    #[test]
2241    fn test_timestamp_ordering() {
2242        let mut tracker = Tracker::new();
2243        tracker.record_new("x", "i32");
2244        tracker.record_new("y", "i32");
2245        tracker.record_new("z", "i32");
2246
2247        let events = tracker.events();
2248        assert!(events[0].timestamp() < events[1].timestamp());
2249        assert!(events[1].timestamp() < events[2].timestamp());
2250    }
2251
2252    #[test]
2253    fn test_track_new_returns_value() {
2254        let _lock = TEST_LOCK.lock();
2255        reset();
2256
2257        let handles: Vec<_> = (0..4)
2258            .map(|i| {
2259                std::thread::spawn(move || {
2260                    let value = track_new(&format!("x_{}", i), 42 + i);
2261                    assert_eq!(value, 42 + i);
2262                })
2263            })
2264            .collect();
2265
2266        for handle in handles {
2267            handle.join().unwrap();
2268        }
2269    }
2270
2271    #[test]
2272    fn test_track_borrow_returns_reference() {
2273        let _lock = TEST_LOCK.lock();
2274        reset();
2275
2276        // Each thread creates its own string and borrows it
2277        let handles: Vec<_> = (0..4)
2278            .map(|i| {
2279                std::thread::spawn(move || {
2280                    let s = String::from("hello");
2281                    let r = track_borrow(&format!("r_{}", i), &s);
2282                    assert_eq!(r, "hello");
2283                })
2284            })
2285            .collect();
2286
2287        for handle in handles {
2288            handle.join().unwrap();
2289        }
2290
2291        let events = get_events();
2292        assert_eq!(events.iter().filter(|e| e.is_borrow()).count(), 4);
2293    }
2294
2295    #[test]
2296    fn test_track_borrow_mut_returns_reference() {
2297        let _lock = TEST_LOCK.lock();
2298        reset();
2299
2300        // Mutable borrows can't be shared, so test sequentially but verify tracking works
2301        let mut s = String::from("hello");
2302        track_borrow_mut("r", &mut s);
2303        s.push_str(" world");
2304        assert_eq!(s, "hello world");
2305
2306        let events = get_events();
2307        assert_eq!(events.iter().filter(|e| e.is_borrow()).count(), 1);
2308    }
2309
2310    #[test]
2311    fn test_complete_workflow() {
2312        let _lock = TEST_LOCK.lock();
2313        reset();
2314
2315        let handles: Vec<_> = (0..4)
2316            .map(|i| {
2317                std::thread::spawn(move || {
2318                    let x = track_new(&format!("x_{}", i), 5);
2319                    let _r = track_borrow(&format!("r_{}", i), &x);
2320                    track_drop(&format!("r_{}", i));
2321                    track_drop(&format!("x_{}", i));
2322                })
2323            })
2324            .collect();
2325
2326        for handle in handles {
2327            handle.join().unwrap();
2328        }
2329
2330        let events = get_events();
2331        assert_eq!(events.len(), 16); // 4 threads * (1 new + 1 borrow + 2 drops)
2332        assert_eq!(events.iter().filter(|e| e.is_new()).count(), 4);
2333        assert_eq!(events.iter().filter(|e| e.is_borrow()).count(), 4);
2334        assert_eq!(events.iter().filter(|e| e.is_drop()).count(), 8);
2335    }
2336
2337    #[test]
2338    fn test_reset() {
2339        let _lock = TEST_LOCK.lock();
2340        reset();
2341
2342        let handles: Vec<_> = (0..4)
2343            .map(|i| {
2344                std::thread::spawn(move || {
2345                    track_new(&format!("x_{}", i), 5);
2346                    track_new(&format!("y_{}", i), 10);
2347                })
2348            })
2349            .collect();
2350
2351        for handle in handles {
2352            handle.join().unwrap();
2353        }
2354
2355        assert_eq!(get_events().len(), 8); // 4 threads * 2 events
2356
2357        reset();
2358
2359        assert_eq!(get_events().len(), 0);
2360    }
2361
2362    #[test]
2363    fn test_unique_ids() {
2364        let _lock = TEST_LOCK.lock();
2365        reset();
2366
2367        let handles: Vec<_> = (0..4)
2368            .map(|_| {
2369                std::thread::spawn(|| {
2370                    track_new("x", 1);
2371                    track_new("x", 2);
2372                    track_new("x", 3);
2373                })
2374            })
2375            .collect();
2376
2377        for handle in handles {
2378            handle.join().unwrap();
2379        }
2380
2381        let events = get_events();
2382        let ids: Vec<_> = events
2383            .iter()
2384            .filter_map(|e| match e {
2385                Event::New { var_id, .. } => Some(var_id.as_str()),
2386                _ => None,
2387            })
2388            .collect();
2389
2390        assert_eq!(ids.len(), 12); // 4 threads * 3 events
2391
2392        // All IDs should be unique
2393        let mut unique_ids = ids.clone();
2394        unique_ids.sort_unstable();
2395        unique_ids.dedup();
2396        assert_eq!(unique_ids.len(), 12, "All IDs should be unique");
2397    }
2398
2399    #[test]
2400    fn test_concurrent_tracking() {
2401        let _lock = TEST_LOCK.lock();
2402        reset();
2403
2404        let handles: Vec<_> = (0..4)
2405            .map(|i| {
2406                std::thread::spawn(move || {
2407                    for j in 0..10 {
2408                        track_new(&format!("var_{}_{}", i, j), i * 10 + j);
2409                    }
2410                })
2411            })
2412            .collect();
2413
2414        for handle in handles {
2415            handle.join().unwrap();
2416        }
2417
2418        let events = get_events();
2419        assert_eq!(events.len(), 40); // 4 threads * 10 events
2420    }
2421
2422    #[test]
2423    fn test_timestamp_monotonicity_concurrent() {
2424        let _lock = TEST_LOCK.lock();
2425        reset();
2426
2427        let handles: Vec<_> = (0..4)
2428            .map(|i| {
2429                std::thread::spawn(move || {
2430                    for j in 0..10 {
2431                        track_new(&format!("var_{}_{}", i, j), i * 10 + j);
2432                    }
2433                })
2434            })
2435            .collect();
2436
2437        for handle in handles {
2438            handle.join().unwrap();
2439        }
2440
2441        let events = get_events();
2442        let mut timestamps: Vec<_> = events.iter().map(|e| e.timestamp()).collect();
2443        timestamps.sort_unstable();
2444
2445        // All timestamps should be unique and monotonic
2446        for i in 1..timestamps.len() {
2447            assert!(
2448                timestamps[i] > timestamps[i - 1],
2449                "Timestamps should be unique and monotonic"
2450            );
2451        }
2452    }
2453
2454    #[test]
2455    fn test_concurrent_reset() {
2456        let _lock = TEST_LOCK.lock();
2457        reset();
2458
2459        // Add some events
2460        for i in 0..10 {
2461            track_new(&format!("var_{}", i), i);
2462        }
2463
2464        assert_eq!(get_events().len(), 10);
2465        reset();
2466        assert_eq!(get_events().len(), 0);
2467    }
2468
2469    #[test]
2470    fn test_high_contention() {
2471        let _lock = TEST_LOCK.lock();
2472        reset();
2473
2474        let handles: Vec<_> = (0..8)
2475            .map(|i| {
2476                std::thread::spawn(move || {
2477                    for j in 0..100 {
2478                        track_new(&format!("var_{}_{}", i, j), i * 100 + j);
2479                    }
2480                })
2481            })
2482            .collect();
2483
2484        for handle in handles {
2485            handle.join().unwrap();
2486        }
2487
2488        let events = get_events();
2489        // try_lock() may drop events under extreme contention - verify we captured most
2490        assert!(
2491            events.len() >= 600,
2492            "Expected at least 600/800 events, got {}",
2493            events.len()
2494        );
2495        assert!(
2496            events.iter().all(|e| e.is_new()),
2497            "All events should be New events"
2498        );
2499    }
2500}