bsr 0.11.0

Tracing garbage collector for Amsel
Documentation
//! Contains the linked list of objects.

use std::cell::Cell;
use std::fmt::Debug;
use std::pin::Pin;
use crate::gc::Gc;
use crate::trace::Trace;

pub(crate) trait EntryLike: Debug {
    /// Is this entry a root?
    fn is_root(&self) -> bool;

    /// Mark this entry as unreachable.
    /// Returns whether it was reachable before.
    fn unmark_reachable(&self) -> bool;
}

impl<T> EntryLike for HeapEntry<T> where T: Trace {
    fn is_root(&self) -> bool {
        self.is_root.get()
    }

    fn unmark_reachable(&self) -> bool {
        self.is_reachable.replace(false)
    }
}

/// An entry in the linked list of objects.
/// Owns its value.
#[derive(Debug)]
pub(crate) struct HeapEntry<T> {
    object: T,
    is_reachable: Cell<bool>,
    is_root: Cell<bool>,
}


impl<T: Trace> HeapEntry<T> {
    /// Create a new entry.
    pub fn new(object: T) -> Self {
        Self {
            object,
            is_reachable: Cell::new(false),
            is_root: Cell::new(false),
        }
    }

    /// Create a pinned entry.
    pub fn pin(object: T) -> Pin<Box<Self>> {
        Box::pin(Self::new(object))
    }

    /// Mark this entry and its children as reachable recursively.
    /// Returns whether it was not already reachable.
    pub fn mark_reachable(&self) -> bool {
        if self.is_reachable.replace(true) {
            return false;
        }
        self.object.mark_children();
        true
    }

    /// Mark this entry as a root.
    /// Returns whether it was not already a root.
    pub fn mark_root(&self) -> bool {
        self.is_root.replace(true)
    }

    /// Unmark this entry as a root.
    /// Returns whether it was a root.
    pub fn unmark_root(&self) -> bool {
        self.is_root.replace(false)
    }

    /// Get the object.
    #[inline(always)]
    pub fn get(&self) -> &T {
        &self.object
    }

    /// Get a [Gc] pointer to the object.
    #[inline(always)]
    pub fn get_gc(self: Pin<&Self>) -> Gc<T> {
        let ptr = self.get_ref() as *const _;
        // Safety: `self` is pinned in this context.
        unsafe { Gc::new(ptr) }
    }
}