use crate::genrc::{self, private, Atomicity, Genrc, Global};
use core::cell::Cell;
#[repr(transparent)]
pub struct Nonatomic(Cell<usize>);
impl private::Sealed for Nonatomic {}
unsafe impl Atomicity for Nonatomic {
fn new(v: usize) -> Self {
Nonatomic(Cell::new(v))
}
fn get(&self) -> usize {
Cell::get(&self.0)
}
fn inc_relaxed(&self) -> usize {
let i = self.get();
self.0.set(i + 1);
i
}
fn inc_if_nonzero(&self) -> bool {
let i = self.get();
if i != 0 {
self.0.set(i + 1);
true
} else {
false
}
}
fn set_release(&self, value: usize) {
self.0.set(value);
}
fn dec(&self) -> usize {
let i = self.get();
self.0.set(i - 1);
i
}
fn acquire_fence(&self) {}
}
pub type Rcl<'a, T, A = Global> = Genrc<'a, T, Nonatomic, A, false>;
pub type Weakl<'a, T, A = Global> = genrc::Weak<'a, T, Nonatomic, A>;
pub type Rc<T, A = Global> = Rcl<'static, T, A>;
pub type Weak<T, A = Global> = Weakl<'static, T, A>;
pub type RcBox<'a, T, A = Global> = Genrc<'a, T, Nonatomic, A, true>;
#[cfg(test)]
mod tests {
use super::*;
use alloc::{boxed::Box, format, vec, vec::Vec};
fn counts<T>(x: &Rcl<T>) -> (usize, usize) {
(Rcl::strong_count(x), Rcl::weak_count(x))
}
fn wcounts<T>(x: &Weakl<T>) -> (usize, usize) {
(Weakl::strong_count(x), Weakl::weak_count(x))
}
struct DropCounter<'a, T>(T, &'a mut usize);
impl<'a, T> Drop for DropCounter<'a, T> {
fn drop(&mut self) {
*self.1 += 1;
}
}
#[test]
fn test_simpler() {
let x = Rc::new(2);
assert_eq!(*x, 2);
drop(x);
}
#[test]
fn test_simple() {
let x = Rc::new(2);
let y = x.clone();
assert_eq!(*x, 2);
assert_eq!(&*x as *const i32, &*y as *const i32);
drop(x);
assert_eq!(*y, 2);
}
#[test]
fn test_weak() {
let x = Rc::new(2);
let y = Rc::downgrade(&x);
assert_eq!(wcounts(&y), (1, 1));
drop(x);
drop(y);
}
#[test]
fn test_derived() {
let mut n = 0;
{
let x = Rc::new(DropCounter((1, 2), &mut n));
let y = Rcl::project(x.clone(), |x| &x.0 .0);
let z = Rcl::project(x.clone(), |x| &x.0 .1);
assert_eq!(*y, 1);
assert_eq!(*z, 2);
assert_eq!(counts(&z), (3, 0));
drop(x);
drop(y);
assert_eq!(counts(&z), (1, 0));
drop(z);
}
assert_eq!(n, 1);
{
let x = std::rc::Rc::new(DropCounter((1, 2), &mut n));
let y = x.clone();
let z = y.clone();
drop(x);
drop(y);
drop(z);
}
assert_eq!(n, 2);
}
#[test]
fn test_trait_obj() {
let x = Rc::new(2);
let d = Rc::project(x.clone(), |p| p as &dyn std::fmt::Debug);
assert_eq!(format!("{:?}", d), "2");
}
#[test]
fn test_array_to_slice() {
let x: Rc<[i32; 3]> = Rc::new([1, 2, 3]);
let y: Rc<[i32]> = Rc::project(x.clone(), |p| &p[..]);
let z: Rc<i32> = Rc::project(y.clone(), |p| &p[1]);
assert_eq!(format!("{:?}", y), "[1, 2, 3]");
assert_eq!(format!("{:?}", z), "2");
}
#[test]
fn test_vec_to_slice() {
let x: Rc<Box<[i32]>> = Rc::new(vec![1, 2, 3].into());
let y: Rc<[i32]> = Rc::project(x.clone(), |p| &p[..]);
let z: Rc<i32> = Rc::project(y.clone(), |p| &p[1]);
assert_eq!(format!("{:?}", y), "[1, 2, 3]");
assert_eq!(format!("{:?}", z), "2");
}
#[test]
fn test_cyclic() {
struct Cyclic(Weak<Cyclic>);
let x = Rc::new_cyclic(|p| Cyclic(p.clone()));
assert_eq!(Rc::strong_count(&x), 1);
assert_eq!(Rc::weak_count(&x), 1);
}
#[test]
fn test_oopsie() {
let a: Rc<[i32; 3]> = Rc::new([1, 2, 3]);
let w = Rc::downgrade(&a);
assert_eq!(w.strong_count(), 1);
let b: Rc<[i32]> = Rc::project(a, |x| &x[..]);
let c: Rc<i32> = Rc::project(b, |x| &x[1]);
assert_eq!(w.strong_count(), 1);
assert!(w.upgrade().is_some());
assert_eq!(w.strong_count(), 1);
drop(c);
assert_eq!(w.strong_count(), 0);
assert!(w.upgrade().is_none());
}
#[test]
fn test_ptr_eq() {
let a = Rc::new(1);
let b = Rc::new(1);
let c = a.clone();
assert!(!Rc::ptr_eq(&a, &b));
assert!(Rc::ptr_eq(&a, &c));
{
let obj = Rc::new([1, 1]);
let p1 = Rc::project(obj.clone(), |x| &x[0]);
let p2 = Rc::project(obj.clone(), |x| &x[1]);
assert!(Rcl::root_ptr_eq(&p1, &p2));
assert!(!Rc::ptr_eq(&p1, &p2));
}
{
let obj = "obj";
let p1: Rc<str> = Rc::from_ref(obj);
let p2: Rc<str> = Rc::from_ref(obj);
assert!(!Rcl::root_ptr_eq(&p1, &p2));
assert!(Rcl::ptr_eq(&p1, &p2));
}
}
#[test]
fn test_cmp() {
let a = Rc::new(1);
let b = Rc::new(2);
assert!(a < b);
}
#[test]
fn test_new_unique() {
struct Tree {
parent: Option<Weak<Tree>>,
children: Vec<Rc<Tree>>,
}
let mut root = Rc::new_unique(Tree {
parent: None,
children: vec![],
});
for _ in 1..3 {
let c = Rc::new(Tree {
parent: Some(RcBox::downgrade(&root)),
children: vec![],
});
root.children.push(c);
}
let p = root.children[0].parent.clone();
assert!(p.clone().unwrap().upgrade().is_none());
let root = RcBox::shared(root);
assert!(Rcl::ptr_eq(&p.unwrap().upgrade().unwrap(), &root));
}
#[test]
fn test_project_mut() {
let x: RcBox<[i32; 3]> = RcBox::new([0, 10, 20]);
{
let mut y = RcBox::project_mut(x, |p| &mut p[1]);
assert_eq!(*y, 10);
*y = 11;
}
{
let mut x = [0, 10, 20];
let y = RcBox::new(&mut x);
let mut z: RcBox<i32> = RcBox::project_mut(y, |p| &mut p[1]);
assert_eq!(*z, 10);
*z = 11;
};
}
}
#[cfg(feature = "allocator_api")]
#[cfg(test)]
mod alloc_tests {
use super::*;
#[test]
fn test_custom_alloc() {
use bumpalo::Bump;
let bump = Bump::new();
let alloc = ≎
let p1: Rc<i32, &Bump> = Rc::new_in(17, alloc);
assert!(std::ptr::eq(*Rc::allocator(&p1), alloc));
let p2: Rcl<i32> = Rc::erase_allocator(p1.clone());
assert!(Rcl::ptr_eq(&p1, &p2));
assert!(Rcl::root_ptr_eq(&p1, &p2));
}
}