#![feature(borrow_state, coerce_unsized, core_intrinsics, optin_builtin_traits, shared, unsize)]
use gc::GcBox;
use std::cell::{self, BorrowState, Cell, RefCell};
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker;
use std::ops::{CoerceUnsized, Deref, DerefMut};
use std::ptr::Shared;
mod gc;
pub mod trace;
#[cfg(test)]
mod test;
pub use trace::Trace;
pub use gc::force_collect;
pub struct Gc<T: Trace + ?Sized + 'static> {
root: Cell<bool>,
ptr: Shared<GcBox<T>>,
}
impl<T: ?Sized> !Send for Gc<T> {}
impl<T: ?Sized> !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) -> Self {
unsafe {
let ptr = GcBox::new(value);
(**ptr).value().unroot();
Gc { ptr: ptr, root: Cell::new(true) }
}
}
}
impl<T: Trace + ?Sized> Gc<T> {
#[inline]
fn inner(&self) -> &GcBox<T> {
gc::GC_SWEEPING.with(|sweeping| {
assert!(!sweeping.get(),
"Cannot access GC-ed objects while GC is running");
});
unsafe { &**self.ptr }
}
}
unsafe impl<T: Trace + ?Sized> Trace for Gc<T> {
#[inline]
unsafe fn trace(&self) {
self.inner().trace_inner();
}
#[inline]
unsafe fn root(&self) {
assert!(!self.root.get(), "Can't double-root a Gc<T>");
self.inner().root_inner();
self.root.set(true);
}
#[inline]
unsafe fn unroot(&self) {
assert!(self.root.get(), "Can't double-unroot a Gc<T>");
self.inner().unroot_inner();
self.root.set(false);
}
}
impl<T: Trace + ?Sized> Clone for Gc<T> {
#[inline]
fn clone(&self) -> Self {
unsafe { self.inner().root_inner(); }
Gc { ptr: self.ptr, root: Cell::new(true) }
}
}
impl<T: Trace + ?Sized> Deref for Gc<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner().value()
}
}
impl<T: Trace + ?Sized> Drop for Gc<T> {
#[inline]
fn drop(&mut self) {
if self.root.get() {
unsafe { self.inner().unroot_inner(); }
}
}
}
impl<T: Trace + Default> Default for Gc<T> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T: Trace + ?Sized + PartialEq> PartialEq for Gc<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
**self == **other
}
#[inline(always)]
fn ne(&self, other: &Self) -> bool {
**self != **other
}
}
impl<T: Trace + ?Sized + Eq> Eq for Gc<T> {}
impl<T: Trace + ?Sized + PartialOrd> PartialOrd for Gc<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
#[inline(always)]
fn lt(&self, other: &Self) -> bool {
**self < **other
}
#[inline(always)]
fn le(&self, other: &Self) -> bool {
**self <= **other
}
#[inline(always)]
fn gt(&self, other: &Self) -> bool {
**self > **other
}
#[inline(always)]
fn ge(&self, other: &Self) -> bool {
**self >= **other
}
}
impl<T: Trace + ?Sized + Ord> Ord for Gc<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T: Trace + ?Sized + Hash> Hash for Gc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: Trace + ?Sized + fmt::Display> fmt::Display for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<T: Trace + ?Sized + fmt::Debug> fmt::Debug for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: Trace> fmt::Pointer for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&*self.ptr, f)
}
}
impl<T: Trace> From<T> for Gc<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}
pub struct GcCell<T: ?Sized + 'static> {
rooted: Cell<bool>,
cell: RefCell<T>,
}
impl<T: Trace> GcCell<T> {
#[inline]
pub fn new(value: T) -> Self {
GcCell {
rooted: Cell::new(true),
cell: RefCell::new(value),
}
}
#[inline]
pub fn into_inner(self) -> T {
self.cell.into_inner()
}
}
impl<T: Trace + ?Sized> GcCell<T> {
#[inline]
pub fn borrow(&self) -> GcCellRef<T> {
self.cell.borrow()
}
#[inline]
pub fn borrow_mut(&self) -> GcCellRefMut<T> {
let val_ref = self.cell.borrow_mut();
if !self.rooted.get() {
unsafe { val_ref.root(); }
}
GcCellRefMut {
refm: val_ref,
rooted: &self.rooted,
}
}
}
unsafe impl<T: Trace + ?Sized> Trace for GcCell<T> {
#[inline]
unsafe fn trace(&self) {
match self.cell.borrow_state() {
BorrowState::Writing => (),
_ => self.cell.borrow().trace(),
}
}
#[inline]
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(),
}
}
#[inline]
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> {
refm: 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.refm }
}
impl<'a, T: Trace + ?Sized> DerefMut for GcCellRefMut<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T { &mut *self.refm }
}
impl<'a, T: Trace + ?Sized> Drop for GcCellRefMut<'a, T> {
#[inline]
fn drop(&mut self) {
if !self.rooted.get() {
unsafe { self.refm.unroot(); }
}
}
}
impl<T: Trace + Default> Default for GcCell<T> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T: Trace + ?Sized + PartialEq> PartialEq for GcCell<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
*self.borrow() == *other.borrow()
}
#[inline(always)]
fn ne(&self, other: &Self) -> bool {
*self.borrow() != *other.borrow()
}
}
impl<T: Trace + ?Sized + Eq> Eq for GcCell<T> {}
impl<T: Trace + ?Sized + PartialOrd> PartialOrd for GcCell<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(*self.borrow()).partial_cmp(&*other.borrow())
}
#[inline(always)]
fn lt(&self, other: &Self) -> bool {
*self.borrow() < *other.borrow()
}
#[inline(always)]
fn le(&self, other: &Self) -> bool {
*self.borrow() <= *other.borrow()
}
#[inline(always)]
fn gt(&self, other: &Self) -> bool {
*self.borrow() > *other.borrow()
}
#[inline(always)]
fn ge(&self, other: &Self) -> bool {
*self.borrow() >= *other.borrow()
}
}
impl<T: Trace + ?Sized + Ord> Ord for GcCell<T> {
#[inline]
fn cmp(&self, other: &GcCell<T>) -> Ordering {
(*self.borrow()).cmp(&*other.borrow())
}
}
impl<T: Trace + ?Sized + Hash> Hash for GcCell<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(*self.borrow()).hash(state);
}
}
impl<T: Trace + ?Sized + fmt::Display> fmt::Display for GcCell<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&*self.borrow(), f)
}
}
impl<T: Trace + ?Sized + fmt::Debug> fmt::Debug for GcCell<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&*self.borrow(), f)
}
}
impl<T: Trace> From<T> for GcCell<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}