use core::fmt;
use core::fmt::{Debug, Display};
use core::ops::{Deref, DerefMut};
use core::cell::Cell;
use core::cell::UnsafeCell;
type BorrowFlag = usize;
const UNUSED: BorrowFlag = 0;
#[inline(always)]
fn is_writing(x: BorrowFlag) -> bool {
x > UNUSED
}
pub struct BorrowError {
_private: (),
}
impl Debug for BorrowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowError").finish()
}
}
impl Display for BorrowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt("already mutably borrowed", f)
}
}
struct BorrowShard<'b> {
borrow: &'b Cell<BorrowFlag>,
}
impl<'b> BorrowShard<'b> {
#[inline]
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<Self> {
match borrow.get() {
UNUSED => {
borrow.set(UNUSED + 1);
Some(BorrowShard { borrow })
}
_ => None,
}
}
#[inline]
fn clone(&self) -> Self {
let borrow = self.borrow.get();
debug_assert!(is_writing(borrow));
assert!(borrow != usize::max_value());
self.borrow.set(borrow + 1);
BorrowShard {
borrow: self.borrow,
}
}
}
impl Drop for BorrowShard<'_> {
#[inline]
fn drop(&mut self) {
let borrow = self.borrow.get();
debug_assert!(is_writing(borrow));
self.borrow.set(borrow + 1);
}
}
pub struct RefMut<'b, T: ?Sized + 'b> {
value: &'b mut T,
borrow: BorrowShard<'b>,
}
impl<'b, T: ?Sized> RefMut<'b, T> {
#[inline]
pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
where
F: FnOnce(&mut T) -> &mut U,
{
let RefMut { value, borrow } = orig;
RefMut {
value: f(value),
borrow,
}
}
#[inline]
pub fn split_tuple<U: ?Sized, V: ?Sized, F>(
orig: RefMut<'b, T>,
f: F,
) -> (RefMut<'b, U>, RefMut<'b, V>)
where
F: FnOnce(&mut T) -> (&mut U, &mut V),
{
let (a, b) = f(orig.value);
let borrow = orig.borrow.clone();
(
RefMut { value: a, borrow },
RefMut {
value: b,
borrow: orig.borrow,
},
)
}
#[inline]
pub fn split_triple<U: ?Sized, V: ?Sized, W: ?Sized, F>(
orig: RefMut<'b, T>,
f: F,
) -> (RefMut<'b, U>, RefMut<'b, V>, RefMut<'b, W>)
where
F: FnOnce(&mut T) -> (&mut U, &mut V, &mut W),
{
let (a, b, c) = f(orig.value);
let borrow_a = orig.borrow.clone();
let borrow_b = orig.borrow.clone();
(
RefMut {
value: a,
borrow: borrow_a,
},
RefMut {
value: b,
borrow: borrow_b,
},
RefMut {
value: c,
borrow: orig.borrow,
},
)
}
}
impl<T: ?Sized> Deref for RefMut<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.value
}
}
impl<T: ?Sized> DerefMut for RefMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
self.value
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.value.fmt(f)
}
}
pub struct BoCell<'a, T> {
borrow: Cell<BorrowFlag>,
value: &'a UnsafeCell<T>,
}
impl<'a, T> BoCell<'a, T> {
#[inline]
pub fn new(contents: &'a mut T) -> Self {
let interior = unsafe { &*(contents as *mut T as *const UnsafeCell<T>) };
BoCell {
borrow: Cell::new(UNUSED),
value: interior,
}
}
pub fn borrow_mut(&self) -> RefMut<'_, T> {
self.try_borrow_mut().expect("Already borrowed")
}
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowError> {
match BorrowShard::new(&self.borrow) {
Some(b) => Ok(RefMut {
value: unsafe { &mut *self.value.get() },
borrow: b,
}),
None => Err(BorrowError { _private: () }),
}
}
}