#![cfg_attr(
feature = "nightly",
feature(coerce_unsized, dispatch_from_dyn, unsize)
)]
use crate::gc::{GcBox, GcBoxHeader};
use std::alloc::Layout;
use std::cell::{Cell, UnsafeCell};
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::ops::{Deref, DerefMut};
use std::ptr::{self, NonNull};
use std::rc::Rc;
#[cfg(feature = "nightly")]
use std::marker::Unsize;
#[cfg(feature = "nightly")]
use std::ops::{CoerceUnsized, DispatchFromDyn};
mod gc;
#[cfg(feature = "serde")]
mod serde;
mod trace;
#[cfg(feature = "derive")]
pub use gc_derive::{Finalize, Trace};
pub use crate::gc::{finalizer_safe, force_collect};
pub use crate::trace::{Finalize, Trace};
#[cfg(feature = "unstable-config")]
pub use crate::gc::{configure, GcConfig};
#[cfg(feature = "unstable-stats")]
pub use crate::gc::{stats, GcStats};
pub struct Gc<T: ?Sized + 'static> {
ptr_root: Cell<NonNull<GcBox<T>>>,
marker: PhantomData<Rc<T>>,
}
#[cfg(feature = "nightly")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Gc<U>> for Gc<T> {}
#[cfg(feature = "nightly")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Gc<U>> for Gc<T> {}
impl<T: Trace> Gc<T> {
pub fn new(value: T) -> Self {
unsafe { Gc::from_gcbox(GcBox::new(value)) }
}
}
impl<T: Trace + ?Sized> Gc<T> {
#[inline]
unsafe fn from_gcbox(ptr: NonNull<GcBox<T>>) -> Gc<T> {
assert!(mem::align_of_val::<GcBox<T>>(ptr.as_ref()) > 1);
ptr.as_ref().value().unroot();
let gc = Gc {
ptr_root: Cell::new(ptr),
marker: PhantomData,
};
gc.set_root();
gc
}
}
impl<T: ?Sized> Gc<T> {
pub fn ptr_eq(this: &Gc<T>, other: &Gc<T>) -> bool {
GcBox::ptr_eq(this.inner(), other.inner())
}
pub fn as_ptr(this: &Gc<T>) -> *const T {
let ptr = this.inner_ptr();
GcBox::value_ptr(ptr)
}
}
unsafe fn clear_root_bit<T: ?Sized>(ptr: NonNull<GcBox<T>>) -> NonNull<GcBox<T>> {
let ptr = ptr.as_ptr();
let data = ptr.cast::<u8>();
let addr = data as isize;
let ptr = set_data_ptr(ptr, data.wrapping_offset((addr & !1) - addr));
NonNull::new_unchecked(ptr)
}
impl<T: ?Sized> Gc<T> {
fn rooted(&self) -> bool {
self.ptr_root.get().as_ptr().cast::<u8>() as usize & 1 != 0
}
unsafe fn set_root(&self) {
let ptr = self.ptr_root.get().as_ptr();
let data = ptr.cast::<u8>();
let addr = data as isize;
let ptr = set_data_ptr(ptr, data.wrapping_offset((addr | 1) - addr));
self.ptr_root.set(NonNull::new_unchecked(ptr));
}
unsafe fn clear_root(&self) {
self.ptr_root.set(clear_root_bit(self.ptr_root.get()));
}
#[inline]
fn inner_ptr(&self) -> *mut GcBox<T> {
assert!(finalizer_safe() || self.rooted());
unsafe { clear_root_bit(self.ptr_root.get()).as_ptr() }
}
#[inline]
fn inner(&self) -> &GcBox<T> {
unsafe { &*self.inner_ptr() }
}
}
impl<T: ?Sized> Gc<T> {
pub fn into_raw(this: Self) -> *const T {
GcBox::value_ptr(ManuallyDrop::new(this).inner_ptr())
}
pub unsafe fn from_raw(ptr: *const T) -> Self {
let (_, offset) = Layout::new::<GcBoxHeader>()
.extend(Layout::for_value::<T>(&*ptr))
.unwrap();
let fake_ptr = ptr as *mut GcBox<T>;
let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-(offset as isize)));
let gc = Gc {
ptr_root: Cell::new(NonNull::new_unchecked(rc_ptr)),
marker: PhantomData,
};
gc.set_root();
gc
}
}
impl<T: ?Sized> Finalize for Gc<T> {}
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.rooted(), "Can't double-root a Gc<T>");
self.inner().root_inner();
self.set_root();
}
#[inline]
unsafe fn unroot(&self) {
assert!(self.rooted(), "Can't double-unroot a Gc<T>");
self.inner().unroot_inner();
self.clear_root();
}
#[inline]
fn finalize_glue(&self) {
Finalize::finalize(self);
}
}
impl<T: ?Sized> Clone for Gc<T> {
#[inline]
fn clone(&self) -> Self {
unsafe {
self.inner().root_inner();
let gc = Gc {
ptr_root: Cell::new(self.ptr_root.get()),
marker: PhantomData,
};
gc.set_root();
gc
}
}
}
impl<T: ?Sized> Deref for Gc<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.inner().value()
}
}
impl<T: ?Sized> Drop for Gc<T> {
#[inline]
fn drop(&mut self) {
if self.rooted() {
unsafe {
self.inner().unroot_inner();
}
}
}
}
impl<T: Trace + Default> Default for Gc<T> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T: ?Sized + PartialEq> PartialEq for Gc<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T: ?Sized + Eq> Eq for Gc<T> {}
impl<T: ?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: ?Sized + Ord> Ord for Gc<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized + Hash> Hash for Gc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: ?Sized + Display> Display for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
impl<T: ?Sized + Debug> Debug for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&**self, f)
}
}
impl<T: ?Sized> fmt::Pointer for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.inner(), f)
}
}
impl<T: Trace> From<T> for Gc<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}
impl<
#[cfg(not(feature = "nightly"))] T: Trace,
#[cfg(feature = "nightly")] T: Trace + Unsize<dyn Trace> + ?Sized,
> From<Box<T>> for Gc<T>
{
fn from(v: Box<T>) -> Gc<T> {
unsafe { Gc::from_gcbox(GcBox::from_box(v)) }
}
}
impl<T: ?Sized> std::borrow::Borrow<T> for Gc<T> {
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized> std::convert::AsRef<T> for Gc<T> {
fn as_ref(&self) -> &T {
self
}
}
#[derive(Copy, Clone)]
struct BorrowFlag(usize);
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum BorrowState {
Reading,
Writing,
Unused,
}
const ROOT: usize = 1;
const WRITING: usize = !1;
const UNUSED: usize = 0;
const BORROWFLAG_INIT: BorrowFlag = BorrowFlag(1);
impl BorrowFlag {
fn borrowed(self) -> BorrowState {
match self.0 & !ROOT {
UNUSED => BorrowState::Unused,
WRITING => BorrowState::Writing,
_ => BorrowState::Reading,
}
}
fn rooted(self) -> bool {
self.0 & ROOT != 0
}
fn set_writing(self) -> Self {
BorrowFlag(self.0 | WRITING)
}
fn set_unused(self) -> Self {
BorrowFlag(self.0 & ROOT)
}
fn add_reading(self) -> Self {
assert!(self.borrowed() != BorrowState::Writing);
BorrowFlag(self.0 + 0b10)
}
fn sub_reading(self) -> Self {
assert!(self.borrowed() == BorrowState::Reading);
BorrowFlag(self.0 - 0b10)
}
fn set_rooted(self, rooted: bool) -> Self {
BorrowFlag((self.0 & !ROOT) | usize::from(rooted))
}
}
pub struct GcCell<T: ?Sized + 'static> {
flags: Cell<BorrowFlag>,
cell: UnsafeCell<T>,
}
impl<T> GcCell<T> {
#[inline]
pub fn new(value: T) -> Self {
GcCell {
flags: Cell::new(BORROWFLAG_INIT),
cell: UnsafeCell::new(value),
}
}
#[inline]
pub fn into_inner(self) -> T {
self.cell.into_inner()
}
}
impl<T: ?Sized> GcCell<T> {
#[inline]
#[track_caller]
pub fn borrow(&self) -> GcCellRef<'_, T> {
match self.try_borrow() {
Ok(value) => value,
Err(e) => panic!("{}", e),
}
}
}
impl<T: Trace + ?Sized> GcCell<T> {
#[inline]
#[track_caller]
pub fn borrow_mut(&self) -> GcCellRefMut<'_, T> {
match self.try_borrow_mut() {
Ok(value) => value,
Err(e) => panic!("{}", e),
}
}
}
impl<T: ?Sized> GcCell<T> {
pub fn try_borrow(&self) -> Result<GcCellRef<'_, T>, BorrowError> {
if self.flags.get().borrowed() == BorrowState::Writing {
return Err(BorrowError);
}
self.flags.set(self.flags.get().add_reading());
assert!(self.flags.get().borrowed() == BorrowState::Reading);
unsafe {
Ok(GcCellRef {
flags: &self.flags,
value: &*self.cell.get(),
})
}
}
}
impl<T: Trace + ?Sized> GcCell<T> {
pub fn try_borrow_mut(&self) -> Result<GcCellRefMut<'_, T>, BorrowMutError> {
if self.flags.get().borrowed() != BorrowState::Unused {
return Err(BorrowMutError);
}
self.flags.set(self.flags.get().set_writing());
unsafe {
if !self.flags.get().rooted() {
(*self.cell.get()).root();
}
Ok(GcCellRefMut {
gc_cell: self,
value: &mut *self.cell.get(),
})
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
pub struct BorrowError;
impl std::fmt::Display for BorrowError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt("GcCell<T> already mutably borrowed", f)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
pub struct BorrowMutError;
impl std::fmt::Display for BorrowMutError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt("GcCell<T> already borrowed", f)
}
}
impl<T: ?Sized> Finalize for GcCell<T> {}
unsafe impl<T: Trace + ?Sized> Trace for GcCell<T> {
#[inline]
unsafe fn trace(&self) {
match self.flags.get().borrowed() {
BorrowState::Writing => (),
_ => (*self.cell.get()).trace(),
}
}
#[inline]
unsafe fn root(&self) {
assert!(!self.flags.get().rooted(), "Can't root a GcCell twice!");
self.flags.set(self.flags.get().set_rooted(true));
match self.flags.get().borrowed() {
BorrowState::Writing => (),
_ => (*self.cell.get()).root(),
}
}
#[inline]
unsafe fn unroot(&self) {
assert!(self.flags.get().rooted(), "Can't unroot a GcCell twice!");
self.flags.set(self.flags.get().set_rooted(false));
match self.flags.get().borrowed() {
BorrowState::Writing => (),
_ => (*self.cell.get()).unroot(),
}
}
#[inline]
fn finalize_glue(&self) {
Finalize::finalize(self);
match self.flags.get().borrowed() {
BorrowState::Writing => (),
_ => unsafe { (*self.cell.get()).finalize_glue() },
}
}
}
pub struct GcCellRef<'a, T: ?Sized + 'static> {
flags: &'a Cell<BorrowFlag>,
value: &'a T,
}
impl<'a, T: ?Sized> GcCellRef<'a, T> {
#[allow(clippy::should_implement_trait)]
#[inline]
#[must_use]
pub fn clone(orig: &GcCellRef<'a, T>) -> GcCellRef<'a, T> {
orig.flags.set(orig.flags.get().add_reading());
GcCellRef {
flags: orig.flags,
value: orig.value,
}
}
#[inline]
pub fn map<U, F>(orig: Self, f: F) -> GcCellRef<'a, U>
where
U: ?Sized,
F: FnOnce(&T) -> &U,
{
let value = f(orig.value);
let orig = ManuallyDrop::new(orig);
GcCellRef {
flags: orig.flags,
value,
}
}
#[inline]
pub fn filter_map<U, F>(orig: Self, f: F) -> Result<GcCellRef<'a, U>, Self>
where
U: ?Sized,
F: FnOnce(&T) -> Option<&U>,
{
match f(orig.value) {
None => Err(orig),
Some(value) => {
let orig = ManuallyDrop::new(orig);
Ok(GcCellRef {
flags: orig.flags,
value,
})
}
}
}
#[inline]
pub fn map_split<U, V, F>(orig: Self, f: F) -> (GcCellRef<'a, U>, GcCellRef<'a, V>)
where
U: ?Sized,
V: ?Sized,
F: FnOnce(&T) -> (&U, &V),
{
let (a, b) = f(orig.value);
orig.flags.set(orig.flags.get().add_reading());
let orig = ManuallyDrop::new(orig);
(
GcCellRef {
flags: orig.flags,
value: a,
},
GcCellRef {
flags: orig.flags,
value: b,
},
)
}
}
impl<'a, T: ?Sized> Deref for GcCellRef<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value
}
}
impl<'a, T: ?Sized> Drop for GcCellRef<'a, T> {
fn drop(&mut self) {
debug_assert!(self.flags.get().borrowed() == BorrowState::Reading);
self.flags.set(self.flags.get().sub_reading());
}
}
impl<'a, T: ?Sized + Debug> Debug for GcCellRef<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&**self, f)
}
}
impl<'a, T: ?Sized + Display> Display for GcCellRef<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
pub struct GcCellRefMut<'a, T: Trace + ?Sized + 'static, U: ?Sized = T> {
gc_cell: &'a GcCell<T>,
value: &'a mut U,
}
impl<'a, T: Trace + ?Sized, U: ?Sized> GcCellRefMut<'a, T, U> {
#[inline]
pub fn map<V, F>(orig: Self, f: F) -> GcCellRefMut<'a, T, V>
where
V: ?Sized,
F: FnOnce(&mut U) -> &mut V,
{
let gc_cell = orig.gc_cell;
let orig = mem::MaybeUninit::new(orig);
let value = unsafe { ptr::addr_of!((*orig.as_ptr()).value).read() };
GcCellRefMut {
gc_cell,
value: f(value),
}
}
#[inline]
pub fn filter_map<V, F>(orig: Self, f: F) -> Result<GcCellRefMut<'a, T, V>, Self>
where
V: ?Sized,
F: FnOnce(&mut U) -> Option<&mut V>,
{
let gc_cell = orig.gc_cell;
let orig = mem::MaybeUninit::new(orig);
let value = unsafe { ptr::addr_of!((*orig.as_ptr()).value).read() };
match f(value) {
None => Err(unsafe { orig.assume_init() }),
Some(value) => Ok(GcCellRefMut { gc_cell, value }),
}
}
}
impl<'a, T: Trace + ?Sized, U: ?Sized> Deref for GcCellRefMut<'a, T, U> {
type Target = U;
#[inline]
fn deref(&self) -> &U {
self.value
}
}
impl<'a, T: Trace + ?Sized, U: ?Sized> DerefMut for GcCellRefMut<'a, T, U> {
#[inline]
fn deref_mut(&mut self) -> &mut U {
self.value
}
}
impl<'a, T: Trace + ?Sized, U: ?Sized> Drop for GcCellRefMut<'a, T, U> {
#[inline]
fn drop(&mut self) {
debug_assert!(self.gc_cell.flags.get().borrowed() == BorrowState::Writing);
if !self.gc_cell.flags.get().rooted() {
unsafe {
(*self.gc_cell.cell.get()).unroot();
}
}
self.gc_cell
.flags
.set(self.gc_cell.flags.get().set_unused());
}
}
impl<'a, T: Trace + ?Sized, U: Debug + ?Sized> Debug for GcCellRefMut<'a, T, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&**self, f)
}
}
impl<'a, T: Trace + ?Sized, U: Display + ?Sized> Display for GcCellRefMut<'a, T, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
unsafe impl<T: ?Sized + Send> Send for GcCell<T> {}
impl<T: Clone> Clone for GcCell<T> {
#[inline]
fn clone(&self) -> Self {
Self::new(self.borrow().clone())
}
}
impl<T: Default> Default for GcCell<T> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T: ?Sized + PartialEq> PartialEq for GcCell<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
*self.borrow() == *other.borrow()
}
}
impl<T: ?Sized + Eq> Eq for GcCell<T> {}
impl<T: ?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: ?Sized + Ord> Ord for GcCell<T> {
#[inline]
fn cmp(&self, other: &GcCell<T>) -> Ordering {
(*self.borrow()).cmp(&*other.borrow())
}
}
impl<T: ?Sized + Debug> Debug for GcCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.flags.get().borrowed() {
BorrowState::Unused | BorrowState::Reading => f
.debug_struct("GcCell")
.field("value", &self.borrow())
.finish(),
BorrowState::Writing => f
.debug_struct("GcCell")
.field("value", &"<borrowed>")
.finish(),
}
}
}
unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
ptr::addr_of_mut!(ptr)
.cast::<*mut u8>()
.write(data.cast::<u8>());
ptr
}