#![deny(missing_docs)]
extern crate core;
use core::alloc::Layout;
use core::cell::Cell;
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::mem::forget;
use core::ops::Deref;
use core::ptr::{self, NonNull};
use std::alloc::dealloc;
pub mod trace;
pub use trace::{Trace, Tracer};
pub mod collect;
pub use collect::{collect_cycles, number_of_roots_buffered};
mod cc_box_ptr;
use cc_box_ptr::CcBoxPtr;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub enum Color {
Black,
Gray,
White,
Purple,
#[allow(dead_code)]
Red,
#[allow(dead_code)]
Orange,
}
#[derive(Debug)]
#[doc(hidden)]
pub struct CcBoxData {
strong: Cell<usize>,
weak: Cell<usize>,
buffered: Cell<bool>,
color: Cell<Color>,
}
impl CcBoxData {
#[inline]
fn color(&self) -> Color {
self.color.get()
}
#[inline]
fn buffered(&self) -> bool {
self.buffered.get()
}
#[inline]
fn strong(&self) -> usize {
self.strong.get()
}
#[inline]
fn inc_strong(&self) {
self.strong.set(self.strong() + 1);
self.color.set(Color::Black);
}
#[inline]
fn dec_strong(&self) {
self.strong.set(self.strong() - 1);
}
#[inline]
fn weak(&self) -> usize {
self.weak.get()
}
#[inline]
fn inc_weak(&self) {
self.weak.set(self.weak() + 1);
}
#[inline]
fn dec_weak(&self) {
self.weak.set(self.weak() - 1);
}
}
#[derive(Debug)]
struct CcBox<T: Trace> {
value: T,
data: CcBoxData,
}
pub struct Cc<T: 'static + Trace> {
_ptr: NonNull<CcBox<T>>,
}
impl<T: Trace> Cc<T> {
pub fn new(value: T) -> Cc<T> {
unsafe {
Cc {
_ptr: NonNull::new_unchecked(Box::into_raw(Box::new(CcBox {
value,
data: CcBoxData {
strong: Cell::new(1),
weak: Cell::new(1),
buffered: Cell::new(false),
color: Cell::new(Color::Black),
},
}))),
}
}
}
pub fn downgrade(&self) -> Weak<T> {
self.data().inc_weak();
Weak { _ptr: self._ptr }
}
}
impl<T: Trace> Cc<T> {
unsafe fn release(&mut self) {
debug_assert!(self.data().strong() == 0);
crate::drop_value(self._ptr);
self._ptr.as_ref().data().color.set(Color::Black);
if self.data().buffered() {
return;
}
crate::cc_box_ptr::free(self._ptr);
}
fn possible_root(&mut self) {
debug_assert!(self.data().strong() > 0);
if self.data().color() == Color::Purple {
return;
}
self.data().color.set(Color::Purple);
if self.data().buffered() {
return;
}
self.data().buffered.set(true);
let ptr: NonNull<dyn CcBoxPtr> = self._ptr;
collect::add_root(ptr);
}
}
impl<T: 'static + Trace> Cc<T> {
#[inline]
pub fn is_unique(&self) -> bool {
self.weak_count() == 0 && self.strong_count() == 1
}
#[inline]
pub fn try_unwrap(self) -> Result<T, Cc<T>> {
if self.is_unique() {
unsafe {
let val = ptr::read(&*self);
dealloc(self._ptr.cast().as_ptr(), Layout::new::<CcBox<T>>());
forget(self);
Ok(val)
}
} else {
Err(self)
}
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.is_unique() {
let inner = unsafe { self._ptr.as_mut() };
Some(&mut inner.value)
} else {
None
}
}
#[inline]
pub fn strong_count(&self) -> usize {
self.data().strong()
}
#[inline]
pub fn weak_count(&self) -> usize {
self.data().weak() - 1
}
}
impl<T: 'static + Clone + Trace> Cc<T> {
#[inline]
pub fn make_unique(&mut self) -> &mut T {
if !self.is_unique() {
*self = Cc::new((**self).clone())
}
let inner = unsafe { self._ptr.as_mut() };
&mut inner.value
}
}
impl<T: Trace> Cc<T> {
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this._ptr.as_ptr() == other._ptr.as_ptr()
}
}
impl<T: Trace> Deref for Cc<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
if self.strong_count() > 0 {
unsafe { &self._ptr.as_ref().value }
} else {
panic!("Invalid access during cycle collection");
}
}
}
impl<T: Trace> Drop for Cc<T> {
fn drop(&mut self) {
unsafe {
if self.data().strong() > 0 {
self.data().dec_strong();
if self.data().strong() == 0 {
self.release();
} else {
self.possible_root();
}
}
}
}
}
impl<T: Trace> Clone for Cc<T> {
#[inline]
fn clone(&self) -> Cc<T> {
self.data().inc_strong();
Cc { _ptr: self._ptr }
}
}
impl<T: Default + Trace> Default for Cc<T> {
#[inline]
fn default() -> Cc<T> {
Cc::new(Default::default())
}
}
impl<T: PartialEq + Trace> PartialEq for Cc<T> {
#[inline(always)]
fn eq(&self, other: &Cc<T>) -> bool {
**self == **other
}
#[inline(always)]
fn ne(&self, other: &Cc<T>) -> bool {
**self != **other
}
}
impl<T: Eq + Trace> Eq for Cc<T> {}
impl<T: PartialOrd + Trace> PartialOrd for Cc<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Cc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
#[inline(always)]
fn lt(&self, other: &Cc<T>) -> bool {
**self < **other
}
#[inline(always)]
fn le(&self, other: &Cc<T>) -> bool {
**self <= **other
}
#[inline(always)]
fn gt(&self, other: &Cc<T>) -> bool {
**self > **other
}
#[inline(always)]
fn ge(&self, other: &Cc<T>) -> bool {
**self >= **other
}
}
impl<T: Ord + Trace> Ord for Cc<T> {
#[inline]
fn cmp(&self, other: &Cc<T>) -> Ordering {
(**self).cmp(&**other)
}
}
impl<T: Hash + Trace> Hash for Cc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: fmt::Display + Trace> fmt::Display for Cc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<T: fmt::Debug + Trace> fmt::Debug for Cc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: Trace> fmt::Pointer for Cc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self._ptr, f)
}
}
pub struct Weak<T: Trace> {
_ptr: NonNull<CcBox<T>>,
}
impl<T: Trace> Weak<T> {
pub fn upgrade(&self) -> Option<Cc<T>> {
if self.data().strong() == 0 {
None
} else {
self.data().inc_strong();
Some(Cc { _ptr: self._ptr })
}
}
}
impl<T: Trace> Drop for Weak<T> {
fn drop(&mut self) {
unsafe {
if self.data().weak() > 0 {
self.data().dec_weak();
if self.data().weak() == 0 {
dealloc(self._ptr.cast().as_ptr(), Layout::new::<CcBox<T>>())
}
}
}
}
}
impl<T: Trace> Clone for Weak<T> {
#[inline]
fn clone(&self) -> Weak<T> {
self.data().inc_weak();
Weak { _ptr: self._ptr }
}
}
impl<T: fmt::Debug + Trace> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
}
impl<T: Trace> Trace for Cc<T> {
fn trace(&self, tracer: &mut Tracer) {
tracer(self._ptr);
}
}
impl<T: Trace> Trace for Weak<T> {
fn trace(&self, _tracer: &mut Tracer) {
}
}
impl<T: Trace> Trace for CcBox<T> {
fn trace(&self, tracer: &mut Tracer) {
Trace::trace(&self.value, tracer);
}
}
impl<T: Trace> Cc<T> {
#[inline(always)]
fn data(&self) -> &CcBoxData {
unsafe {
&self._ptr.as_ref().data
}
}
}
impl<T: Trace> Weak<T> {
#[inline(always)]
fn data(&self) -> &CcBoxData {
unsafe {
&(*self._ptr.as_ptr()).data
}
}
}
impl<T: Trace> CcBoxPtr for CcBox<T> {
#[inline(always)]
fn data(&self) -> &CcBoxData {
&self.data
}
}
unsafe fn deallocate(ptr: NonNull<dyn CcBoxPtr>) {
dealloc(ptr.cast().as_ptr(), Layout::for_value(ptr.as_ref()));
}
pub(crate) unsafe fn drop_value(ptr: NonNull<dyn CcBoxPtr>) {
ptr::drop_in_place(ptr.as_ptr());
}
#[cfg(test)]
mod tests {
use core::cell::RefCell;
use super::{collect_cycles, Cc, Trace, Tracer, Weak};
#[test]
fn test_clone() {
{
let x = Cc::new(RefCell::new(5));
let y = x.clone();
*x.borrow_mut() = 20;
assert_eq!(*y.borrow(), 20);
}
collect_cycles();
}
#[test]
fn test_simple() {
let x = Cc::new(5);
assert_eq!(*x, 5);
}
#[test]
fn test_simple_clone() {
{
let x = Cc::new(5);
let y = x.clone();
assert_eq!(*x, 5);
assert_eq!(*y, 5);
}
collect_cycles();
}
#[test]
fn test_destructor() {
let x: Cc<Box<_>> = Cc::new(Box::new(5));
assert_eq!(**x, 5);
}
#[test]
fn test_live() {
{
let x = Cc::new(5);
let y = x.downgrade();
assert!(y.upgrade().is_some());
}
collect_cycles();
}
#[test]
fn test_dead() {
let x = Cc::new(5);
let y = x.downgrade();
drop(x);
assert!(y.upgrade().is_none());
}
#[test]
fn weak_self_cyclic() {
{
struct Cycle {
x: RefCell<Option<Weak<Cycle>>>,
}
impl Trace for Cycle {
fn trace(&self, _: &mut Tracer) {}
}
let a = Cc::new(Cycle {
x: RefCell::new(None),
});
let b = a.clone().downgrade();
*a.x.borrow_mut() = Some(b);
}
collect_cycles();
}
#[test]
fn is_unique() {
{
let x = Cc::new(3);
assert!(x.is_unique());
let y = x.clone();
assert!(!x.is_unique());
drop(y);
assert!(x.is_unique());
let w = x.downgrade();
assert!(!x.is_unique());
drop(w);
assert!(x.is_unique());
}
collect_cycles();
}
#[test]
fn test_strong_count() {
{
let a = Cc::new(0u32);
assert!(a.strong_count() == 1);
let w = a.downgrade();
assert!(a.strong_count() == 1);
let b = w.upgrade().expect("upgrade of live rc failed");
assert!(b.strong_count() == 2);
assert!(b.strong_count() == 2);
drop(w);
drop(a);
assert!(b.strong_count() == 1);
let c = b.clone();
assert!(b.strong_count() == 2);
assert!(c.strong_count() == 2);
}
collect_cycles();
}
#[test]
fn test_weak_count() {
{
let a = Cc::new(0u32);
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 0);
let w = a.downgrade();
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 1);
drop(w);
assert!(a.strong_count() == 1);
assert!(a.weak_count() == 0);
let c = a.clone();
assert!(a.strong_count() == 2);
assert!(a.weak_count() == 0);
drop(c);
}
collect_cycles();
}
#[test]
fn try_unwrap() {
{
let x = Cc::new(3);
assert_eq!(x.try_unwrap(), Ok(3));
let x = Cc::new(4);
let _y = x.clone();
assert_eq!(x.try_unwrap(), Err(Cc::new(4)));
let x = Cc::new(5);
let _w = x.downgrade();
assert_eq!(x.try_unwrap(), Err(Cc::new(5)));
}
collect_cycles();
}
#[test]
fn get_mut() {
{
let mut x = Cc::new(3);
*x.get_mut().unwrap() = 4;
assert_eq!(*x, 4);
let y = x.clone();
assert!(x.get_mut().is_none());
drop(y);
assert!(x.get_mut().is_some());
let _w = x.downgrade();
assert!(x.get_mut().is_none());
}
collect_cycles();
}
#[test]
fn test_cowrc_clone_make_unique() {
{
let mut cow0 = Cc::new(75);
let mut cow1 = cow0.clone();
let mut cow2 = cow1.clone();
assert!(75 == *cow0.make_unique());
assert!(75 == *cow1.make_unique());
assert!(75 == *cow2.make_unique());
*cow0.make_unique() += 1;
*cow1.make_unique() += 2;
*cow2.make_unique() += 3;
assert!(76 == *cow0);
assert!(77 == *cow1);
assert!(78 == *cow2);
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 != *cow2);
}
collect_cycles();
}
#[test]
fn test_cowrc_clone_unique2() {
{
let mut cow0 = Cc::new(75);
let cow1 = cow0.clone();
let cow2 = cow1.clone();
assert!(75 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
*cow0.make_unique() += 1;
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow2);
assert!(*cow0 != *cow1);
assert!(*cow0 != *cow2);
assert!(*cow1 == *cow2);
}
collect_cycles();
}
#[test]
fn test_cowrc_clone_weak() {
{
let mut cow0 = Cc::new(75);
let cow1_weak = cow0.downgrade();
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
*cow0.make_unique() += 1;
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
}
collect_cycles();
}
#[test]
fn test_show() {
let foo = Cc::new(75);
assert_eq!(format!("{:?}", foo), "75");
}
#[cfg(not(all(target_os = "macos", miri)))]
#[test]
fn test_map() {
let mut map = std::collections::HashMap::new();
map.insert("Foo".to_string(), 4);
let x = Cc::new(map);
assert_eq!(x.get("Foo"), Some(&4));
}
#[test]
fn list_cycle() {
use std::cell::RefCell;
struct List(Vec<Cc<RefCell<List>>>);
impl Trace for List {
fn trace(&self, tracer: &mut Tracer) {
self.0.trace(tracer);
}
}
{
let a = Cc::new(RefCell::new(List(Vec::new())));
let b = Cc::new(RefCell::new(List(Vec::new())));
{
let mut a = a.borrow_mut();
a.0.push(b.clone());
}
{
let mut b = b.borrow_mut();
b.0.push(a.clone());
}
}
collect_cycles();
}
#[test]
fn test_retain_weak() {
let retained_weak_a;
{
struct A {
x: Cc<RefCell<Option<A>>>,
}
struct WeakA {
_x: Weak<RefCell<Option<A>>>,
}
impl A {
fn downgrade(this: &Self) -> WeakA {
WeakA {
_x: Cc::downgrade(&this.x),
}
}
}
impl Clone for A {
fn clone(&self) -> Self {
A { x: self.x.clone() }
}
}
impl Trace for A {
fn trace(&self, tracer: &mut Tracer) {
self.x.trace(tracer);
}
}
let a = A {
x: Cc::new(RefCell::new(None)),
};
*a.x.borrow_mut() = Some(a.clone());
retained_weak_a = A::downgrade(&a);
}
collect_cycles();
let _x = retained_weak_a;
}
#[test]
fn test_no_leak_with_double_indirection() {
use crate::collect::*;
#[derive(Debug, Clone)]
struct S {
ty: Cc<Cc<i32>>,
}
let ty = Cc::new(5);
drop(ty.clone());
let s = S { ty: Cc::new(ty) };
drop(s.ty.clone());
std::mem::drop(s);
collect_cycles();
}
#[test]
fn test_double_visit_scan_black() {
let count = std::rc::Rc::new(std::cell::Cell::new(0));
struct A {
count: std::rc::Rc<std::cell::Cell<i32>>,
next_op: Cc<RefCell<Option<A>>>,
}
impl Clone for A {
fn clone(&self) -> Self {
self.count.set(self.count.get() + 1);
A {
count: self.count.clone(),
next_op: self.next_op.clone(),
}
}
}
impl Trace for A {
fn trace(&self, tracer: &mut Tracer) {
self.next_op.trace(tracer);
}
}
impl A {
fn new(count: std::rc::Rc<std::cell::Cell<i32>>, next_op: Option<A>) -> A {
count.set(count.get() + 1);
A {
count,
next_op: Cc::new(RefCell::new(next_op)),
}
}
}
impl Drop for A {
fn drop(&mut self) {
self.count.set(self.count.get() - 1);
}
}
{
let q;
{
let z = A::new(count.clone(), None);
let y = A::new(count.clone(), Some(z.clone()));
let x = A::new(count.clone(), Some(y));
*z.next_op.borrow_mut() = Some(x.clone());
q = x;
}
collect_cycles();
*q.next_op.borrow_mut() = None;
}
collect_cycles();
assert_eq!(count.get(), 0);
}
#[test]
fn extra_free() {
struct Env {
pub closures: Vec<Cc<RefCell<Clos>>>,
pub next: Option<Cc<Env>>,
}
impl Trace for Env {
fn trace(&self, tracer: &mut Tracer) {
self.closures.trace(tracer);
self.next.trace(tracer);
}
}
struct Clos {
pub env: Cc<Env>,
}
impl Trace for Clos {
fn trace(&self, tracer: &mut Tracer) {
self.env.trace(tracer);
}
}
let live_env = {
let base_env = Cc::new(Env {
closures: vec![],
next: None,
});
let env_a = Cc::new(Env {
closures: vec![Cc::new(RefCell::new(Clos {
env: base_env.clone(),
}))],
next: Some(base_env.clone()),
});
let circular_env = Cc::new(Env {
closures: vec![Cc::new(RefCell::new(Clos {
env: base_env.clone(),
}))],
next: Some(env_a.clone()),
});
circular_env.closures[0].replace(Clos {
env: circular_env.clone(),
});
let live_env = Cc::new(Env {
closures: vec![],
next: Some(env_a.clone()),
});
drop(base_env); drop(env_a); collect_cycles();
drop(circular_env); collect_cycles();
live_env
};
if let Some(a) = &live_env.next {
assert_eq!(a.closures.len(), 1);
}
drop(live_env);
collect_cycles();
}
#[test]
fn weak_cycle() {
type Owner = RefCell<Option<Weak<Gadget>>>;
struct Gadget {
owner: Cc<Owner>,
}
impl Trace for Gadget {
fn trace(&self, tracer: &mut Tracer) {
self.owner.trace(tracer);
}
}
let gadget_owner = Cc::new(RefCell::new(None));
let gadget = Cc::new(Gadget {
owner: gadget_owner.clone(),
});
*gadget_owner.borrow_mut() = Some(gadget.clone().downgrade());
drop(gadget_owner);
drop(gadget);
collect_cycles();
}
#[test]
fn clone_drop_collect() {
struct A {
a: Cc<i32>,
}
impl Trace for A {
fn trace(&self, tracer: &mut Tracer) {
self.a.trace(tracer);
}
}
let a = Cc::new(A { a: Cc::new(1) });
let b = Cc::clone(&a);
drop(b);
collect_cycles();
}
}