use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut};
use std::cmp::PartialEq;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::pin::Pin;
use std::rc::{Rc, Weak};
#[derive(Debug, Default, Eq)]
pub struct RcCell<T>(Rc<RefCell<T>>);
#[derive(Debug, Default)]
pub struct WeakCell<T>(Weak<RefCell<T>>);
impl<T> RcCell<T> {
pub fn new(value: T) -> Self {
Self(Rc::new(RefCell::new(value)))
}
pub fn try_unwrap(self) -> Result<T, Self> {
Rc::try_unwrap(self.0)
.map(RefCell::into_inner)
.map_err(Self)
}
pub fn unwrap(self) -> T {
self.try_unwrap().ok().unwrap()
}
pub fn downgrade(&self) -> WeakCell<T> {
WeakCell(Rc::downgrade(&self.0))
}
pub fn weak_count(this: &Self) -> usize {
Rc::weak_count(&this.0)
}
pub fn strong_count(this: &Self) -> usize {
Rc::strong_count(&this.0)
}
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
Rc::ptr_eq(&this.0, &other.0)
}
pub fn try_borrow(&self) -> Result<Ref<T>, BorrowError> {
self.0.try_borrow()
}
pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError> {
self.0.try_borrow_mut()
}
pub fn borrow(&self) -> Ref<T> {
self.0.borrow()
}
pub fn borrow_mut(&self) -> RefMut<T> {
self.0.borrow_mut()
}
}
impl<T: std::marker::Unpin> RcCell<T> {
pub fn pin(value: T) -> Pin<Self> {
Pin::new(Self::new(value))
}
}
impl<T> WeakCell<T> {
pub fn new() -> Self {
Self(Weak::new())
}
pub fn upgrade(&self) -> Option<RcCell<T>> {
self.0.upgrade().map(RcCell)
}
pub fn strong_count(&self) -> usize {
self.0.strong_count()
}
pub fn weak_count(&self) -> usize {
self.0.weak_count()
}
pub fn ptr_eq(&self, other: &Self) -> bool {
self.0.ptr_eq(&other.0)
}
}
impl<T> Clone for RcCell<T> {
fn clone(&self) -> Self {
RcCell(self.0.clone())
}
}
impl<T> Deref for RcCell<T> {
type Target = RefCell<T>;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl<T> Hash for RcCell<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ptr().hash(state);
}
}
impl<T> PartialEq for RcCell<T> {
fn eq(&self, other: &Self) -> bool {
self.0.as_ptr() == other.0.as_ptr()
}
}
impl<T> Clone for WeakCell<T> {
fn clone(&self) -> Self {
WeakCell(self.0.clone())
}
}
#[cfg(test)]
mod tests {
use super::RcCell;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq)]
struct DummyStruct {
name: String,
}
impl DummyStruct {
fn new(name: &str) -> Self {
Self {
name: name.to_string(),
}
}
}
#[test]
fn test_try_unwrap() {
let a = RcCell::new(DummyStruct::new("dummy"));
let b = a.clone();
let c = b.clone();
let d = c.downgrade();
let e = d.clone();
assert!(RcCell::ptr_eq(&a, &c));
assert_eq!(RcCell::weak_count(&a), 2);
assert_eq!(RcCell::strong_count(&a), 3);
assert!(RcCell::try_unwrap(a).is_err());
assert!(d.upgrade().is_some());
assert!(RcCell::try_unwrap(b).is_err());
assert!(e.upgrade().is_some());
let res = RcCell::try_unwrap(c);
assert!(res.is_ok());
assert_eq!(res.ok().unwrap().name, "dummy");
assert!(d.upgrade().is_none());
assert!(e.upgrade().is_none());
}
#[test]
#[should_panic(expected = "called `Option::unwrap()` on a `None` value")]
fn test_unwrap_panic() {
let a = RcCell::new(DummyStruct::new("dummy"));
let _b = a.clone();
let _res = RcCell::unwrap(a);
}
#[test]
fn test_unwrap_ok() {
let a = RcCell::new(DummyStruct::new("dummy"));
let _b = a.downgrade();
assert_eq!(RcCell::unwrap(a).name, "dummy")
}
#[test]
fn test_try_borrows() {
let a = RcCell::new(DummyStruct::new("dummy"));
let b = a.downgrade();
assert_eq!(RcCell::weak_count(&a), 1);
assert_eq!(RcCell::strong_count(&a), 1);
assert!(a.try_borrow().is_ok());
assert!(b.upgrade().is_some());
assert!(b.upgrade().unwrap().try_borrow().is_ok());
let c = b.upgrade().unwrap();
assert!(a.try_borrow().is_ok());
assert!(b.upgrade().is_some());
assert!(b.upgrade().unwrap().try_borrow().is_ok());
assert!(c.try_borrow().is_ok());
let d = a.try_borrow_mut();
assert!(d.is_ok());
assert!(c.try_borrow().is_err());
assert!(c.try_borrow_mut().is_err());
drop(d);
let d = a.try_borrow();
assert!(d.is_ok());
assert!(c.try_borrow().is_ok());
assert!(c.try_borrow_mut().is_err());
}
#[test]
#[should_panic(expected = "already borrowed: BorrowMutError")]
fn test_borrow_mut_panic() {
let a = RcCell::new(DummyStruct::new("dummy"));
let _b = a.try_borrow();
a.borrow_mut();
}
#[test]
#[should_panic(expected = "already borrowed: BorrowMutError")]
fn test_mut_borrow_panic() {
let a = RcCell::new(DummyStruct::new("dummy"));
let _b = a.try_borrow_mut();
a.borrow_mut();
}
#[test]
#[should_panic(expected = "already mutably borrowed: BorrowError")]
fn test_mut_borrow_mut_panic() {
let a = RcCell::new(DummyStruct::new("dummy"));
let _b = a.try_borrow_mut();
a.borrow();
}
#[test]
fn test_borrow() {
let a = RcCell::new(DummyStruct::new("dummy"));
let b = a.clone();
let c = RcCell::new(DummyStruct::new("dummy"));
assert_eq!(a, b);
assert_ne!(a, c);
assert_eq!(*a.borrow(), *c.borrow());
assert!(RcCell::ptr_eq(&a, &b));
assert!(!RcCell::ptr_eq(&a, &c));
a.borrow_mut().name = String::from("DUMMY");
assert_eq!(a, b);
assert_ne!(a, c);
assert_ne!(*a.borrow(), *c.borrow());
}
#[test]
fn test_hashmap() {
let a = RcCell::new(DummyStruct::new("a"));
let b = RcCell::new(DummyStruct::new("a"));
let c = RcCell::new(DummyStruct::new("a"));
assert!(!RcCell::ptr_eq(&a, &b));
let mut map = HashMap::new();
assert!(map.is_empty());
assert!(map.insert(a.clone(), 1).is_none());
assert!(map.insert(b.clone(), 2).is_none());
assert!(map.insert(a.clone(), 3).is_some());
assert!(map.get(&a).is_some());
assert_eq!(map.get(&a).unwrap(), &3);
assert!(map.get(&b).is_some());
assert_eq!(map.get(&b).unwrap(), &2);
assert!(map.get(&c).is_none());
}
}