borrowscope_runtime/tracker/
smart_pointers.rs

1//! Smart pointer tracking: Rc, Arc, Box, Weak, Pin, Cow
2
3use super::TRACKER;
4use std::borrow::ToOwned;
5
6pub fn track_rc_new_with_id<T: ?Sized>(
7    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
8    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
9    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
10    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
11    value: std::rc::Rc<T>,
12) -> std::rc::Rc<T> {
13    #[cfg(feature = "track")]
14    {
15        let strong_count = std::rc::Rc::strong_count(&value);
16        let weak_count = std::rc::Rc::weak_count(&value);
17        let mut tracker = TRACKER.lock();
18        tracker.record_rc_new_with_id(id, name, type_name, location, strong_count, weak_count);
19    }
20    value
21}
22
23/// Track Rc::clone with explicit IDs and location (advanced API)
24#[inline(always)]
25pub fn track_rc_clone_with_id<T: ?Sized>(
26    #[cfg_attr(not(feature = "track"), allow(unused_variables))] new_id: usize,
27    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_id: usize,
28    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
29    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
30    value: std::rc::Rc<T>,
31) -> std::rc::Rc<T> {
32    #[cfg(feature = "track")]
33    {
34        let strong_count = std::rc::Rc::strong_count(&value);
35        let weak_count = std::rc::Rc::weak_count(&value);
36        let mut tracker = TRACKER.lock();
37        tracker.record_rc_clone_with_id(
38            new_id,
39            source_id,
40            name,
41            location,
42            strong_count,
43            weak_count,
44        );
45    }
46    value
47}
48
49/// Track Arc::new with explicit ID and location (advanced API)
50#[inline(always)]
51pub fn track_arc_new_with_id<T: ?Sized>(
52    #[cfg_attr(not(feature = "track"), allow(unused_variables))] id: usize,
53    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
54    #[cfg_attr(not(feature = "track"), allow(unused_variables))] type_name: &str,
55    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
56    value: std::sync::Arc<T>,
57) -> std::sync::Arc<T> {
58    #[cfg(feature = "track")]
59    {
60        let strong_count = std::sync::Arc::strong_count(&value);
61        let weak_count = std::sync::Arc::weak_count(&value);
62        let mut tracker = TRACKER.lock();
63        tracker.record_arc_new_with_id(id, name, type_name, location, strong_count, weak_count);
64    }
65    value
66}
67
68/// Track Arc::clone with explicit IDs and location (advanced API)
69#[inline(always)]
70pub fn track_arc_clone_with_id<T: ?Sized>(
71    #[cfg_attr(not(feature = "track"), allow(unused_variables))] new_id: usize,
72    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_id: usize,
73    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
74    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
75    value: std::sync::Arc<T>,
76) -> std::sync::Arc<T> {
77    #[cfg(feature = "track")]
78    {
79        let strong_count = std::sync::Arc::strong_count(&value);
80        let weak_count = std::sync::Arc::weak_count(&value);
81        let mut tracker = TRACKER.lock();
82        tracker.record_arc_clone_with_id(
83            new_id,
84            source_id,
85            name,
86            location,
87            strong_count,
88            weak_count,
89        );
90    }
91    value
92}
93
94/// Track `Rc::new` allocation.
95///
96/// Records an `RcNew` event with the current strong and weak reference counts.
97/// Use this when creating a new reference-counted pointer.
98///
99/// # Arguments
100///
101/// * `name` - A descriptive name for the Rc
102/// * `value` - The Rc being tracked (returned unchanged)
103///
104/// # Returns
105///
106/// The input `Rc`, unchanged.
107///
108/// # Examples
109///
110/// ```rust
111/// # use borrowscope_runtime::*;
112/// use std::rc::Rc;
113/// # reset();
114///
115/// let shared = track_rc_new("shared", Rc::new(vec![1, 2, 3]));
116/// assert_eq!(Rc::strong_count(&shared), 1);
117///
118/// let events = get_events();
119/// assert!(events[0].is_rc());
120/// assert_eq!(events[0].strong_count(), Some(1));
121/// ```
122#[inline(always)]
123pub fn track_rc_new<T: ?Sized>(
124    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
125    value: std::rc::Rc<T>,
126) -> std::rc::Rc<T> {
127    #[cfg(feature = "track")]
128    {
129        let strong_count = std::rc::Rc::strong_count(&value);
130        let weak_count = std::rc::Rc::weak_count(&value);
131        let mut tracker = TRACKER.lock();
132        tracker.record_rc_new(name, strong_count, weak_count);
133    }
134    value
135}
136
137/// Track `Rc::clone` operation.
138///
139/// Records an `RcClone` event with the updated reference counts.
140/// Use this when cloning an Rc to share ownership.
141///
142/// # Arguments
143///
144/// * `name` - A descriptive name for the new clone
145/// * `source_name` - Name of the Rc being cloned from
146/// * `value` - The cloned Rc (returned unchanged)
147///
148/// # Returns
149///
150/// The input `Rc`, unchanged.
151///
152/// # Examples
153///
154/// ```rust
155/// # use borrowscope_runtime::*;
156/// use std::rc::Rc;
157/// # reset();
158///
159/// let original = track_rc_new("original", Rc::new(42));
160/// let clone1 = track_rc_clone("clone1", "original", Rc::clone(&original));
161/// let clone2 = track_rc_clone("clone2", "original", Rc::clone(&original));
162///
163/// assert_eq!(Rc::strong_count(&original), 3);
164///
165/// let events = get_events();
166/// assert_eq!(events[1].strong_count(), Some(2)); // After first clone
167/// assert_eq!(events[2].strong_count(), Some(3)); // After second clone
168/// ```
169#[inline(always)]
170pub fn track_rc_clone<T: ?Sized>(
171    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
172    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
173    value: std::rc::Rc<T>,
174) -> std::rc::Rc<T> {
175    #[cfg(feature = "track")]
176    {
177        let strong_count = std::rc::Rc::strong_count(&value);
178        let weak_count = std::rc::Rc::weak_count(&value);
179        let mut tracker = TRACKER.lock();
180        tracker.record_rc_clone(name, source_name, strong_count, weak_count);
181    }
182    value
183}
184
185/// Track `Arc::new` allocation.
186///
187/// Records an `ArcNew` event with the current strong and weak reference counts.
188/// Use this when creating a new thread-safe reference-counted pointer.
189///
190/// # Arguments
191///
192/// * `name` - A descriptive name for the Arc
193/// * `value` - The Arc being tracked (returned unchanged)
194///
195/// # Returns
196///
197/// The input `Arc`, unchanged.
198///
199/// # Examples
200///
201/// ```rust
202/// # use borrowscope_runtime::*;
203/// use std::sync::Arc;
204/// # reset();
205///
206/// let shared = track_arc_new("shared", Arc::new(vec![1, 2, 3]));
207/// assert_eq!(Arc::strong_count(&shared), 1);
208///
209/// let events = get_events();
210/// assert!(events[0].is_arc());
211/// ```
212#[inline(always)]
213pub fn track_arc_new<T: ?Sized>(
214    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
215    value: std::sync::Arc<T>,
216) -> std::sync::Arc<T> {
217    #[cfg(feature = "track")]
218    {
219        let strong_count = std::sync::Arc::strong_count(&value);
220        let weak_count = std::sync::Arc::weak_count(&value);
221        let mut tracker = TRACKER.lock();
222        tracker.record_arc_new(name, strong_count, weak_count);
223    }
224    value
225}
226
227/// Track `Arc::clone` operation.
228///
229/// Records an `ArcClone` event with the updated reference counts.
230/// Use this when cloning an Arc for thread-safe shared ownership.
231///
232/// # Arguments
233///
234/// * `name` - A descriptive name for the new clone
235/// * `source_name` - Name of the Arc being cloned from
236/// * `value` - The cloned Arc (returned unchanged)
237///
238/// # Returns
239///
240/// The input `Arc`, unchanged.
241///
242/// # Examples
243///
244/// ```rust
245/// # use borrowscope_runtime::*;
246/// use std::sync::Arc;
247/// use std::thread;
248/// # reset();
249///
250/// let data = track_arc_new("data", Arc::new(42));
251/// let data_clone = track_arc_clone("thread_copy", "data", Arc::clone(&data));
252///
253/// let handle = thread::spawn(move || {
254///     println!("Value: {}", *data_clone);
255/// });
256/// handle.join().unwrap();
257/// ```
258#[inline(always)]
259pub fn track_arc_clone<T: ?Sized>(
260    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
261    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
262    value: std::sync::Arc<T>,
263) -> std::sync::Arc<T> {
264    #[cfg(feature = "track")]
265    {
266        let strong_count = std::sync::Arc::strong_count(&value);
267        let weak_count = std::sync::Arc::weak_count(&value);
268        let mut tracker = TRACKER.lock();
269        tracker.record_arc_clone(name, source_name, strong_count, weak_count);
270    }
271    value
272}
273
274/// Track `RefCell::new` allocation.
275///
276/// Records a `RefCellNew` event. Use this when creating a new RefCell
277/// for interior mutability.
278///
279/// # Arguments
280///
281/// * `name` - A descriptive name for the RefCell
282/// * `value` - The RefCell being tracked (returned unchanged)
283///
284/// # Returns
285///
286/// The input `RefCell`, unchanged.
287///
288/// # Examples
289///
290/// ```rust
291/// # use borrowscope_runtime::*;
292/// use std::cell::RefCell;
293/// # reset();
294///
295/// let cell = track_refcell_new("cell", RefCell::new(42));
296///
297/// let events = get_events();
298/// assert!(events[0].is_refcell());
299/// ```
300#[inline(always)]
301pub fn track_weak_new<T: ?Sized>(
302    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
303    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
304    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
305    value: std::rc::Weak<T>,
306) -> std::rc::Weak<T> {
307    #[cfg(feature = "track")]
308    {
309        let weak_count = std::rc::Weak::weak_count(&value);
310        let mut tracker = TRACKER.lock();
311        tracker.record_weak_new(name, source_name, weak_count, location);
312    }
313    value
314}
315
316/// Track sync Weak::new or Arc::downgrade
317#[inline(always)]
318pub fn track_weak_new_sync<T: ?Sized>(
319    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
320    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
321    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
322    value: std::sync::Weak<T>,
323) -> std::sync::Weak<T> {
324    #[cfg(feature = "track")]
325    {
326        let weak_count = std::sync::Weak::weak_count(&value);
327        let mut tracker = TRACKER.lock();
328        tracker.record_weak_new(name, source_name, weak_count, location);
329    }
330    value
331}
332
333/// Track Weak::clone
334#[inline(always)]
335pub fn track_weak_clone<T: ?Sized>(
336    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
337    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
338    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
339    value: std::rc::Weak<T>,
340) -> std::rc::Weak<T> {
341    #[cfg(feature = "track")]
342    {
343        let weak_count = std::rc::Weak::weak_count(&value);
344        let mut tracker = TRACKER.lock();
345        tracker.record_weak_clone(name, source_name, weak_count, location);
346    }
347    value
348}
349
350/// Track sync Weak::clone
351#[inline(always)]
352pub fn track_weak_clone_sync<T: ?Sized>(
353    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
354    #[cfg_attr(not(feature = "track"), allow(unused_variables))] source_name: &str,
355    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
356    value: std::sync::Weak<T>,
357) -> std::sync::Weak<T> {
358    #[cfg(feature = "track")]
359    {
360        let weak_count = std::sync::Weak::weak_count(&value);
361        let mut tracker = TRACKER.lock();
362        tracker.record_weak_clone(name, source_name, weak_count, location);
363    }
364    value
365}
366
367/// Track Weak::upgrade
368#[inline(always)]
369pub fn track_weak_upgrade<T>(
370    #[cfg_attr(not(feature = "track"), allow(unused_variables))] weak_id: &str,
371    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
372    value: Option<std::rc::Rc<T>>,
373) -> Option<std::rc::Rc<T>> {
374    #[cfg(feature = "track")]
375    {
376        let mut tracker = TRACKER.lock();
377        tracker.record_weak_upgrade(weak_id, value.is_some(), location);
378    }
379    value
380}
381
382/// Track sync Weak::upgrade
383#[inline(always)]
384pub fn track_weak_upgrade_sync<T>(
385    #[cfg_attr(not(feature = "track"), allow(unused_variables))] weak_id: &str,
386    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
387    value: Option<std::sync::Arc<T>>,
388) -> Option<std::sync::Arc<T>> {
389    #[cfg(feature = "track")]
390    {
391        let mut tracker = TRACKER.lock();
392        tracker.record_weak_upgrade(weak_id, value.is_some(), location);
393    }
394    value
395}
396
397/// Track Box::new
398#[inline(always)]
399pub fn track_box_new<T: ?Sized>(
400    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
401    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
402    value: Box<T>,
403) -> Box<T> {
404    #[cfg(feature = "track")]
405    {
406        let type_name = std::any::type_name::<T>();
407        let mut tracker = TRACKER.lock();
408        tracker.record_box_new(name, type_name, location);
409    }
410    value
411}
412
413/// Track Box::into_raw
414#[inline(always)]
415pub fn track_box_into_raw<T>(
416    #[cfg_attr(not(feature = "track"), allow(unused_variables))] box_id: &str,
417    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
418    ptr: *mut T,
419) -> *mut T {
420    #[cfg(feature = "track")]
421    {
422        let mut tracker = TRACKER.lock();
423        tracker.record_box_into_raw(box_id, location);
424    }
425    ptr
426}
427
428/// Track Box::from_raw
429#[inline(always)]
430pub fn track_box_from_raw<T>(
431    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
432    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
433    value: Box<T>,
434) -> Box<T> {
435    #[cfg(feature = "track")]
436    {
437        let mut tracker = TRACKER.lock();
438        tracker.record_box_from_raw(name, location);
439    }
440    value
441}
442
443/// Track lock guard acquisition
444#[inline(always)]
445pub fn track_lock_guard_acquire(
446    #[cfg_attr(not(feature = "track"), allow(unused_variables))] guard_id: &str,
447    #[cfg_attr(not(feature = "track"), allow(unused_variables))] lock_id: &str,
448    #[cfg_attr(not(feature = "track"), allow(unused_variables))] lock_type: &str,
449    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
450) {
451    #[cfg(feature = "track")]
452    {
453        let mut tracker = TRACKER.lock();
454        tracker.record_lock_guard_acquire(guard_id, lock_id, lock_type, location);
455    }
456}
457
458/// Track lock guard drop
459#[inline(always)]
460pub fn track_lock_guard_drop(
461    #[cfg_attr(not(feature = "track"), allow(unused_variables))] guard_id: &str,
462    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
463) {
464    #[cfg(feature = "track")]
465    {
466        let mut tracker = TRACKER.lock();
467        tracker.record_lock_guard_drop(guard_id, location);
468    }
469}
470
471/// Track Pin::new
472#[inline(always)]
473pub fn track_pin_new<P>(
474    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
475    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
476    value: std::pin::Pin<P>,
477) -> std::pin::Pin<P> {
478    #[cfg(feature = "track")]
479    {
480        let mut tracker = TRACKER.lock();
481        tracker.record_pin_new(name, location);
482    }
483    value
484}
485
486/// Track Pin::into_inner
487#[inline(always)]
488pub fn track_pin_into_inner<T>(
489    #[cfg_attr(not(feature = "track"), allow(unused_variables))] pin_id: &str,
490    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
491    value: T,
492) -> T {
493    #[cfg(feature = "track")]
494    {
495        let mut tracker = TRACKER.lock();
496        tracker.record_pin_into_inner(pin_id, location);
497    }
498    value
499}
500
501/// Track Cow::Borrowed
502#[inline(always)]
503pub fn track_cow_borrowed<'a, B: ?Sized + ToOwned>(
504    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
505    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
506    value: std::borrow::Cow<'a, B>,
507) -> std::borrow::Cow<'a, B> {
508    #[cfg(feature = "track")]
509    {
510        let mut tracker = TRACKER.lock();
511        tracker.record_cow_borrowed(name, location);
512    }
513    value
514}
515
516/// Track Cow::Owned
517#[inline(always)]
518pub fn track_cow_owned<'a, B: ?Sized + ToOwned>(
519    #[cfg_attr(not(feature = "track"), allow(unused_variables))] name: &str,
520    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
521    value: std::borrow::Cow<'a, B>,
522) -> std::borrow::Cow<'a, B> {
523    #[cfg(feature = "track")]
524    {
525        let mut tracker = TRACKER.lock();
526        tracker.record_cow_owned(name, location);
527    }
528    value
529}
530
531/// Track Cow::to_mut (clone-on-write)
532#[inline(always)]
533pub fn track_cow_to_mut(
534    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cow_id: &str,
535    #[cfg_attr(not(feature = "track"), allow(unused_variables))] cloned: bool,
536    #[cfg_attr(not(feature = "track"), allow(unused_variables))] location: &str,
537) {
538    #[cfg(feature = "track")]
539    {
540        let mut tracker = TRACKER.lock();
541        tracker.record_cow_to_mut(cow_id, cloned, location);
542    }
543}
544