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