TraceCell

May 16, 2015 ยท View on GitHub

/// Will allocate a value. By default this value is rooted unsafe fn magic_gc_allocate(value: T) -> NonZero<*mut T> { unimplemented!() }

/// Mark the given pointer during a trace /// Returns whether the pointer was already marked unsafe fn magic_gc_mark(ptr: *const T) -> bool { unimplemented!() }

/// Add the pointer as a GC root unsafe fn magic_gc_add_root(ptr: *const T) { unimplemented!() }

/// Remove the pointer as a GC root unsafe fn magic_gc_remove_root(ptr: *const T) { unimplemented!() }

/// The Trace trait which needs to be implemented on garbage collected objects trait Trace { /// Mark all contained Gcs fn trace(&self); /// Increment the root-count of all contained Gcs unsafe fn root(&self); /// Decrement the root-count of all contained Gcs unsafe fn unroot(&self); }

/// This is the internal data structure which holds a garbage collected /// value, as well as the number of root requests which it has on it. /// This object should always be allocated with it's new function struct GcBox { _roots: Cell, _value: T, }

impl GcBox { /// Allocate a GcBox on the heap fn new(value: T) -> NonZero<*mut GcBox> { magic_gc_allocate(GcBox { _roots: Cell::new(1), _value: value, }) }

/// Get the value form the GcBox
fn value(&self) -> &T {
    &self._value
}

/// Root the
fn root(&self) {
    let roots = self._roots.get() + 1;
    self._roots.set(roots);

    if roots == 1 {
        magic_gc_add_root(self as *const GcBox<T>);
    }
}

fn unroot(&self) {
    let roots = self._roots.get() - 1;
    self._roots.set(roots);

    if roots == 0 {
        magic_gc_remove_root(self as *const GcBox<T>);
    }
}

}

//////// // Gc // ////////

struct Gc { _ptr: NonZero<*const GcBox>, }

impl<T: Trace> Gc { pub fn new(value: T) -> Gc { unsafe { // Allocate the box first let ptr = GcBox::new(value);

        // The thing which we are storing internally is no longer rooted!
        (*ptr).value().unroot();
        let gc = Gc { _ptr: ptr }
    }
}

fn inner(&self) -> &GcBox<T> {
    &*self._ptr
}

}

impl<T: Trace> Trace for Gc { fn trace(&self) { // Only recurse if we haven't already marked this node if !magic_gc_mark(self._ptr) { self.inner().value().trace(); } }

unsafe fn root(&self) {
    self.inner().root();
}

unsafe fn unroot(&self) {
    self.inner().unroot();
}

}

impl<T: Trace> Clone for Gc { fn clone(&self) -> Gc { unsafe { self.root(); Gc { _ptr: self._ptr } } } }

impl<T: Trace> Deref for Gc { type Target = T;

fn deref(&self) -> &T {
    &self.inner().value()
}

}

//////////// // GcCell // ////////////

/// A mutable garbage collected pointer/cell hybrid struct GcCell { _ptr: NonZero<*const GcBox<RefCell>>, }

impl <T: Trace> GcCell { pub fn new(value: T) -> GcCell { unsafe { // Allocate the box first let ptr = GcBox::new(RefCell::new(value));

        // The thing which we are storing internally is no longer rooted!
        (**ptr).value().borrow().unroot();
        GcCell { _ptr: ptr }
    }
}

fn inner(&self) -> &GcCellBox<T> {
    unsafe { &(**self._ptr) }
}

pub fn borrow(&self) -> GcCellRef<T> {
    self.inner().value().borrow()
}

pub fn borrow_mut(&self) -> GcCellRefMut<T> {
    let inner = self.inner();
    let val_ref = inner.value().borrow_mut();

    // Ensure that the box remains alive for the lifetime of the GcCellRefMut
    self.root();
    // Root everything inside the box for the lifetime of the GcCellRefMut
    val_ref.root();

    GcCellRefMut {
        _box: inner,
        _ref: val_ref,
    }
}

}

impl<T: Trace> Trace for GcCell { fn trace(&self) { // Only recurse if we haven't already marked this node if !magic_gc_mark(self._ptr) { let inner = self.inner();

        match inner.value().borrow_state() {
            BorrowState::Writing => {
                // In this case, the stuff inside is already rooted,
                // so we don't have to do anything - we can just stop here
            }
            _ => {
                self.inner().value().trace();
            }
        }
    }
}

unsafe fn root(&self) {
    self.inner().root();
}

unsafe fn unroot(&self) {
    self.inner().unroot();
}

}

/// In the non-mutable case, nothing interesting needs to happen. We are just taking /// a reference into the RefCell. type GcCellRef<'a, T> = cell::Ref<'a, T>;

/// The GcCellRefMut struct acts as a RAII guard (like RefCell's RefMut), which /// will provides unique mutable access to the value inside the GcCell while also /// ensuring that the data isn't collected incorrectly /// This means that it roots the internal box (to ensure that the pointer remains alive), /// (although this is probably unnecessary - investigate). /// as well as the data inside the box. (as it may be modified, or moved out of the object) /// When this guard is present, it is not possible for the trace implementation to see inside /// the object, so the object inside must be rooted to prevent it from being collected. struct GcCellRefMut<'a, T> { _box: &'a GcBox<RefCell>, _ref: ::std::cell::RefMut<'a, T>, }

impl<'a, T: Trace> Deref for GcCellRefMut<'a, T> { type Target = T;

#[inline]
fn deref(&self) -> &T { &*self._ref }

}

impl<'a, T: Trace> DerefMut for GcCellRefMut<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut T { &mut *self._ref } }

impl<'a, T: Trace> Drop for GcCellRefMut<'a, T> { fn drop(&mut self) { // The box no longer has to be kept alive self._box.unroot(); // The data is now within a Gc tree again // we don't have to keep it alive explicitly any longer self._ref.unroot(); } }