//! Atomic runtime borrow checking module. //! These types implement something akin to `RefCell`, but are atomically handled allowing them to //! cross thread boundaries. use std::cell::UnsafeCell; use std::hash::{Hash, Hasher}; use std::any::{Any, type_name}; use std::ops::Deref; use std::ops::DerefMut; use std::sync::atomic::AtomicIsize; use crate::resource::Resource; #[cfg(not(debug_assertions))] use std::marker::PhantomData; // #[inline(always)] // pub fn downcast_typename_mut(value: &mut dyn Any) -> &mut U { // unsafe { &mut *(value as *mut dyn Any as *mut U) } // } // #[inline(always)] // pub fn downcast_typename_ref(value: &dyn Any) -> &U { // unsafe { &*(value as *const dyn Any as *const U) } // // if type_name::() == type_name::() { // // unsafe { Some(&*(value as *const dyn Any as *const U)) } // // } else { // // None // // } // } pub trait DowncastTypename { fn downcast_typename_mut(&mut self) -> Option<&mut T>; fn downcast_typename_ref(&self) -> Option<&T>; fn is_typename(&self) -> bool; } impl DowncastTypename for dyn Resource { #[inline(always)] fn downcast_typename_mut(&mut self) -> Option<&mut T> { if self.is_typename::() { // SAFETY: just checked whether we are pointing to the correct type unsafe { Some(&mut *(self.as_any_mut() as *mut dyn Any as *mut T)) } } else { None } } #[inline(always)] fn downcast_typename_ref(&self) -> Option<&T> { if self.is_typename::() { // SAFETY: just checked whether we are pointing to the correct type unsafe { Some(&*(self.as_any() as *const dyn Any as *const T)) } } else { None } } #[inline(always)] fn is_typename(&self) -> bool { true // TODO: it would be nice to add type safety here, but the type names don't match // println!("{} {}", type_name_of_val(self), type_name::()); // type_name_of_val(self) == type_name::() } } pub fn type_name_of_val(_val: &T) -> &'static str { type_name::() } /// A `RefCell` implementation which is thread safe. This type performs all the standard runtime /// borrow checking which would be familiar from using `RefCell`. /// /// `UnsafeCell` is used in this type, but borrow checking is performed using atomic values, /// garunteeing safe access across threads. /// /// # Safety /// Runtime borrow checking is only conducted in builds with `debug_assertions` enabled. Release /// builds assume proper resource access and will cause undefined behavior with improper use. pub struct AtomicRefCell { value: UnsafeCell, borrow_state: AtomicIsize, } impl Default for AtomicRefCell { fn default() -> Self { Self::new(T::default()) } } impl std::fmt::Debug for AtomicRefCell { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "({:?}) {:?}", self.borrow_state, self.value) } } impl AtomicRefCell { pub fn new(value: T) -> Self { AtomicRefCell { value: UnsafeCell::from(value), borrow_state: AtomicIsize::from(0), } } /// Retrieve an immutable `Ref` wrapped reference of `&T`. /// /// # Panics /// /// This method panics if this value is already mutably borrowed. /// /// # Safety /// Runtime borrow checking is only conducted in builds with `debug_assertions` enabled. Release /// builds assume proper resource access and will cause undefined behavior with improper use. #[inline(always)] pub fn get(&self) -> Ref { self.try_get().unwrap() } /// Unwrap the value from the RefCell and kill it, returning the value. pub fn into_inner(self) -> T { self.value.into_inner() } /// Retrieve an immutable `Ref` wrapped reference of `&T`. This is the safe version of `get` /// providing an error result on failure. /// /// # Returns /// /// `Some(T)` if the value can be retrieved. /// `Err` if the value is already mutably borrowed. #[cfg(debug_assertions)] pub fn try_get(&self) -> Result, String> { loop { let read = self.borrow_state.load(std::sync::atomic::Ordering::SeqCst); if read < 0 { return Err(format!( "resource already borrowed as mutable: {}", std::any::type_name::() )); } if self.borrow_state.compare_and_swap( read, read + 1, std::sync::atomic::Ordering::SeqCst, ) == read { break; } } Ok(Ref::new(Shared::new(&self.borrow_state), unsafe { &*self.value.get() })) } /// Retrieve an immutable `Ref` wrapped reference of `&T`. This is the safe version of `get` /// providing an error result on failure. /// /// # Returns /// /// `Some(T)` if the value can be retrieved. /// `Err` if the value is already mutably borrowed. /// /// # Safety /// /// This release version of this function does not perform runtime borrow checking and will /// cause undefined behavior if borrow rules are violated. This means they should be enforced /// on the use of this type. #[cfg(not(debug_assertions))] #[inline(always)] pub fn try_get(&self) -> Result, &'static str> { Ok(Ref::new(Shared::new(&self.borrow_state), unsafe { &*self.value.get() })) } /// Retrieve an mutable `RefMut` wrapped reference of `&mut T`. /// /// # Panics /// /// This method panics if this value is already mutably borrowed. /// /// # Safety /// Runtime borrow checking is only conducted in builds with `debug_assertions` enabled. Release /// builds assume proper resource access and will cause undefined behavior with improper use. #[inline(always)] pub fn get_mut(&self) -> RefMut { self.try_get_mut().unwrap() } /// Retrieve a mutable `RefMut` wrapped reference of `&mut T`. This is the safe version of /// `get_mut` providing an error result on failure. /// /// # Returns /// /// `Some(T)` if the value can be retrieved. /// `Err` if the value is already mutably borrowed. /// /// # Safety /// /// This release version of this function does not perform runtime borrow checking and will /// cause undefined behavior if borrow rules are violated. This means they should be enforced /// on the use of this type. #[cfg(debug_assertions)] pub fn try_get_mut(&self) -> Result, String> { let borrowed = self.borrow_state .compare_and_swap(0, -1, std::sync::atomic::Ordering::SeqCst); match borrowed { 0 => Ok(RefMut::new(Exclusive::new(&self.borrow_state), unsafe { &mut *self.value.get() })), x if x < 0 => Err(format!( "resource already borrowed as mutable: {}", std::any::type_name::() )), _ => Err(format!( "resource already borrowed as immutable: {}", std::any::type_name::() )), } } /// Retrieve a mutable `RefMut` wrapped reference of `&mut T`. This is the safe version of /// `get_mut` providing an error result on failure. /// /// # Returns /// /// `Some(T)` if the value can be retrieved. /// `Err` if the value is already mutably borrowed. /// /// # Safety /// /// This release version of this function does not perform runtime borrow checking and will /// cause undefined behavior if borrow rules are violated. This means they should be enforced /// on the use of this type. #[cfg(not(debug_assertions))] #[inline(always)] pub fn try_get_mut(&self) -> Result, &'static str> { Ok(RefMut::new(Exclusive::new(&self.borrow_state), unsafe { &mut *self.value.get() })) } } unsafe impl Send for AtomicRefCell {} unsafe impl Sync for AtomicRefCell {} /// Type used for allowing unsafe cloning of internal types pub trait UnsafeClone { /// Clone this type unsafely /// /// # Safety /// Types implementing this trait perform clones under an unsafe context. unsafe fn clone(&self) -> Self; } impl UnsafeClone for (A, B) { unsafe fn clone(&self) -> Self { (self.0.clone(), self.1.clone()) } } #[derive(Debug)] pub struct Shared<'a> { #[cfg(debug_assertions)] state: &'a AtomicIsize, #[cfg(not(debug_assertions))] state: PhantomData<&'a ()>, } impl<'a> Shared<'a> { #[cfg(debug_assertions)] fn new(state: &'a AtomicIsize) -> Self { Self { state } } #[cfg(not(debug_assertions))] #[inline(always)] fn new(_: &'a AtomicIsize) -> Self { Self { state: PhantomData } } } #[cfg(debug_assertions)] impl<'a> Drop for Shared<'a> { fn drop(&mut self) { self.state.fetch_sub(1, std::sync::atomic::Ordering::SeqCst); } } impl<'a> Clone for Shared<'a> { #[inline(always)] fn clone(&self) -> Self { #[cfg(debug_assertions)] self.state.fetch_add(1, std::sync::atomic::Ordering::SeqCst); Shared { state: self.state } } } impl<'a> UnsafeClone for Shared<'a> { unsafe fn clone(&self) -> Self { Clone::clone(&self) } } #[derive(Debug)] pub struct Exclusive<'a> { #[cfg(debug_assertions)] state: &'a AtomicIsize, #[cfg(not(debug_assertions))] state: PhantomData<&'a ()>, } impl<'a> Exclusive<'a> { #[cfg(debug_assertions)] fn new(state: &'a AtomicIsize) -> Self { Self { state } } #[cfg(not(debug_assertions))] #[inline(always)] fn new(_: &'a AtomicIsize) -> Self { Self { state: PhantomData } } } #[cfg(debug_assertions)] impl<'a> Drop for Exclusive<'a> { fn drop(&mut self) { self.state.fetch_add(1, std::sync::atomic::Ordering::SeqCst); } } impl<'a> UnsafeClone for Exclusive<'a> { #[inline(always)] unsafe fn clone(&self) -> Self { #[cfg(debug_assertions)] self.state.fetch_sub(1, std::sync::atomic::Ordering::SeqCst); Exclusive { state: self.state } } } #[derive(Debug)] pub struct Ref<'a, T: 'a> { #[allow(dead_code)] // held for drop impl borrow: Shared<'a>, value: &'a T, } impl<'a, T: 'a> Clone for Ref<'a, T> { #[inline(always)] fn clone(&self) -> Self { Ref::new(Clone::clone(&self.borrow), self.value) } } impl<'a, T: 'a> Ref<'a, T> { #[inline(always)] pub fn new(borrow: Shared<'a>, value: &'a T) -> Self { Self { borrow, value } } #[inline(always)] pub fn map_into K>(self, mut f: F) -> RefMap<'a, K> { RefMap::new(self.borrow, f(&self.value)) } #[inline(always)] pub fn map &K>(&self, mut f: F) -> Ref<'a, K> { Ref::new(Clone::clone(&self.borrow), f(&self.value)) } /// Deconstructs this mapped borrow to its underlying borrow state and value. /// /// # Safety /// /// Ensure that you still follow all safety guidelines of this mapped ref. #[inline(always)] pub unsafe fn deconstruct(self) -> (Shared<'a>, &'a T) { (self.borrow, self.value) } } impl<'a, T: 'a> Deref for Ref<'a, T> { type Target = T; #[inline(always)] fn deref(&self) -> &Self::Target { self.value } } impl<'a, T: 'a> AsRef for Ref<'a, T> { #[inline(always)] fn as_ref(&self) -> &T { self.value } } impl<'a, T: 'a> std::borrow::Borrow for Ref<'a, T> { #[inline(always)] fn borrow(&self) -> &T { self.value } } impl<'a, T> PartialEq for Ref<'a, T> where T: 'a + PartialEq, { fn eq(&self, other: &Self) -> bool { self.value == other.value } } impl<'a, T> Eq for Ref<'a, T> where T: 'a + Eq {} impl<'a, T> PartialOrd for Ref<'a, T> where T: 'a + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { self.value.partial_cmp(&other.value) } } impl<'a, T> Ord for Ref<'a, T> where T: 'a + Ord, { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) } } impl<'a, T> Hash for Ref<'a, T> where T: 'a + Hash, { fn hash(&self, state: &mut H) { self.value.hash(state); } } #[derive(Debug)] pub struct RefMut<'a, T: 'a> { #[allow(dead_code)] // held for drop impl borrow: Exclusive<'a>, value: &'a mut T, } impl<'a, T: 'a> RefMut<'a, T> { #[inline(always)] pub fn new(borrow: Exclusive<'a>, value: &'a mut T) -> Self { Self { borrow, value } } #[inline(always)] pub fn map_into K>(mut self, mut f: F) -> RefMapMut<'a, K> { RefMapMut::new(self.borrow, f(&mut self.value)) } /// Deconstructs this mapped borrow to its underlying borrow state and value. /// /// # Safety /// /// Ensure that you still follow all safety guidelines of this mapped ref. #[inline(always)] pub unsafe fn deconstruct(self) -> (Exclusive<'a>, &'a mut T) { (self.borrow, self.value) } #[inline(always)] pub fn split (&'a mut First, &'a mut Rest)>( self, f: F, ) -> (RefMut<'a, First>, RefMut<'a, Rest>) { let (first, rest) = f(self.value); ( RefMut::new(unsafe { self.borrow.clone() }, first), RefMut::new(self.borrow, rest), ) } } impl<'a, T: 'a> Deref for RefMut<'a, T> { type Target = T; #[inline(always)] fn deref(&self) -> &Self::Target { self.value } } impl<'a, T: 'a> DerefMut for RefMut<'a, T> { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { self.value } } impl<'a, T: 'a> AsRef for RefMut<'a, T> { #[inline(always)] fn as_ref(&self) -> &T { self.value } } impl<'a, T: 'a> std::borrow::Borrow for RefMut<'a, T> { #[inline(always)] fn borrow(&self) -> &T { self.value } } impl<'a, T> PartialEq for RefMut<'a, T> where T: 'a + PartialEq, { fn eq(&self, other: &Self) -> bool { self.value == other.value } } impl<'a, T> Eq for RefMut<'a, T> where T: 'a + Eq {} impl<'a, T> PartialOrd for RefMut<'a, T> where T: 'a + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { self.value.partial_cmp(&other.value) } } impl<'a, T> Ord for RefMut<'a, T> where T: 'a + Ord, { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.value.cmp(&other.value) } } impl<'a, T> Hash for RefMut<'a, T> where T: 'a + Hash, { fn hash(&self, state: &mut H) { self.value.hash(state); } } #[derive(Debug)] pub struct RefMap<'a, T: 'a> { #[allow(dead_code)] // held for drop impl borrow: Shared<'a>, value: T, } impl<'a, T: 'a> RefMap<'a, T> { #[inline(always)] pub fn new(borrow: Shared<'a>, value: T) -> Self { Self { borrow, value } } #[inline(always)] pub fn map_into K>(mut self, mut f: F) -> RefMap<'a, K> { RefMap::new(self.borrow, f(&mut self.value)) } /// Deconstructs this mapped borrow to its underlying borrow state and value. /// /// # Safety /// /// Ensure that you still follow all safety guidelines of this mapped ref. #[inline(always)] pub unsafe fn deconstruct(self) -> (Shared<'a>, T) { (self.borrow, self.value) } } impl<'a, T: 'a> Deref for RefMap<'a, T> { type Target = T; #[inline(always)] fn deref(&self) -> &Self::Target { &self.value } } impl<'a, T: 'a> AsRef for RefMap<'a, T> { #[inline(always)] fn as_ref(&self) -> &T { &self.value } } impl<'a, T: 'a> std::borrow::Borrow for RefMap<'a, T> { #[inline(always)] fn borrow(&self) -> &T { &self.value } } #[derive(Debug)] pub struct RefMapMut<'a, T: 'a> { #[allow(dead_code)] // held for drop impl borrow: Exclusive<'a>, value: T, } impl<'a, T: 'a> RefMapMut<'a, T> { #[inline(always)] pub fn new(borrow: Exclusive<'a>, value: T) -> Self { Self { borrow, value } } #[inline(always)] pub fn map_into K>(mut self, mut f: F) -> RefMapMut<'a, K> { RefMapMut { value: f(&mut self.value), borrow: self.borrow, } } /// Deconstructs this mapped borrow to its underlying borrow state and value. /// /// # Safety /// /// Ensure that you still follow all safety guidelines of this mutable mapped ref. #[inline(always)] pub unsafe fn deconstruct(self) -> (Exclusive<'a>, T) { (self.borrow, self.value) } } impl<'a, T: 'a> Deref for RefMapMut<'a, T> { type Target = T; #[inline(always)] fn deref(&self) -> &Self::Target { &self.value } } impl<'a, T: 'a> DerefMut for RefMapMut<'a, T> { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } impl<'a, T: 'a> AsRef for RefMapMut<'a, T> { #[inline(always)] fn as_ref(&self) -> &T { &self.value } } impl<'a, T: 'a> std::borrow::Borrow for RefMapMut<'a, T> { #[inline(always)] fn borrow(&self) -> &T { &self.value } } #[derive(Debug)] pub struct RefIter<'a, T: 'a, I: Iterator> { #[allow(dead_code)] // held for drop impl borrow: Shared<'a>, iter: I, } impl<'a, T: 'a, I: Iterator> RefIter<'a, T, I> { #[inline(always)] pub fn new(borrow: Shared<'a>, iter: I) -> Self { Self { borrow, iter } } } impl<'a, T: 'a, I: Iterator> Iterator for RefIter<'a, T, I> { type Item = Ref<'a, T>; #[inline(always)] fn next(&mut self) -> Option { if let Some(item) = self.iter.next() { Some(Ref::new(Clone::clone(&self.borrow), item)) } else { None } } fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl<'a, T: 'a, I: Iterator + ExactSizeIterator> ExactSizeIterator for RefIter<'a, T, I> { } #[derive(Debug)] enum TryIter { Found { borrow: State, iter: T }, Missing(usize), } #[derive(Debug)] pub struct TryRefIter<'a, T: 'a, I: Iterator> { inner: TryIter, I>, } impl<'a, T: 'a, I: Iterator> TryRefIter<'a, T, I> { #[inline(always)] pub(crate) fn found(borrow: Shared<'a>, iter: I) -> Self { Self { inner: TryIter::Found { borrow, iter }, } } #[inline(always)] pub(crate) fn missing(count: usize) -> Self { Self { inner: TryIter::Missing(count), } } } impl<'a, T: 'a, I: Iterator> Iterator for TryRefIter<'a, T, I> { type Item = Option>; #[inline(always)] fn next(&mut self) -> Option { Some(match self.inner { TryIter::Found { ref borrow, ref mut iter, .. } => Some(Ref::new(Clone::clone(borrow), iter.next()?)), TryIter::Missing(ref mut n) => { *n = n.checked_sub(1)?; None } }) } fn size_hint(&self) -> (usize, Option) { match self.inner { TryIter::Found { ref iter, .. } => iter.size_hint(), TryIter::Missing(n) => (n, Some(n)), } } } impl<'a, T: 'a, I: Iterator + ExactSizeIterator> ExactSizeIterator for TryRefIter<'a, T, I> { } #[derive(Debug)] pub struct RefIterMut<'a, T: 'a, I: Iterator> { #[allow(dead_code)] // held for drop impl borrow: Exclusive<'a>, iter: I, } impl<'a, T: 'a, I: Iterator> RefIterMut<'a, T, I> { #[inline(always)] pub fn new(borrow: Exclusive<'a>, iter: I) -> Self { Self { borrow, iter } } } impl<'a, T: 'a, I: Iterator> Iterator for RefIterMut<'a, T, I> { type Item = RefMut<'a, T>; #[inline(always)] fn next(&mut self) -> Option { if let Some(item) = self.iter.next() { Some(RefMut::new(unsafe { self.borrow.clone() }, item)) } else { None } } fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl<'a, T: 'a, I: Iterator + ExactSizeIterator> ExactSizeIterator for RefIterMut<'a, T, I> { } #[derive(Debug)] pub struct TryRefIterMut<'a, T: 'a, I: Iterator> { inner: TryIter, I>, } impl<'a, T: 'a, I: Iterator> TryRefIterMut<'a, T, I> { #[inline(always)] pub(crate) fn found(borrow: Exclusive<'a>, iter: I) -> Self { Self { inner: TryIter::Found { borrow, iter }, } } #[inline(always)] pub(crate) fn missing(count: usize) -> Self { Self { inner: TryIter::Missing(count), } } } impl<'a, T: 'a, I: Iterator> Iterator for TryRefIterMut<'a, T, I> { type Item = Option>; #[inline(always)] fn next(&mut self) -> Option { Some(match self.inner { TryIter::Found { ref borrow, ref mut iter, .. } => Some(RefMut::new(unsafe { borrow.clone() }, iter.next()?)), TryIter::Missing(ref mut n) => { *n = n.checked_sub(1)?; None } }) } fn size_hint(&self) -> (usize, Option) { match self.inner { TryIter::Found { ref iter, .. } => iter.size_hint(), TryIter::Missing(n) => (n, Some(n)), } } } impl<'a, T: 'a, I: Iterator + ExactSizeIterator> ExactSizeIterator for TryRefIterMut<'a, T, I> { }