wrc 2.0.0

A thread-safe weighted reference counting smart-pointer for Rust.
Documentation
use crate::weight::Weight;
use crate::Wrc;
use std::cell::Cell;
use std::ops::DerefMut;

struct Canary<'a>(&'a Cell<usize>);

impl<'a> Drop for Canary<'a> {
    fn drop(&mut self) {
        let drop_count = self.0.get();
        self.0.set(drop_count + 1);
    }
}

#[test]
fn initializes_with_default_weight() {
    let wrc = Wrc::new(5);
    assert_eq!(wrc.get_weight(), 1 << 16);
    assert_eq!(Wrc::total_weight(&wrc), 1 << 16);
}

#[test]
fn clone_splits_weight() {
    let wrc0 = Wrc::new(5);
    assert_eq!(wrc0.get_weight(), 1 << 16);

    let wrc1 = wrc0.clone();
    assert_eq!(
        wrc0.get_weight() + wrc1.get_weight(),
        Wrc::total_weight(&wrc0)
    );
}

#[allow(clippy::redundant_clone)]
#[test]
fn more_weight_is_allocated_with_weight_exhausted() {
    let wrc0 = Wrc::new(5);
    let wrc1 = wrc0
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone()
        .clone();
    assert_eq!(wrc1.get_weight(), 1);

    // Intermediate weights are dropped because they go out of scope.
    assert_eq!(Wrc::total_weight(&wrc0), (1 << 15) + 1);

    let wrc2 = wrc1.clone();
    assert_eq!(wrc1.get_weight(), 1);
    assert_eq!(wrc2.get_weight(), 1 << 16);
    assert_eq!(Wrc::total_weight(&wrc0), (1 << 15) + 1 + (1 << 16));
}

#[test]
fn dropping_refs_drops_weight_from_inner() {
    let wrc0 = Wrc::new(5);
    let wrc1 = wrc0.clone();
    let wrc2 = wrc1.clone();
    let wrc3 = wrc2.clone();

    assert_eq!(wrc0.get_weight(), 1 << 15);
    assert_eq!(wrc1.get_weight(), 1 << 14);
    assert_eq!(wrc2.get_weight(), 1 << 13);
    assert_eq!(wrc3.get_weight(), 1 << 13);
    assert_eq!(Wrc::total_weight(&wrc0), 1 << 16);

    drop(wrc3);
    assert_eq!(Wrc::total_weight(&wrc0), (1 << 16) - (1 << 13));
    drop(wrc2);
    assert_eq!(Wrc::total_weight(&wrc0), (1 << 16) - (1 << 14));
    drop(wrc1);
    assert_eq!(Wrc::total_weight(&wrc0), 1 << 15);
}

#[test]
fn dropping_all_refs_drops_the_inner() {
    let drop_count = Cell::new(0);
    let wrc0 = Wrc::new(Canary(&drop_count));
    let wrc1 = wrc0.clone();
    assert_eq!(drop_count.get(), 0);
    drop(wrc0);
    assert_eq!(drop_count.get(), 0);
    drop(wrc1);
    assert_eq!(drop_count.get(), 1);
}

#[test]
fn deref_mut() {
    let mut wrc = Wrc::new(5);
    {
        let mutref = wrc.deref_mut();
        *mutref = 13;
    }
    assert_eq!(*wrc, 13);
}