#![allow(dead_code)]
use std::cell::Cell;
use std::rc::Rc;
struct Token {
alive: Cell<bool>,
}
pub struct StrongOwner<T> {
value: T,
token: Rc<Token>,
}
impl<T> StrongOwner<T> {
pub fn new(value: T) -> (Self, WeakRef<T>) {
let token = Rc::new(Token {
alive: Cell::new(true),
});
let weak = WeakRef {
token: Rc::clone(&token),
_marker: std::marker::PhantomData,
};
(Self { value, token }, weak)
}
pub fn get(&self) -> &T {
&self.value
}
}
impl<T> Drop for StrongOwner<T> {
fn drop(&mut self) {
self.token.alive.set(false);
}
}
pub struct WeakRef<T> {
token: Rc<Token>,
_marker: std::marker::PhantomData<*const T>,
}
impl<T> WeakRef<T> {
pub fn is_alive(&self) -> bool {
self.token.alive.get()
}
pub fn is_dangling(&self) -> bool {
!self.is_alive()
}
pub fn token_ref_count(&self) -> usize {
Rc::strong_count(&self.token)
}
}
pub fn new_weak_pair<T>(value: T) -> (StrongOwner<T>, WeakRef<T>) {
StrongOwner::new(value)
}
pub fn weak_is_alive<T>(w: &WeakRef<T>) -> bool {
w.is_alive()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alive_while_owner_exists() {
let (owner, weak) = StrongOwner::new(42);
assert!(weak.is_alive());
drop(owner);
}
#[test]
fn test_dangling_after_owner_drop() {
let (owner, weak) = StrongOwner::new(42);
drop(owner);
assert!(weak.is_dangling());
}
#[test]
fn test_get() {
let (owner, _weak) = StrongOwner::new(99);
assert_eq!(*owner.get(), 99);
}
#[test]
fn test_is_alive_helper() {
let (_owner, weak) = StrongOwner::new(0);
assert!(weak_is_alive(&weak));
}
#[test]
fn test_new_pair_helper() {
let (_owner, weak) = new_weak_pair(1u32);
assert!(weak.is_alive());
}
#[test]
fn test_multiple_weakrefs_not_supported_directly() {
let (owner, weak) = StrongOwner::new("hello");
assert!(weak.is_alive());
drop(owner);
assert!(!weak.is_alive());
}
#[test]
fn test_token_ref_count_alive() {
let (_owner, weak) = StrongOwner::new(5);
assert_eq!(weak.token_ref_count(), 2);
}
#[test]
fn test_token_ref_count_dead() {
let (owner, weak) = StrongOwner::new(5);
drop(owner);
assert_eq!(weak.token_ref_count(), 1);
}
#[test]
fn test_is_not_dangling_when_alive() {
let (_owner, weak) = StrongOwner::new(0);
assert!(!weak.is_dangling());
}
#[test]
fn test_string_value() {
let (owner, weak) = StrongOwner::new(String::from("hello"));
assert_eq!(owner.get(), "hello");
drop(owner);
assert!(weak.is_dangling());
}
}