#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate core;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "sync-unsafe-cell")]
use core::cell::SyncUnsafeCell;
#[cfg(not(feature = "sync-unsafe-cell"))]
use core::cell::UnsafeCell;
use core::{
borrow::Borrow,
cell::Cell,
iter,
marker::PhantomData,
ptr::NonNull,
};
use crate::{
element::{
BorrowRef,
BorrowRefMut,
BorrowState,
},
registry_container::{
Key,
KeyedRegistryContainer,
RegistryContainer,
},
Arena,
BorrowError,
ElementRef,
ElementRefMut,
};
pub(crate) struct BaseRegistryEntry<T> {
data: NonNull<T>,
borrow_state: NonNull<Cell<BorrowState>>,
}
unsafe impl<T> Send for BaseRegistryEntry<T> {}
impl<T> BaseRegistryEntry<T> {
pub fn new(data: &mut T, borrow_state: &Cell<BorrowState>) -> Self {
Self {
data: data.into(),
borrow_state: borrow_state.into(),
}
}
pub fn borrow(&self) -> Result<ElementRef<T>, BorrowError> {
BorrowRef::new(unsafe { self.borrow_state.as_ref() })
.ok_or(BorrowError::AlreadyBorrowed)
.map(|borrow_ref| ElementRef::new(self.data, borrow_ref))
}
pub fn borrow_mut(&self) -> Result<ElementRefMut<T>, BorrowError> {
BorrowRefMut::new(unsafe { self.borrow_state.as_ref() })
.ok_or(BorrowError::AlreadyBorrowed)
.map(|borrow_ref| ElementRefMut::new(self.data.into(), borrow_ref))
}
}
pub(crate) struct BaseRegistry<K, V, R> {
arena: Arena<V>,
borrow_states: Arena<Cell<BorrowState>>,
#[cfg(feature = "sync-unsafe-cell")]
entries: SyncUnsafeCell<R>,
#[cfg(not(feature = "sync-unsafe-cell"))]
entries: UnsafeCell<R>,
phantom_key: PhantomData<K>,
}
impl<K, V, R> BaseRegistry<K, V, R>
where
R: RegistryContainer<K, BaseRegistryEntry<V>>,
{
pub fn new() -> Self {
Self {
arena: Arena::new(),
borrow_states: Arena::new(),
entries: R::new().into(),
phantom_key: PhantomData,
}
}
pub fn with_capacity(size: usize) -> Self {
Self {
arena: Arena::with_capacity(size),
borrow_states: Arena::with_capacity(size),
entries: R::with_capacity(size).into(),
phantom_key: PhantomData,
}
}
pub fn entries(&self) -> &R {
unsafe { &*self.entries.get() }
}
pub fn entries_mut(&self) -> &mut R {
unsafe { &mut *self.entries.get() }
}
pub fn is_empty(&self) -> bool {
self.entries().is_empty()
}
pub fn len(&self) -> usize {
self.entries().len()
}
pub fn reserve(&self, additional: usize) {
self.arena.reserve(additional);
self.borrow_states.reserve(additional);
self.entries_mut().reserve(additional);
}
pub fn insert(&self, value: V) -> (&mut V, &mut Cell<BorrowState>) {
(
self.arena.alloc(value),
self.borrow_states.alloc(BorrowState::default().into()),
)
}
pub fn insert_extend<I>(
&self,
iterable: I,
) -> impl Iterator<Item = (&mut V, &mut Cell<BorrowState>)>
where
I: IntoIterator<Item = V>,
{
let values = self.arena.alloc_extend(iterable);
let borrow_states = self
.borrow_states
.alloc_extend(iter::repeat(BorrowState::default().into()).take(values.len()));
values.into_iter().zip(borrow_states.into_iter())
}
pub fn into_vec(self) -> Vec<V> {
self.arena.into_vec()
}
pub fn borrow(&self, key: &K) -> ElementRef<V> {
self.try_borrow(key)
.unwrap_or_else(|err| panic!("Borrow error: {err}"))
}
pub fn try_borrow(&self, key: &K) -> Result<ElementRef<V>, BorrowError> {
self.entries()
.get(&key)
.ok_or(BorrowError::OutOfBounds)
.and_then(|entry| entry.borrow())
}
pub fn borrow_mut(&self, key: &K) -> ElementRefMut<V> {
self.try_borrow_mut(key)
.unwrap_or_else(|err| panic!("Borrow error: {err}"))
}
pub fn try_borrow_mut(&self, key: &K) -> Result<ElementRefMut<V>, BorrowError> {
self.entries()
.get(&key)
.ok_or(BorrowError::OutOfBounds)
.and_then(|entry| entry.borrow_mut())
}
pub fn safe_to_drop(&mut self) -> bool {
self.borrow_states
.iter_mut()
.all(|borrow_state| borrow_state.get() == BorrowState::NotBorrowed)
}
}
impl<K, V, R> Default for BaseRegistry<K, V, R>
where
R: RegistryContainer<K, BaseRegistryEntry<V>>,
{
fn default() -> Self {
Self::new()
}
}
pub trait KeyedBaseRegistry<K, V> {
fn borrow<L>(&self, key: &L) -> ElementRef<V>
where
K: Borrow<L>,
L: Key + ?Sized;
fn try_borrow<L>(&self, key: &L) -> Result<ElementRef<V>, BorrowError>
where
K: Borrow<L>,
L: Key + ?Sized;
fn borrow_mut<L>(&self, key: &L) -> ElementRefMut<V>
where
K: Borrow<L>,
L: Key + ?Sized;
fn try_borrow_mut<L>(&self, key: &L) -> Result<ElementRefMut<V>, BorrowError>
where
K: Borrow<L>,
L: Key + ?Sized;
}
impl<K, V, R> KeyedBaseRegistry<K, V> for BaseRegistry<K, V, R>
where
K: Key,
R: KeyedRegistryContainer<K, BaseRegistryEntry<V>>,
{
fn borrow<L>(&self, key: &L) -> ElementRef<V>
where
K: Borrow<L>,
L: Key + ?Sized,
{
KeyedBaseRegistry::try_borrow(self, key).unwrap_or_else(|err| panic!("Borrow error: {err}"))
}
fn try_borrow<L>(&self, key: &L) -> Result<ElementRef<V>, BorrowError>
where
K: Borrow<L>,
L: Key + ?Sized,
{
KeyedRegistryContainer::get(self.entries(), key)
.ok_or(BorrowError::OutOfBounds)
.and_then(|entry| entry.borrow())
}
fn borrow_mut<L>(&self, key: &L) -> ElementRefMut<V>
where
K: Borrow<L>,
L: Key + ?Sized,
{
KeyedBaseRegistry::try_borrow_mut(self, key)
.unwrap_or_else(|err| panic!("Borrow error: {err}"))
}
fn try_borrow_mut<L>(&self, key: &L) -> Result<ElementRefMut<V>, BorrowError>
where
K: Borrow<L>,
L: Key + ?Sized,
{
KeyedRegistryContainer::get(self.entries(), key)
.ok_or(BorrowError::OutOfBounds)
.and_then(|entry| entry.borrow_mut())
}
}
#[cfg(test)]
mod base_registry_test {
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{
vec,
vec::Vec,
};
use core::mem;
#[cfg(feature = "std")]
use std::sync::{
Arc,
Mutex,
};
use crate::{
base_registry::{
BaseRegistry,
BaseRegistryEntry,
},
BorrowError,
ElementRef,
ElementRefMut,
};
type VecBasedRegistry<T> = BaseRegistry<usize, T, Vec<BaseRegistryEntry<T>>>;
fn insert_into_registry<T>(registry: &VecBasedRegistry<T>, value: T) {
let (data, borrow_state) = registry.insert(value);
registry.entries_mut().push(BaseRegistryEntry {
data: data.into(),
borrow_state: borrow_state.into(),
});
}
fn insert_many_into_registry<T, I>(registry: &VecBasedRegistry<T>, iterable: I)
where
I: IntoIterator<Item = T>,
{
for value in iterable {
insert_into_registry(registry, value);
}
}
#[test]
fn tracks_length() {
let registry = VecBasedRegistry::with_capacity(16);
insert_many_into_registry(®istry, [1, 2, 3, 4]);
assert_eq!(registry.len(), 4);
insert_into_registry(®istry, 5);
assert_eq!(registry.len(), 5);
insert_into_registry(®istry, 6);
assert_eq!(registry.len(), 6);
insert_many_into_registry(®istry, 0..100);
assert_eq!(registry.len(), 106);
}
#[test]
fn borrow_out_of_bounds() {
let registry = VecBasedRegistry::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
assert_eq!(
registry.try_borrow(&5).err(),
Some(BorrowError::OutOfBounds)
);
assert_eq!(
registry.try_borrow_mut(&6).err(),
Some(BorrowError::OutOfBounds)
);
}
#[test]
fn counts_immutable_borrws() {
let registry = VecBasedRegistry::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
{
let borrow_1 = registry.try_borrow(&1);
let borrow_2 = registry.try_borrow(&1);
let borrow_3 = registry.try_borrow(&1);
assert!(borrow_1.as_ref().is_ok_and(|val| val.eq(&2)));
assert!(borrow_2.as_ref().is_ok_and(|val| val.eq(&2)));
drop(borrow_1);
drop(borrow_2);
assert_eq!(
registry.try_borrow_mut(&1).err(),
Some(BorrowError::AlreadyBorrowed)
);
assert!(borrow_3.is_ok_and(|val| val.eq(&2)));
}
assert!(registry.try_borrow_mut(&1).is_ok_and(|val| val.eq(&2)));
}
#[test]
fn only_one_mutable_borrow() {
let registry = VecBasedRegistry::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
let mut borrow_1 = registry.try_borrow_mut(&2);
assert!(borrow_1.as_ref().is_ok_and(|val| val.eq(&3)));
assert_eq!(
registry.try_borrow_mut(&2).err(),
Some(BorrowError::AlreadyBorrowed)
);
*borrow_1.as_deref_mut().unwrap() *= 2;
drop(borrow_1);
let borrow_2 = registry.try_borrow_mut(&2);
assert!(borrow_2.as_ref().is_ok_and(|val| val.eq(&6)));
}
#[test]
fn borrows_do_not_interfere() {
let registry = VecBasedRegistry::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
let borrow_0_1 = registry.try_borrow(&0);
let borrow_1_1 = registry.try_borrow_mut(&1);
let borrow_2_1 = registry.try_borrow(&2);
let borrow_2_2 = registry.try_borrow(&2);
let borrow_3_1 = registry.try_borrow_mut(&3);
assert!(borrow_0_1.as_ref().is_ok_and(|val| val.eq(&1)));
assert!(borrow_1_1.as_ref().is_ok_and(|val| val.eq(&2)));
assert!(borrow_2_1.as_ref().is_ok_and(|val| val.eq(&3)));
assert!(borrow_2_2.as_ref().is_ok_and(|val| val.eq(&3)));
assert!(borrow_3_1.as_ref().is_ok_and(|val| val.eq(&4)));
}
#[test]
fn immutable_borrow_can_be_cloned() {
let registry = VecBasedRegistry::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
let borrow_1 = registry.borrow(&0);
let borrow_2 = borrow_1.clone();
assert!(borrow_1.eq(&1));
assert!(borrow_2.eq(&1));
drop(borrow_1);
assert_eq!(
registry.try_borrow_mut(&0).err(),
Some(BorrowError::AlreadyBorrowed)
);
drop(borrow_2);
assert!(registry.try_borrow_mut(&0).is_ok_and(|val| val.eq(&1)));
}
#[test]
fn converts_to_vector() {
let registry = VecBasedRegistry::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
assert_eq!(registry.into_vec(), vec![1, 2, 3, 4]);
}
#[test]
fn can_insert_with_borrows_out() {
let registry = VecBasedRegistry::with_capacity(16);
insert_many_into_registry(®istry, [1, 2, 3, 4]);
let borrow_1 = registry.borrow(&0);
let borrow_2 = registry.borrow_mut(&1);
insert_many_into_registry(®istry, 5..100);
let borrow_3 = registry.borrow(&4);
let borrow_4 = registry.borrow(&97);
assert!(borrow_1.eq(&1));
assert!(borrow_2.eq(&2));
assert!(borrow_3.eq(&5));
assert!(borrow_4.eq(&98));
}
#[test]
fn safe_to_drop_tracks_borrows() {
let mut registry = VecBasedRegistry::new();
assert!(registry.safe_to_drop());
insert_many_into_registry(®istry, [1, 2, 3, 4]);
assert!(registry.safe_to_drop());
let borrow_1: ElementRef<'_, i32> = unsafe { mem::transmute(registry.borrow(&0)) };
let borrow_2: ElementRef<'_, i32> = unsafe { mem::transmute(registry.borrow(&0)) };
let borrow_3: ElementRefMut<'_, i32> = unsafe { mem::transmute(registry.borrow_mut(&1)) };
assert!(!registry.safe_to_drop());
assert!(borrow_1.eq(&1));
assert!(borrow_2.eq(&1));
assert!(borrow_3.eq(&2));
drop(borrow_1);
assert!(!registry.safe_to_drop());
drop(borrow_2);
assert!(!registry.safe_to_drop());
drop(borrow_3);
assert!(registry.safe_to_drop());
}
#[test]
#[cfg(feature = "std")]
fn base_registry_is_send() {
let registry = VecBasedRegistry::<u64>::new();
insert_many_into_registry(®istry, [1, 2, 3, 4]);
let registry = Arc::new(Mutex::new(registry));
let f = |registry: Arc<Mutex<VecBasedRegistry<u64>>>| {
move || {
assert_eq!(registry.lock().unwrap().borrow(&0).as_ref(), &1);
}
};
std::thread::spawn(f(registry.clone())).join().unwrap();
}
}