#![feature(std_misc, optin_builtin_traits, core)]
use std::cell::{self, Cell, RefCell, BorrowState};
use std::ops::{Deref, DerefMut, CoerceUnsized};
use std::marker;
use gc::{GcBox, GcBoxTrait};
mod gc;
mod trace;
pub use trace::Trace;
pub use gc::force_collect;
pub struct Gc<T: Trace + ?Sized + 'static> {
root: Cell<bool>,
_ptr: *mut GcBox<T>,
}
impl<T: ?Sized> !marker::Send for Gc<T> {}
impl<T: ?Sized> !marker::Sync for Gc<T> {}
impl<T: Trace + ?Sized + marker::Unsize<U>, U: Trace + ?Sized> CoerceUnsized<Gc<U>> for Gc<T> {}
impl<T: Trace> Gc<T> {
pub fn new(value: T) -> Gc<T> {
unsafe {
let ptr = GcBox::new(value);
(*ptr).value().unroot();
Gc { _ptr: ptr, root: Cell::new(true) }
}
}
}
impl<T: Trace + ?Sized> Gc<T> {
fn inner(&self) -> &GcBox<T> {
unsafe { &*self._ptr }
}
}
impl<T: Trace + ?Sized> Trace for Gc<T> {
unsafe fn trace(&self) {
self.inner().trace_inner();
}
unsafe fn root(&self) {
assert!(!self.root.get(), "Can't double-root a Gc<T>");
self.root.set(true);
self.inner().root_inner();
}
unsafe fn unroot(&self) {
assert!(self.root.get(), "Can't double-unroot a Gc<T>");
self.root.set(false);
self.inner().unroot_inner();
}
}
impl<T: Trace + ?Sized> Clone for Gc<T> {
fn clone(&self) -> Gc<T> {
unsafe { self.inner().root_inner(); }
Gc { _ptr: self._ptr, root: Cell::new(true) }
}
}
impl<T: Trace + ?Sized> Deref for Gc<T> {
type Target = T;
fn deref(&self) -> &T {
&self.inner().value()
}
}
impl<T: Trace + ?Sized> Drop for Gc<T> {
fn drop(&mut self) {
if self.root.get() {
unsafe { self.unroot(); }
}
}
}
pub struct GcCell<T: ?Sized + 'static> {
rooted: Cell<bool>,
cell: RefCell<T>,
}
impl <T: Trace> GcCell<T> {
pub fn new(value: T) -> GcCell<T> {
GcCell{
rooted: Cell::new(true),
cell: RefCell::new(value),
}
}
}
impl <T: Trace + ?Sized> GcCell<T> {
pub fn borrow(&self) -> GcCellRef<T> {
self.cell.borrow()
}
pub fn borrow_mut(&self) -> GcCellRefMut<T> {
let val_ref = self.cell.borrow_mut();
if !self.rooted.get() {
unsafe { val_ref.root(); }
}
GcCellRefMut {
_ref: val_ref,
_rooted: &self.rooted,
}
}
}
impl<T: Trace + ?Sized> Trace for GcCell<T> {
unsafe fn trace(&self) {
match self.cell.borrow_state() {
BorrowState::Writing => (),
_ => self.cell.borrow().trace(),
}
}
unsafe fn root(&self) {
assert!(!self.rooted.get(), "Can't root a GcCell Twice!");
self.rooted.set(true);
match self.cell.borrow_state() {
BorrowState::Writing => (),
_ => self.cell.borrow().root(),
}
}
unsafe fn unroot(&self) {
assert!(self.rooted.get(), "Can't unroot a GcCell Twice!");
self.rooted.set(false);
match self.cell.borrow_state() {
BorrowState::Writing => (),
_ => self.cell.borrow().unroot(),
}
}
}
pub type GcCellRef<'a, T> = cell::Ref<'a, T>;
pub struct GcCellRefMut<'a, T: Trace + ?Sized + 'static> {
_ref: ::std::cell::RefMut<'a, T>,
_rooted: &'a Cell<bool>,
}
impl<'a, T: Trace + ?Sized> Deref for GcCellRefMut<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T { &*self._ref }
}
impl<'a, T: Trace + ?Sized> DerefMut for GcCellRefMut<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T { &mut *self._ref }
}
impl<'a, T: Trace + ?Sized> Drop for GcCellRefMut<'a, T> {
fn drop(&mut self) {
if !self._rooted.get() {
unsafe { self._ref.unroot(); }
}
}
}