borrowscope_runtime/tracker/
interior_mut.rs

1//! Interior mutability tracking: RefCell, Cell, OnceCell, OnceLock
2
3use super::TRACKER;
4
5pub fn track_refcell_new<T>(
6    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
7    value: std::cell::RefCell<T>,
8) -> std::cell::RefCell<T> {
9    #[cfg(feature = "track")]
10    {
11        let mut tracker = TRACKER.lock();
12        tracker.record_refcell_new(name);
13    }
14    value
15}
16
17/// Track `RefCell::borrow` operation.
18///
19/// Records a `RefCellBorrow` event with `is_mutable: false`.
20/// Use this when obtaining a shared borrow from a RefCell.
21///
22/// # Arguments
23///
24/// * `borrow_id` - Unique identifier for this borrow
25/// * `refcell_id` - Identifier of the RefCell being borrowed
26/// * `location` - Source location (e.g., "file.rs:42")
27/// * `value` - The Ref guard (returned unchanged)
28///
29/// # Returns
30///
31/// The input `Ref` guard, unchanged.
32///
33/// # Examples
34///
35/// ```rust
36/// # use borrowscope_runtime::*;
37/// use std::cell::RefCell;
38/// # reset();
39///
40/// let cell = track_refcell_new("cell", RefCell::new(42));
41/// {
42///     let guard = track_refcell_borrow("borrow1", "cell", "main.rs:10", cell.borrow());
43///     println!("Value: {}", *guard);
44/// } // guard dropped here
45/// ```
46#[inline(always)]
47pub fn track_refcell_borrow<'a, T>(
48    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrow_id: &str,
49    #[cfg_attr(not(feature = "track"), allow(unused_variables))] refcell_id: &str,
50    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
51    value: std::cell::Ref<'a, T>,
52) -> std::cell::Ref<'a, T> {
53    #[cfg(feature = "track")]
54    {
55        let mut tracker = TRACKER.lock();
56        tracker.record_refcell_borrow(borrow_id, refcell_id, false, location);
57    }
58    value
59}
60
61/// Track `RefCell::borrow_mut` operation.
62///
63/// Records a `RefCellBorrow` event with `is_mutable: true`.
64/// Use this when obtaining an exclusive borrow from a RefCell.
65///
66/// # Arguments
67///
68/// * `borrow_id` - Unique identifier for this borrow
69/// * `refcell_id` - Identifier of the RefCell being borrowed
70/// * `location` - Source location (e.g., "file.rs:42")
71/// * `value` - The RefMut guard (returned unchanged)
72///
73/// # Returns
74///
75/// The input `RefMut` guard, unchanged.
76///
77/// # Examples
78///
79/// ```rust
80/// # use borrowscope_runtime::*;
81/// use std::cell::RefCell;
82/// # reset();
83///
84/// let cell = track_refcell_new("cell", RefCell::new(42));
85/// {
86///     let mut guard = track_refcell_borrow_mut("borrow1", "cell", "main.rs:10", cell.borrow_mut());
87///     *guard = 100;
88/// }
89/// assert_eq!(*cell.borrow(), 100);
90/// ```
91#[inline(always)]
92pub fn track_refcell_borrow_mut<'a, T>(
93    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrow_id: &str,
94    #[cfg_attr(not(feature = "track"), allow(unused_variables))] refcell_id: &str,
95    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
96    value: std::cell::RefMut<'a, T>,
97) -> std::cell::RefMut<'a, T> {
98    #[cfg(feature = "track")]
99    {
100        let mut tracker = TRACKER.lock();
101        tracker.record_refcell_borrow(borrow_id, refcell_id, true, location);
102    }
103    value
104}
105
106/// Track RefCell borrow drop (when Ref/RefMut is dropped).
107///
108/// Records a `RefCellDrop` event. Call this when a RefCell guard goes out of scope.
109///
110/// # Arguments
111///
112/// * `borrow_id` - The identifier used when the borrow was created
113/// * `location` - Source location where the drop occurs
114///
115/// # Examples
116///
117/// ```rust
118/// # use borrowscope_runtime::*;
119/// use std::cell::RefCell;
120/// # reset();
121///
122/// let cell = track_refcell_new("cell", RefCell::new(42));
123/// {
124///     let guard = track_refcell_borrow("b1", "cell", "main.rs:10", cell.borrow());
125///     // use guard...
126///     track_refcell_drop("b1", "main.rs:12");
127/// }
128/// ```
129#[inline(always)]
130pub fn track_refcell_drop(
131    #[cfg_attr(not(feature = "track"), allow(unused_variables))] borrow_id: &str,
132    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
133) {
134    #[cfg(feature = "track")]
135    {
136        let mut tracker = TRACKER.lock();
137        tracker.record_refcell_drop(borrow_id, location);
138    }
139}
140
141/// Track `Cell::new` allocation.
142///
143/// Records a `CellNew` event. Use this when creating a new Cell
144/// for interior mutability with Copy types.
145///
146/// # Arguments
147///
148/// * `name` - A descriptive name for the Cell
149/// * `value` - The Cell being tracked (returned unchanged)
150///
151/// # Returns
152///
153/// The input `Cell`, unchanged.
154///
155/// # Examples
156///
157/// ```rust
158/// # use borrowscope_runtime::*;
159/// use std::cell::Cell;
160/// # reset();
161///
162/// let counter = track_cell_new("counter", Cell::new(0));
163///
164/// let events = get_events();
165/// assert!(events[0].is_cell());
166/// ```
167#[inline(always)]
168pub fn track_cell_new<T>(
169    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
170    value: std::cell::Cell<T>,
171) -> std::cell::Cell<T> {
172    #[cfg(feature = "track")]
173    {
174        let mut tracker = TRACKER.lock();
175        tracker.record_cell_new(name);
176    }
177    value
178}
179
180/// Track `Cell::get` operation.
181///
182/// Records a `CellGet` event. Use this when reading a value from a Cell.
183///
184/// # Arguments
185///
186/// * `cell_id` - Identifier of the Cell being read
187/// * `location` - Source location (e.g., "file.rs:42")
188/// * `value` - The value read from the Cell (returned unchanged)
189///
190/// # Returns
191///
192/// The input value, unchanged.
193///
194/// # Examples
195///
196/// ```rust
197/// # use borrowscope_runtime::*;
198/// use std::cell::Cell;
199/// # reset();
200///
201/// let counter = track_cell_new("counter", Cell::new(42));
202/// let value = track_cell_get("counter", "main.rs:5", counter.get());
203/// assert_eq!(value, 42);
204/// ```
205#[inline(always)]
206pub fn track_cell_get<T: Copy>(
207    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
208    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
209    value: T,
210) -> T {
211    #[cfg(feature = "track")]
212    {
213        let mut tracker = TRACKER.lock();
214        tracker.record_cell_get(cell_id, location);
215    }
216    value
217}
218
219/// Track `Cell::set` operation.
220///
221/// Records a `CellSet` event. Use this when writing a value to a Cell.
222///
223/// # Arguments
224///
225/// * `cell_id` - Identifier of the Cell being written
226/// * `location` - Source location (e.g., "file.rs:42")
227///
228/// # Examples
229///
230/// ```rust
231/// # use borrowscope_runtime::*;
232/// use std::cell::Cell;
233/// # reset();
234///
235/// let counter = track_cell_new("counter", Cell::new(0));
236/// counter.set(1);
237/// track_cell_set("counter", "main.rs:5");
238/// counter.set(2);
239/// track_cell_set("counter", "main.rs:6");
240///
241/// let events = get_events();
242/// assert_eq!(events.iter().filter(|e| matches!(e, borrowscope_runtime::Event::CellSet { .. })).count(), 2);
243/// ```
244#[inline(always)]
245pub fn track_cell_set(
246    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
247    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
248) {
249    #[cfg(feature = "track")]
250    {
251        let mut tracker = TRACKER.lock();
252        tracker.record_cell_set(cell_id, location);
253    }
254}
255
256/// Track static variable initialization.
257///
258/// Records a `StaticInit` event. Use this when a static variable is first initialized.
259///
260/// # Arguments
261///
262/// * `var_name` - Name of the static variable
263/// * `var_id` - Unique identifier for the variable
264/// * `type_name` - Type of the static variable
265/// * `is_mutable` - Whether this is a `static mut`
266/// * `value` - The initial value (returned unchanged)
267///
268/// # Returns
269///
270/// The input value, unchanged.
271#[inline(always)]
272pub fn track_once_cell_new<T>(
273    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
274    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
275    value: std::cell::OnceCell<T>,
276) -> std::cell::OnceCell<T> {
277    #[cfg(feature = "track")]
278    {
279        let mut tracker = TRACKER.lock();
280        tracker.record_once_cell_new(name, "OnceCell", location);
281    }
282    value
283}
284
285/// Track OnceLock::new
286#[inline(always)]
287pub fn track_once_lock_new<T>(
288    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
289    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
290    value: std::sync::OnceLock<T>,
291) -> std::sync::OnceLock<T> {
292    #[cfg(feature = "track")]
293    {
294        let mut tracker = TRACKER.lock();
295        tracker.record_once_cell_new(name, "OnceLock", location);
296    }
297    value
298}
299
300/// Track OnceCell::set
301#[inline(always)]
302pub fn track_once_cell_set<T>(
303    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
304    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
305    result: Result<(), T>,
306) -> Result<(), T> {
307    #[cfg(feature = "track")]
308    {
309        let mut tracker = TRACKER.lock();
310        tracker.record_once_cell_set(cell_id, result.is_ok(), location);
311    }
312    result
313}
314
315/// Track OnceCell::get
316#[inline(always)]
317pub fn track_once_cell_get<'a, T>(
318    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
319    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
320    value: Option<&'a T>,
321) -> Option<&'a T> {
322    #[cfg(feature = "track")]
323    {
324        let mut tracker = TRACKER.lock();
325        tracker.record_once_cell_get(cell_id, value.is_some(), location);
326    }
327    value
328}
329
330/// Track OnceCell::get_or_init
331#[inline(always)]
332pub fn track_once_cell_get_or_init<'a, T>(
333    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cell_id: &str,
334    #[cfg_attr(not(feature = "track"), allow(unused_variables))] was_initialized: bool,
335    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
336    value: &'a T,
337) -> &'a T {
338    #[cfg(feature = "track")]
339    {
340        let mut tracker = TRACKER.lock();
341        tracker.record_once_cell_get_or_init(cell_id, was_initialized, location);
342    }
343    value
344}
345
346// =============================================================================
347// Phase 11: MaybeUninit Tracking Functions
348// =============================================================================
349