use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use crate::cell::CellState;
#[derive(Debug)]
pub struct RefGuard<'a, T> {
state: &'a UnsafeCell<CellState<T>>,
value: NonNull<T>,
}
impl<'a, T> RefGuard<'a, T> {
pub(crate) unsafe fn new(state: &'a UnsafeCell<CellState<T>>, value: NonNull<T>) -> Self {
Self { state, value }
}
}
impl<T> Deref for RefGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.value.as_ref() }
}
}
impl<T> Drop for RefGuard<'_, T> {
fn drop(&mut self) {
unsafe { CellState::borrow_state(self.state) }
.decrement_shared()
.unwrap();
}
}
#[derive(Debug)]
pub struct MutGuard<'a, T> {
state: &'a UnsafeCell<CellState<T>>,
count: usize,
value: NonNull<T>,
}
impl<'a, T> MutGuard<'a, T> {
pub(crate) unsafe fn new(
state: &'a UnsafeCell<CellState<T>>,
count: usize,
value: NonNull<T>,
) -> Self {
Self {
state,
count,
value,
}
}
}
impl<T> Deref for MutGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
let count = unsafe { CellState::borrow_state(self.state) }.mut_count();
assert_eq!(
self.count,
count,
"\
attempted to access a non-current mutable borrow of type: `{}`. \n\
current count: {}\n\
value pointer: {:p}\n\
attempted access count: {}\n\
**this is a bug, please report it**\
",
std::any::type_name::<T>(),
self.count,
self.value,
count
);
unsafe { self.value.as_ref() }
}
}
impl<T> DerefMut for MutGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
let count = unsafe { CellState::borrow_state(self.state) }.mut_count();
assert_eq!(
self.count,
count,
"\
attempted to access a non-current mutable borrow of type: `{}`. \n\
current count: {}\n\
value pointer: {:p}\n\
attempted access count: {}\n\
**this is a bug, please report it**\
",
std::any::type_name::<T>(),
self.count,
self.value,
count
);
unsafe { self.value.as_mut() }
}
}
impl<T> Drop for MutGuard<'_, T> {
fn drop(&mut self) {
unsafe { CellState::borrow_state(self.state) }
.decrement_mut()
.unwrap();
}
}
#[derive(Debug)]
pub struct InaccessibleGuard<'a, T> {
state: &'a UnsafeCell<CellState<T>>,
stack_depth: usize,
prev_ptr: NonNull<T>,
}
impl<'a, T> InaccessibleGuard<'a, T> {
pub(crate) fn new<'b>(
state: &'a UnsafeCell<CellState<T>>,
new_ref: &'b mut T,
) -> Result<Self, Box<dyn std::error::Error>>
where
'a: 'b,
{
let cell_state = unsafe { state.get().as_mut() }.unwrap();
let current_ptr = cell_state.get_ptr();
let new_ptr = NonNull::from(new_ref);
if current_ptr != new_ptr {
return Err("wrong reference passed in".into());
}
cell_state.borrow_state.set_inaccessible()?;
let prev_ptr = cell_state.get_ptr();
let stack_depth = cell_state.push_ptr(new_ptr);
Ok(Self {
state,
stack_depth,
prev_ptr,
})
}
fn perform_drop(state: &'a UnsafeCell<CellState<T>>, prev_ptr: NonNull<T>, stack_depth: usize) {
let state = unsafe { state.get().as_mut() }.unwrap();
if state.stack_depth != stack_depth {
state
.borrow_state
.poison("cannot drop inaccessible guards in the wrong order")
.unwrap();
}
state.borrow_state.unset_inaccessible().unwrap();
state.pop_ptr(prev_ptr);
}
#[doc(hidden)]
pub fn can_drop(&self) -> bool {
let state = unsafe { self.state.get().as_mut() }.unwrap();
state.borrow_state.may_unset_inaccessible() || state.stack_depth == self.stack_depth
}
#[doc(hidden)]
pub fn try_drop(self) -> Result<(), Self> {
if !self.can_drop() {
return Err(self);
}
let manual = std::mem::ManuallyDrop::new(self);
Self::perform_drop(manual.state, manual.prev_ptr, manual.stack_depth);
Ok(())
}
}
impl<T> Drop for InaccessibleGuard<'_, T> {
fn drop(&mut self) {
Self::perform_drop(self.state, self.prev_ptr, self.stack_depth);
}
}