#![allow(dead_code)]
use std::cell::Cell;
struct RcInner<T> {
value: T,
strong: Cell<usize>,
}
pub struct RefCounted<T> {
inner: *mut RcInner<T>,
}
impl<T> RefCounted<T> {
pub fn new(value: T) -> Self {
let inner = Box::into_raw(Box::new(RcInner {
value,
strong: Cell::new(1),
}));
Self { inner }
}
pub fn ref_count(&self) -> usize {
unsafe { (*self.inner).strong.get() }
}
pub fn get(&self) -> &T {
unsafe { &(*self.inner).value }
}
pub fn clone_handle(&self) -> Self {
let count = unsafe { (*self.inner).strong.get() };
unsafe { (*self.inner).strong.set(count + 1) };
Self { inner: self.inner }
}
pub fn is_unique(&self) -> bool {
self.ref_count() == 1
}
}
impl<T> Drop for RefCounted<T> {
fn drop(&mut self) {
let count = unsafe { (*self.inner).strong.get() };
if count == 1 {
unsafe { drop(Box::from_raw(self.inner)) };
} else {
unsafe { (*self.inner).strong.set(count - 1) };
}
}
}
pub fn new_ref_counted<T>(value: T) -> RefCounted<T> {
RefCounted::new(value)
}
pub fn rc_count<T>(handle: &RefCounted<T>) -> usize {
handle.ref_count()
}
pub fn rc_is_unique<T>(handle: &RefCounted<T>) -> bool {
handle.is_unique()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_initial_count() {
let h = RefCounted::new(42);
assert_eq!(h.ref_count(), 1);
}
#[test]
fn test_clone_increments() {
let h = RefCounted::new(42);
let h2 = h.clone_handle();
assert_eq!(h.ref_count(), 2);
assert_eq!(h2.ref_count(), 2);
}
#[test]
fn test_get() {
let h = RefCounted::new(99);
assert_eq!(*h.get(), 99);
}
#[test]
fn test_drop_decrements() {
let h = RefCounted::new(1);
{
let _h2 = h.clone_handle();
assert_eq!(h.ref_count(), 2);
}
assert_eq!(h.ref_count(), 1);
}
#[test]
fn test_is_unique_true() {
let h = RefCounted::new(5);
assert!(h.is_unique());
}
#[test]
fn test_is_unique_false() {
let h = RefCounted::new(5);
let _h2 = h.clone_handle();
assert!(!h.is_unique());
}
#[test]
fn test_new_helper() {
let h = new_ref_counted(7u32);
assert_eq!(*h.get(), 7);
}
#[test]
fn test_rc_count_helper() {
let h = RefCounted::new(3);
assert_eq!(rc_count(&h), 1);
}
#[test]
fn test_rc_is_unique_helper() {
let h = RefCounted::new(0);
assert!(rc_is_unique(&h));
}
#[test]
fn test_multiple_clones() {
let h = RefCounted::new(0);
let h2 = h.clone_handle();
let h3 = h.clone_handle();
assert_eq!(h.ref_count(), 3);
drop(h2);
drop(h3);
assert_eq!(h.ref_count(), 1);
}
}