use std::cell::{Cell, UnsafeCell};
use std::ptr::null_mut;
use std::rc::Rc;
pub struct RcRcu<T> {
inner: Rc<Inner<T>>,
have_borrowed: Cell<bool>,
}
impl<T: Clone> Clone for RcRcu<T> {
fn clone(&self) -> Self {
RcRcu {
inner: self.inner.clone(),
have_borrowed: Cell::new(false),
}
}
}
pub struct Inner<T> {
borrow_count: Cell<usize>,
am_writing: Cell<bool>,
list: List<T>,
}
pub struct List<T> {
value: UnsafeCell<T>,
next: Cell<*mut List<T>>,
}
impl<T> std::ops::Deref for RcRcu<T> {
type Target = T;
fn deref(&self) -> &T {
let aleady_borrowed = self.have_borrowed.get();
if !aleady_borrowed {
self.inner
.borrow_count
.set(self.inner.borrow_count.get() + 1);
self.have_borrowed.set(true); }
if self.inner.list.next.get() == null_mut() {
unsafe { &*self.inner.list.value.get() }
} else {
unsafe { &*(*self.inner.list.next.get()).value.get() }
}
}
}
impl<T> std::borrow::Borrow<T> for RcRcu<T> {
fn borrow(&self) -> &T {
&*self
}
}
impl<T> Drop for List<T> {
fn drop(&mut self) {
if self.next.get() != null_mut() {
let _to_free = unsafe { Box::from_raw(self.next.get()) };
}
}
}
impl<'a, T: Clone> RcRcu<T> {
pub fn new(x: T) -> Self {
RcRcu {
have_borrowed: Cell::new(false),
inner: Rc::new(Inner {
borrow_count: Cell::new(0),
am_writing: Cell::new(false),
list: List {
value: UnsafeCell::new(x),
next: Cell::new(null_mut()),
},
}),
}
}
pub fn update(&'a self) -> Guard<'a, T> {
if self.inner.am_writing.get() {
panic!("Cannont update an RcRcu twice simultaneously.");
}
self.inner.am_writing.set(true);
Guard {
list: Some(List {
value: UnsafeCell::new((*(*self)).clone()),
next: self.inner.list.next.clone(),
}),
rc_guts: &self.inner,
}
}
pub fn clean(&mut self) {
let aleady_borrowed = self.have_borrowed.get();
if aleady_borrowed {
self.inner
.borrow_count
.set(self.inner.borrow_count.get() - 1);
self.have_borrowed.set(false); }
if self.inner.borrow_count.get() == 0 && self.inner.list.next.get() != null_mut() {
unsafe {
std::mem::swap(
&mut *self.inner.list.value.get(),
&mut *(*self.inner.list.next.get()).value.get(),
);
let _to_free = Box::from_raw(self.inner.list.next.replace(null_mut()));
}
}
}
}
pub struct Guard<'a, T: Clone> {
list: Option<List<T>>,
rc_guts: &'a Inner<T>,
}
impl<'a, T: Clone> std::ops::Deref for Guard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
if let Some(ref list) = self.list {
unsafe { &*list.value.get() }
} else {
unreachable!()
}
}
}
impl<'a, T: Clone> std::ops::DerefMut for Guard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
if let Some(ref list) = self.list {
unsafe { &mut *list.value.get() }
} else {
unreachable!()
}
}
}
impl<'a, T: Clone> Drop for Guard<'a, T> {
fn drop(&mut self) {
let list = std::mem::replace(&mut self.list, None);
self.rc_guts
.list
.next
.set(Box::into_raw(Box::new(list.unwrap())));
self.rc_guts.am_writing.set(false);
}
}
#[cfg(test)]
mod test {
use super::RcRcu;
#[derive(Debug, Clone)]
struct Foo(usize);
#[test]
fn debug() {
assert_eq!(&format!("{:?}", Foo(1)), "Foo(1)");
assert_eq!(&format!("{:?}", RcRcu::new(Foo(1))), "Foo(1)");
}
}