wrc 0.2.0

A thread-safe weighted reference counting smart-pointer for Rust.
use WRC;
use weight::Weight;
use std::cell::Cell;

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(), 1 << 15);
    assert_eq!(wrc1.get_weight(), 1 << 15);
    assert_eq!(WRC::total_weight(&wrc0), 1 << 16);
}

#[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);
}