use std::{
cell::{Cell, UnsafeCell},
ops::{Deref, DerefMut},
};
#[derive(Copy, Clone)]
pub enum RefState {
Unshared,
Exclusive,
Shared(usize),
}
pub struct RefCell<T> {
value: UnsafeCell<T>,
state: Cell<RefState>,
}
impl<T> RefCell<T> {
pub fn from(value: T) -> Self {
Self {
value: UnsafeCell::from(value),
state: Cell::from(RefState::Unshared),
}
}
pub fn borrow(&self) -> Option<Ref<'_, T>> {
match self.state.get() {
RefState::Shared(n) => {
self.state.set(RefState::Shared(n + 1));
Some(Ref { refcell: self })
}
RefState::Unshared => {
self.state.set(RefState::Shared(1));
Some(Ref { refcell: self })
}
RefState::Exclusive => None,
}
}
pub fn borrow_mut(&self) -> Option<RefMut<'_, T>> {
if let RefState::Unshared = self.state.get() {
self.state.set(RefState::Exclusive);
Some(RefMut { refcell: self })
} else {
None
}
}
}
pub struct Ref<'refcell, T> {
refcell: &'refcell RefCell<T>,
}
impl<T> Drop for Ref<'_, T> {
fn drop(&mut self) {
match self.refcell.state.get() {
RefState::Exclusive => unreachable!(),
RefState::Unshared => unreachable!(),
RefState::Shared(1) => {
self.refcell.state.set(RefState::Unshared);
}
RefState::Shared(n) => {
self.refcell.state.set(RefState::Shared(n - 1));
}
}
}
}
impl<T> Deref for Ref<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.refcell.value.get() }
}
}
pub struct RefMut<'refcell, T> {
refcell: &'refcell RefCell<T>,
}
impl<T> Drop for RefMut<'_, T> {
fn drop(&mut self) {
match self.refcell.state.get() {
RefState::Exclusive => {}
RefState::Shared(_) | RefState::Unshared => unreachable!(),
}
}
}
impl<T> Deref for RefMut<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.refcell.value.get() }
}
}
impl<T> DerefMut for RefMut<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.refcell.value.get() }
}
}