borrowscope_runtime/tracker/
query.rs

1//! Query functions for retrieving and summarizing events
2
3use crate::event::Event;
4use super::TRACKER;
5
6pub fn reset() {
7    let mut tracker = TRACKER.lock();
8    tracker.clear();
9}
10
11/// Get all recorded events.
12///
13/// Returns a copy of all events recorded since the last [`reset()`].
14/// Events are ordered by timestamp (monotonically increasing).
15///
16/// # Returns
17///
18/// A `Vec<Event>` containing all recorded events.
19///
20/// # Examples
21///
22/// ```rust
23/// # use borrowscope_runtime::*;
24/// # reset();
25/// let x = track_new("x", 42);
26/// let r = track_borrow("r", &x);
27///
28/// let events = get_events();
29/// assert_eq!(events.len(), 2);
30/// assert!(events[0].is_new());
31/// assert!(events[1].is_borrow());
32/// ```
33///
34/// # Exporting to JSON
35///
36/// ```rust
37/// # use borrowscope_runtime::*;
38/// # reset();
39/// # let _ = track_new("x", 1);
40/// let events = get_events();
41/// let json = serde_json::to_string_pretty(&events).unwrap();
42/// println!("{}", json);
43/// ```
44pub fn get_events() -> Vec<Event> {
45    TRACKER.lock().events().to_vec()
46}
47
48/// Get events filtered by a predicate.
49///
50/// # Examples
51///
52/// ```rust
53/// # use borrowscope_runtime::*;
54/// # reset();
55/// let _ = track_new("x", 1);
56/// let _ = track_borrow("r", &1);
57/// let borrows = get_events_filtered(|e| e.is_borrow());
58/// assert_eq!(borrows.len(), 1);
59/// ```
60pub fn get_events_filtered<F>(predicate: F) -> Vec<Event>
61where
62    F: Fn(&Event) -> bool,
63{
64    TRACKER.lock().events().iter().filter(|e| predicate(e)).cloned().collect()
65}
66
67/// Get all `New` events.
68pub fn get_new_events() -> Vec<Event> {
69    get_events_filtered(|e| e.is_new())
70}
71
72/// Get all `Borrow` events (both mutable and immutable).
73pub fn get_borrow_events() -> Vec<Event> {
74    get_events_filtered(|e| e.is_borrow())
75}
76
77/// Get all `Drop` events.
78pub fn get_drop_events() -> Vec<Event> {
79    get_events_filtered(|e| e.is_drop())
80}
81
82/// Get all `Move` events.
83pub fn get_move_events() -> Vec<Event> {
84    get_events_filtered(|e| e.is_move())
85}
86
87/// Get events for a specific variable by name.
88///
89/// # Examples
90///
91/// ```rust
92/// # use borrowscope_runtime::*;
93/// # reset();
94/// let _ = track_new("data", vec![1, 2, 3]);
95/// let _ = track_new("other", 42);
96/// let data_events = get_events_for_var("data");
97/// assert_eq!(data_events.len(), 1);
98/// ```
99pub fn get_events_for_var(name: &str) -> Vec<Event> {
100    get_events_filtered(|e| e.var_name().map(|n| n == name).unwrap_or(false))
101}
102
103/// Get count of events by type.
104///
105/// Returns (new, borrow, move, drop) counts.
106///
107/// # Examples
108///
109/// ```rust
110/// # use borrowscope_runtime::*;
111/// # reset();
112/// let x = track_new("x", 1);
113/// let _ = track_borrow("r", &x);
114/// track_drop("r");
115/// track_drop("x");
116/// let (new, borrow, mov, drop) = get_event_counts();
117/// assert_eq!((new, borrow, mov, drop), (1, 1, 0, 2));
118/// ```
119pub fn get_event_counts() -> (usize, usize, usize, usize) {
120    let events = TRACKER.lock();
121    let events = events.events();
122    (
123        events.iter().filter(|e| e.is_new()).count(),
124        events.iter().filter(|e| e.is_borrow()).count(),
125        events.iter().filter(|e| e.is_move()).count(),
126        events.iter().filter(|e| e.is_drop()).count(),
127    )
128}
129
130/// Summary statistics for tracked events.
131#[derive(Debug, Clone, Default)]
132pub struct TrackingSummary {
133    /// Number of variables created
134    pub variables_created: usize,
135    /// Number of variables dropped
136    pub variables_dropped: usize,
137    /// Number of immutable borrows
138    pub immutable_borrows: usize,
139    /// Number of mutable borrows
140    pub mutable_borrows: usize,
141    /// Number of moves
142    pub moves: usize,
143    /// Number of Rc operations
144    pub rc_operations: usize,
145    /// Number of Arc operations
146    pub arc_operations: usize,
147    /// Number of RefCell operations
148    pub refcell_operations: usize,
149    /// Number of Cell operations
150    pub cell_operations: usize,
151    /// Number of unsafe operations
152    pub unsafe_operations: usize,
153}
154
155impl std::fmt::Display for TrackingSummary {
156    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157        writeln!(f, "=== BorrowScope Summary ===")?;
158        writeln!(
159            f,
160            "Variables: {} created, {} dropped",
161            self.variables_created, self.variables_dropped
162        )?;
163        writeln!(
164            f,
165            "Borrows: {} immutable, {} mutable",
166            self.immutable_borrows, self.mutable_borrows
167        )?;
168        if self.moves > 0 {
169            writeln!(f, "Moves: {}", self.moves)?;
170        }
171        if self.rc_operations > 0 || self.arc_operations > 0 {
172            writeln!(
173                f,
174                "Smart pointers: {} Rc, {} Arc",
175                self.rc_operations, self.arc_operations
176            )?;
177        }
178        if self.refcell_operations > 0 || self.cell_operations > 0 {
179            writeln!(
180                f,
181                "Interior mutability: {} RefCell, {} Cell",
182                self.refcell_operations, self.cell_operations
183            )?;
184        }
185        if self.unsafe_operations > 0 {
186            writeln!(f, "Unsafe operations: {}", self.unsafe_operations)?;
187        }
188        Ok(())
189    }
190}
191
192/// Get a summary of all tracked events.
193///
194/// # Examples
195///
196/// ```rust
197/// # use borrowscope_runtime::*;
198/// # reset();
199/// let x = track_new("x", 42);
200/// let r = track_borrow("r", &x);
201/// track_drop("r");
202/// track_drop("x");
203///
204/// let summary = get_summary();
205/// assert_eq!(summary.variables_created, 1);
206/// assert_eq!(summary.immutable_borrows, 1);
207/// assert_eq!(summary.variables_dropped, 2);
208/// ```
209pub fn get_summary() -> TrackingSummary {
210    let events = TRACKER.lock();
211    let events = events.events();
212    let mut summary = TrackingSummary::default();
213
214    for event in events {
215        match event {
216            Event::New { .. } => summary.variables_created += 1,
217            Event::Drop { .. } => summary.variables_dropped += 1,
218            Event::Borrow { mutable, .. } => {
219                if *mutable {
220                    summary.mutable_borrows += 1;
221                } else {
222                    summary.immutable_borrows += 1;
223                }
224            }
225            Event::Move { .. } => summary.moves += 1,
226            Event::RcNew { .. } | Event::RcClone { .. } => summary.rc_operations += 1,
227            Event::ArcNew { .. } | Event::ArcClone { .. } => summary.arc_operations += 1,
228            Event::RefCellNew { .. } | Event::RefCellBorrow { .. } | Event::RefCellDrop { .. } => {
229                summary.refcell_operations += 1
230            }
231            Event::CellNew { .. } | Event::CellGet { .. } | Event::CellSet { .. } => {
232                summary.cell_operations += 1
233            }
234            Event::RawPtrCreated { .. }
235            | Event::RawPtrDeref { .. }
236            | Event::UnsafeBlockEnter { .. }
237            | Event::UnsafeBlockExit { .. }
238            | Event::UnsafeFnCall { .. }
239            | Event::FfiCall { .. }
240            | Event::Transmute { .. }
241            | Event::UnionFieldAccess { .. } => summary.unsafe_operations += 1,
242            _ => {}
243        }
244    }
245    summary
246}
247
248/// Print a summary of tracked events to stdout.
249///
250/// # Examples
251///
252/// ```rust
253/// # use borrowscope_runtime::*;
254/// # reset();
255/// let x = track_new("x", 42);
256/// let r = track_borrow("r", &x);
257/// track_drop("r");
258/// track_drop("x");
259///
260/// print_summary();
261/// // Output:
262/// // === BorrowScope Summary ===
263/// // Variables: 1 created, 2 dropped
264/// // Borrows: 1 immutable, 0 mutable
265/// ```
266pub fn print_summary() {
267    println!("{}", get_summary());
268}
269