use core::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
};
pub struct RefCell<T: ?Sized> {
borrow: UnsafeCell<BorrowFlag>,
value: UnsafeCell<T>,
}
pub struct BorrowError;
pub struct BorrowMutError;
type BorrowFlag = isize;
const UNUSED: BorrowFlag = 0;
impl<T> RefCell<T> {
pub const fn new(value: T) -> RefCell<T> {
RefCell {
value: UnsafeCell::new(value),
borrow: UnsafeCell::new(UNUSED),
}
}
pub const fn into_inner(self) -> T {
self.value.into_inner()
}
}
impl<T: ?Sized> RefCell<T> {
#[track_caller]
pub const fn borrow(&self) -> Ref<'_, T> {
if let Ok(x) = self.try_borrow() {
x
} else {
panic!("already mutably borrowed")
}
}
pub const fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
if unsafe { *self.borrow.get() } >= 0 {
unsafe { *self.borrow.get() += 1 };
Ok(Ref {
value: unsafe { &*self.value.get() },
borrow: &self.borrow,
})
} else {
Err(BorrowError)
}
}
#[track_caller]
pub const fn borrow_mut(&self) -> RefMut<'_, T> {
if let Ok(x) = self.try_borrow_mut() {
x
} else {
panic!("already borrowed")
}
}
pub const fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
if unsafe { *self.borrow.get() } == 0 {
unsafe { *self.borrow.get() = -1 };
Ok(RefMut {
value: unsafe { &mut *self.value.get() },
borrow: &self.borrow,
})
} else {
Err(BorrowMutError)
}
}
}
pub struct Ref<'b, T: ?Sized> {
value: &'b T,
borrow: &'b UnsafeCell<BorrowFlag>,
}
pub struct RefMut<'b, T: ?Sized> {
value: &'b mut T,
borrow: &'b UnsafeCell<BorrowFlag>,
}
impl<T: ?Sized> const Deref for Ref<'_, T> {
type Target = T;
fn deref(&self) -> &T {
self.value
}
}
impl<T: ?Sized> const Deref for RefMut<'_, T> {
type Target = T;
fn deref(&self) -> &T {
self.value
}
}
impl<T: ?Sized> const DerefMut for RefMut<'_, T> {
fn deref_mut(&mut self) -> &mut T {
self.value
}
}
impl<T: ?Sized> const Drop for Ref<'_, T> {
fn drop(&mut self) {
unsafe { *self.borrow.get() -= 1 };
}
}
impl<T: ?Sized> const Drop for RefMut<'_, T> {
fn drop(&mut self) {
unsafe { *self.borrow.get() += 1 };
}
}