sphinx/runtime/gc/trace.rs
1use core::cell::{Cell, RefCell};
2
3
4/// Trait required for all GC'd data.
5/// Unsafe because if the `trace()` implementation fails to call `Gc::mark_trace()`
6/// and `GcWeak::mark_trace()` on all of the `Gc` and `GcWeak` pointers that it can reach,
7/// the GC will free memory that is still in use.
8/// SAFETY: If the receiver also impls `Drop`, the `drop()` impl must not deref any `Gc` or `GcWeak` pointers
9pub unsafe trait GcTrace {
10
11 /// SAFETY: Must call `Gc::mark_trace()` on every reachable Gc handle
12 fn trace(&self);
13
14 /// If the GcTrace owns any allocations, this should return the extra allocated size.
15 /// If the allocation can change size, like a Vec<T>, then don't include it in the
16 /// size hint, or return a const estimate of the average size.
17 #[inline]
18 fn size_hint(&self) -> usize { 0 }
19
20 fn cleanup(&self) { }
21}
22
23// Arrays
24unsafe impl<T> GcTrace for [T] where T: GcTrace {
25 fn trace(&self) {
26 for item in self.iter() {
27 item.trace()
28 }
29 }
30
31 fn size_hint(&self) -> usize {
32 self.iter().map(GcTrace::size_hint).sum()
33 }
34}
35
36// Cells
37unsafe impl<T> GcTrace for Cell<T> where T: GcTrace + Copy {
38 fn trace(&self) {
39 self.get().trace()
40 }
41
42 fn size_hint(&self) -> usize {
43 self.get().size_hint()
44 }
45}
46
47unsafe impl<T> GcTrace for RefCell<T> where T: GcTrace {
48 fn trace(&self) {
49 self.borrow().trace()
50 }
51
52 fn size_hint(&self) -> usize {
53 self.borrow().size_hint()
54 }
55}