Trait Trace

Source
pub trait Trace {
    // Required method
    fn visit_children(&self, visitor: &mut GcVisitor<'_>);
}
Expand description

Must be implemented for any value which will be stored inside of a Gc.

While this is implemented for many of Rust’s basic types, it’s not recommended that you store them in a Gc unless they contain possibly cyclic references as there is still a real cost to doing so. You’re probably better off using std::rc::Rc in cases where you know a type can’t participate in cycles. Visit the gc pointers owned by this type.

Required Methods§

Source

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

It is recommended that you simply call visit_children(visitor) on each value owned by the implementor which may participate in a reference cycle. The default implementation for Gc will appropriately notify the collector when it is visited.

Improper implementation of this trait will not cause undefined behavior; however, if you fail to report a value you may leak memory and if you report a value you don’t own (or report a value more than once), you may cause the collector to clean it up prematurely. Attemting to access a value which has been cleaned up will cause a panic, but will not cause undefined behavior.

§Example

struct GraphNode<T: 'static> {
    neighbors: Vec<Gc<GraphNode<T>>>,
    data: T,
}

impl<T: 'static> Trace for GraphNode<T> {
    fn visit_children(&self, visitor: &mut GcVisitor) {
        self.neighbors.visit_children(visitor);
    }
}
empty_trace!(NodeId);

struct Graph<T: 'static> {
    nodes: HashMap<NodeId, Gc<GraphNode<T>>>,
}

impl<T: 'static> Trace for Graph<T> {
    fn visit_children(&self, visitor: &mut GcVisitor) {
        self.nodes.visit_children(visitor);
    }
}

// Usage:
{
    {
        let graph: Graph<usize> = build_graph();
        operate_on_graph(&graph);
    }
    // None of the graph nodes will remain allocated after this call.
    collect_full();
}
§Examples of improper implementations
  • You should not report Gcs owned by the inner contents of Gcs.
struct MyStruct {
    ptr: Gc<MyStruct>,
    other_ptr: Gc<MyStruct>,
}

impl Trace for MyStruct {
    fn visit_children(&self, visitor: &mut GcVisitor) {
        // This is normal and ok.
        self.ptr.visit_children(visitor);
        // This is also acceptable
        visitor.visit_node(&self.other_ptr);

        // This will not cause undefined behavior, but it is wrong and may cause panics if
        // it causes the collector to believe the node is dead, and the program later
        // attempts to access the now dead value.
        self.ptr.borrow().ptr.visit_children(visitor);
    }
}
  • You should not report a unique Gc instance twice.
struct MyStruct {
    ptr: Gc<usize>,
}

impl Trace for MyStruct {
    fn visit_children(&self, visitor: &mut GcVisitor) {
        // This is normal and ok.
        visitor.visit_node(&self.ptr);

        // This is wrong and may cause panics.
        visitor.visit_node(&self.ptr);
    }
}
  • You should not report Gcs that are not owned by your object.
    • It is acceptable skip reporting, although doing so will result in memory leaks.
thread_local! { static GLOBAL_PTR: Gc<usize> = Gc::new(10)}

struct MyStruct {
    ptr: Gc<MyStruct>,
    leaks: Gc<usize>,
}

impl Trace for MyStruct {
    fn visit_children(&self, visitor: &mut GcVisitor) {
        // This is normal and ok.
        visitor.visit_node(&self.ptr);

        // Leaving this line commented out will leak, which is safe.
        // Uncommenting it is safe and will allow leaks to be cleaned up.
        // visitor(self.leaks.node());

        // This is wrong and will cause GLOBAL_PTR to be cleaned up. If anything tries to
        // access GLOBAL_PTR without checking if it is still alive, a panic will occur.
        GLOBAL_PTR.with(|ptr| visitor.visit_node(ptr));
    }
}

Implementations on Foreign Types§

Source§

impl Trace for bool

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for char

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for f32

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for f64

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for i8

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for i16

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for i32

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for i64

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for i128

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for isize

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for u8

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for u16

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for u32

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for u64

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for u128

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for ()

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for usize

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl Trace for String

Source§

fn visit_children(&self, _: &mut GcVisitor<'_>)

Source§

impl<K: Trace, V: Trace> Trace for BTreeMap<K, V>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<K: Trace, V: Trace, S: BuildHasher> Trace for HashMap<K, V, S>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<T: Trace> Trace for Option<T>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<T: Trace> Trace for [T]

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<T: Trace> Trace for Box<T>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<T: Trace> Trace for Vec<T>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<T: Trace> Trace for RefCell<T>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<T: Trace, const S: usize> Trace for [T; S]

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<V: Trace> Trace for BinaryHeap<V>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<V: Trace> Trace for BTreeSet<V>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<V: Trace> Trace for LinkedList<V>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<V: Trace> Trace for VecDeque<V>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Source§

impl<V: Trace, S: BuildHasher> Trace for HashSet<V, S>

Source§

fn visit_children(&self, visitor: &mut GcVisitor<'_>)

Implementors§

Source§

impl<T> Trace for Gc<T>
where T: Trace + 'static,