rune/core/gc/
trace.rs

1use std::cell::RefCell;
2
3use super::super::object::RawObj;
4use crate::core::object::{Gc, Object};
5use rune_core::hashmap::{HashMap, HashSet};
6
7/// A trait for owned types that can be traced by the garbage collector. This should be implemented
8/// by any type that will hold references to GC managed objects.
9pub(crate) trait Trace {
10    fn trace(&self, state: &mut GcState);
11}
12
13/// A trait for types that are pointers to GC objects. This is a separate trait from `Trace` because
14/// pointers will need to be updated during garbage collection (with the `GcMoveable` trait). Derive
15/// `Trace` will not handle use `GcMoveable` to move the object to the new space, so the pointer
16/// will not get updated. This trait is used by the `Slot` type to update pointers during garbage
17/// collection.
18pub(crate) trait TracePtr {
19    fn trace_ptr(&self, state: &mut GcState);
20}
21
22pub(crate) struct GcState {
23    stack: Vec<RawObj>,
24    pub(in crate::core) to_space: bumpalo::Bump,
25}
26
27impl GcState {
28    pub fn new() -> Self {
29        GcState { stack: Vec::new(), to_space: bumpalo::Bump::new() }
30    }
31
32    pub fn push(&mut self, obj: Object) {
33        self.stack.push(Gc::into_raw(obj));
34    }
35
36    pub fn trace_stack(&mut self) {
37        while let Some(raw) = self.stack.pop() {
38            let obj = unsafe { Object::from_raw(raw) };
39            obj.trace_ptr(self);
40        }
41    }
42}
43
44impl<T: Trace> TracePtr for &T {
45    fn trace_ptr(&self, state: &mut GcState) {
46        (*self).trace(state);
47    }
48}
49
50impl Trace for usize {
51    fn trace(&self, _: &mut GcState) {}
52}
53
54impl Trace for u64 {
55    fn trace(&self, _: &mut GcState) {}
56}
57
58impl Trace for i64 {
59    fn trace(&self, _: &mut GcState) {}
60}
61
62impl<T: Trace, U: Trace> Trace for (T, U) {
63    fn trace(&self, state: &mut GcState) {
64        self.0.trace(state);
65        self.1.trace(state);
66    }
67}
68
69impl<T: Trace> Trace for [T] {
70    fn trace(&self, state: &mut GcState) {
71        for x in self {
72            x.trace(state);
73        }
74    }
75}
76
77impl<T: Trace, const N: usize> Trace for [T; N] {
78    fn trace(&self, state: &mut GcState) {
79        for x in self {
80            x.trace(state);
81        }
82    }
83}
84
85impl<T: Trace> Trace for Vec<T> {
86    fn trace(&self, state: &mut GcState) {
87        for x in self {
88            x.trace(state);
89        }
90    }
91}
92
93impl<T: Trace> Trace for RefCell<T> {
94    fn trace(&self, state: &mut GcState) {
95        self.borrow().trace(state);
96    }
97}
98
99impl<T: Trace> Trace for std::collections::VecDeque<T> {
100    fn trace(&self, state: &mut GcState) {
101        for x in self {
102            x.trace(state);
103        }
104    }
105}
106
107impl<K: Trace, V: Trace> Trace for HashMap<K, V> {
108    fn trace(&self, state: &mut GcState) {
109        for key in self.keys() {
110            key.trace(state);
111        }
112        for value in self.values() {
113            value.trace(state);
114        }
115    }
116}
117
118impl<T: Trace> Trace for HashSet<T> {
119    fn trace(&self, state: &mut GcState) {
120        for x in self {
121            x.trace(state);
122        }
123    }
124}
125
126impl<T: Trace> Trace for Option<T> {
127    fn trace(&self, state: &mut GcState) {
128        if let Some(x) = self.as_ref() {
129            x.trace(state);
130        }
131    }
132}
133
134#[cfg(test)]
135mod test {
136    use super::super::super::gc::{Context, RootSet};
137    use super::*;
138    use rune_core::macros::root;
139
140    #[derive(Default)]
141    struct Foo(u64);
142    impl Trace for Foo {
143        fn trace(&self, _state: &mut GcState) {
144            assert!(self.0 == 7);
145        }
146    }
147
148    #[test]
149    fn test_trace_root() {
150        let roots = &RootSet::default();
151        let cx = &mut Context::new(roots);
152        let foo = Foo(7);
153        assert_eq!(roots.roots.borrow().len(), 0);
154        {
155            root!(_root, init(foo), cx);
156            assert_eq!(roots.roots.borrow().len(), 1);
157        }
158        assert_eq!(roots.roots.borrow().len(), 0);
159    }
160}