Skip to main content

gc_lib/
lib.rs

1use std::{cell::RefCell, fmt, rc::Rc};
2
3pub struct GC<T>(pub Rc<RefCell<T>>);
4
5impl<T> GC<T> {
6    pub fn new(value: T) -> Self {
7        GC(Rc::new(RefCell::new(value)))
8    }
9
10    pub fn borrow(&self) -> std::cell::Ref<T> {
11        self.0.borrow()
12    }
13
14    pub fn borrow_mut(&self) -> std::cell::RefMut<T> {
15        self.0.borrow_mut()
16    }
17
18    pub fn strong_count(&self) -> usize {
19        Rc::strong_count(&self.0)
20    }
21
22    pub fn weak_count(&self) -> usize {
23        Rc::weak_count(&self.0)
24    }
25
26    pub fn downgrade(&self) -> std::rc::Weak<RefCell<T>> {
27        Rc::downgrade(&self.0)
28    }
29
30    pub fn upgrade(weak: &std::rc::Weak<RefCell<T>>) -> Option<Self> {
31        weak.upgrade().map(GC)
32    }
33}
34
35impl<T> fmt::Debug for GC<T>
36where
37    T: fmt::Debug,
38{
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        self.0.borrow().fmt(f)
41    }
42}
43
44impl<T> Clone for GC<T> {
45    fn clone(&self) -> Self {
46        GC(self.0.clone())
47    }
48}
49
50
51#[cfg(test)]
52mod tests {
53    use std::rc::Weak;
54
55    use super::*;
56
57    #[test]
58    fn test_gc() {
59        let _x = GC::new(5);
60        let _y = GC::new("Hello, world!");
61        let _z = GC::new(vec![1, 2, 3, 4, 5]);
62
63        struct Tracked {
64            id: u32,
65        }
66    
67        impl Drop for Tracked {
68            fn drop(&mut self) {
69                println!("Tracked object {} is being dropped!", self.id);
70            }
71        }
72    
73        {
74            let obj1 = GC::new(Tracked { id: 1 });
75            
76            {
77                let obj2 = GC::new(Tracked { id: 2 });
78                
79                let _obj1_ref1 = obj1.clone();
80                let _obj1_ref2 = obj1.clone();
81                
82                assert_eq!(obj1.strong_count(), 3);
83                assert_eq!(obj2.strong_count(), 1);
84                
85            
86            } // obj2 will be dropped here when we exit this scope
87            assert_eq!(obj1.strong_count(), 1);
88        } // Both obj1 and obj2 should be dropped by now
89    
90    
91
92        struct TrackableResource {
93            id: u32,
94        }
95    
96        impl Drop for TrackableResource {
97            fn drop(&mut self) {
98                println!("Resource {} being dropped!", self.id);
99            }
100        }
101    
102        // Create a weak reference tracker
103        let tracker: RefCell<Vec<Weak<RefCell<TrackableResource>>>> = RefCell::new(Vec::new());
104    
105        // Create some GC objects and track them weakly
106        {
107            let obj = GC::new(TrackableResource { id: 42 });
108            
109            // Store a weak reference to the internal Rc
110            tracker.borrow_mut().push(Rc::downgrade(&obj.0));
111            
112            assert_eq!(obj.strong_count(), 1);
113            assert_eq!(tracker.borrow()[0].upgrade().is_some(), true);
114        }
115    
116        assert_eq!(tracker.borrow()[0].upgrade().is_some(), false);
117
118        }
119}