Return Ref and RefMut from the borrow queries to enforce borrow checks even more

This commit is contained in:
SeanOMik 2023-12-01 16:50:41 -05:00
parent 6fedb270b9
commit 7f17a97ef7
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
2 changed files with 36 additions and 39 deletions

View File

@ -12,8 +12,8 @@ I couldn't find anything that fulfilled my needs, specifically an ECS that can s
- [x] Find some way to fill in the gaps in component columns after entities are deleted - [x] Find some way to fill in the gaps in component columns after entities are deleted
* This was done by moving the last entity in the column to the gap that was just removed. * This was done by moving the last entity in the column to the gap that was just removed.
- [x] Grow archetype as it fills up - [x] Grow archetype as it fills up
- [ ] Borrow safety of components inside Archetypes - [x] Borrow safety of components inside Archetypes
* Return `Ref` and `RefMut` from borrow queries - [x] Return `Ref` and `RefMut` from borrow queries
- [ ] Querying components from archetypes - [ ] Querying components from archetypes
- [x] Views - [x] Views
- [ ] Mutable views - [ ] Mutable views
@ -25,6 +25,7 @@ I couldn't find anything that fulfilled my needs, specifically an ECS that can s
* Needed for scripting engines that can create their own components that Rust does not know the types of. * Needed for scripting engines that can create their own components that Rust does not know the types of.
- [ ] Systems - [ ] Systems
- [ ] Dispatchers/Executors - [ ] Dispatchers/Executors
- [ ] Execution graph that follows dependencies
<br> <br>

View File

@ -1,12 +1,12 @@
use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::{Ref, RefCell, RefMut}}; use std::{marker::PhantomData, any::TypeId, ptr::NonNull, cell::{Ref, RefCell, RefMut}};
use crate::world::World; use crate::{world::World, ComponentColumn};
use super::{Fetch, Query, AsQuery, DefaultQuery}; use super::{Fetch, Query, AsQuery, DefaultQuery};
/// Fetcher for borrowing components from archetypes. /// Fetcher for borrowing components from archetypes.
pub struct FetchBorrow<'a, T> { pub struct FetchBorrow<'a, T> {
ptr: Option<Ref<'a, NonNull<u8>>>, col: &'a ComponentColumn,
size: usize, size: usize,
_phantom: PhantomData<&'a T> _phantom: PhantomData<&'a T>
} }
@ -15,22 +15,20 @@ impl<'a, T> Fetch<'a> for FetchBorrow<'a, T>
where where
T: 'a, T: 'a,
{ {
type Item = &'a T; type Item = Ref<'a, T>;
fn dangling() -> Self { fn dangling() -> Self {
FetchBorrow { unreachable!()
ptr: None,
size: 0,
_phantom: PhantomData::default()
}
} }
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
let ptr = self.ptr.as_ref().unwrap(); let ptr = self.col.borrow_ptr();
Ref::map(ptr, |ptr| {
let ptr = NonNull::new_unchecked(ptr.as_ptr() let ptr = NonNull::new_unchecked(ptr.as_ptr()
.add(entity.0 as usize * self.size)) .add(entity.0 as usize * self.size))
.cast(); .cast();
&*ptr.as_ptr() &*ptr.as_ptr()
})
} }
} }
@ -60,7 +58,7 @@ impl<T> Query for QueryBorrow<T>
where where
T: 'static T: 'static
{ {
type Item<'a> = &'a T; type Item<'a> = Ref<'a, T>;
type Fetch<'a> = FetchBorrow<'a, T>; type Fetch<'a> = FetchBorrow<'a, T>;
@ -71,10 +69,9 @@ where
unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> { unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id) let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
.expect("You ignored 'can_visit_archetype'!"); .expect("You ignored 'can_visit_archetype'!");
let col_data = col.borrow_ptr();
FetchBorrow { FetchBorrow {
ptr: Some(col_data), col,
size: col.info.layout.size(), size: col.info.layout.size(),
_phantom: PhantomData, _phantom: PhantomData,
} }
@ -103,7 +100,7 @@ impl<T: 'static> DefaultQuery for &T {
/// A fetcher for mutably borrowing components from archetypes. /// A fetcher for mutably borrowing components from archetypes.
pub struct FetchBorrowMut<'a, T> { pub struct FetchBorrowMut<'a, T> {
ptr: Option<RefMut<'a, NonNull<u8>>>, col: &'a ComponentColumn,
size: usize, size: usize,
_phantom: PhantomData<&'a T> _phantom: PhantomData<&'a T>
} }
@ -112,22 +109,20 @@ impl<'a, T> Fetch<'a> for FetchBorrowMut<'a, T>
where where
T: 'a, T: 'a,
{ {
type Item = &'a mut T; type Item = RefMut<'a, T>;
fn dangling() -> Self { fn dangling() -> Self {
FetchBorrowMut { unreachable!()
ptr: None,
size: 0,
_phantom: PhantomData::default()
}
} }
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
let ptr = self.ptr.as_ref().unwrap(); let ptr = self.col.borrow_mut_ptr();
RefMut::map(ptr, |ptr| {
let ptr = NonNull::new_unchecked(ptr.as_ptr() let ptr = NonNull::new_unchecked(ptr.as_ptr()
.add(entity.0 as usize * self.size)) .add(entity.0 as usize * self.size))
.cast(); .cast();
&mut *ptr.as_ptr() &mut *ptr.as_ptr()
})
} }
} }
@ -157,7 +152,7 @@ impl<T> Query for QueryBorrowMut<T>
where where
T: 'static T: 'static
{ {
type Item<'a> = &'a mut T; type Item<'a> = RefMut<'a, T>;
type Fetch<'a> = FetchBorrowMut<'a, T>; type Fetch<'a> = FetchBorrowMut<'a, T>;
@ -168,10 +163,9 @@ where
unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> { unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id) let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id)
.expect("You ignored 'can_visit_archetype'!"); .expect("You ignored 'can_visit_archetype'!");
let col_data = col.borrow_mut_ptr();
FetchBorrowMut { FetchBorrowMut {
ptr: Some(col_data), col,
size: col.info.layout.size(), size: col.info.layout.size(),
_phantom: PhantomData, _phantom: PhantomData,
} }
@ -202,7 +196,7 @@ impl<T: 'static> DefaultQuery for &mut T {
mod tests { mod tests {
use std::{any::TypeId, mem::size_of, marker::PhantomData}; use std::{any::TypeId, mem::size_of, marker::PhantomData};
use crate::{world::{World, Entity, EntityId}, archetype::{Archetype, ArchetypeId}, query::View, tests::Vec2, bundle::Bundle}; use crate::{world::{World, Entity, EntityId}, archetype::{Archetype, ArchetypeId}, query::View, tests::Vec2, bundle::Bundle, Fetch};
use super::{QueryBorrow, QueryBorrowMut, FetchBorrowMut}; use super::{QueryBorrow, QueryBorrowMut, FetchBorrowMut};
@ -245,7 +239,7 @@ mod tests {
let mut orig = vec![]; let mut orig = vec![];
for v in v.into_iter() { for mut v in v.into_iter() {
orig.push(v.clone()); orig.push(v.clone());
v.x += 10.0; v.x += 10.0;
v.y += 10.0; v.y += 10.0;
@ -281,14 +275,16 @@ mod tests {
let col = a.columns.iter().find(|c| c.info.type_id == TypeId::of::<Vec2>()).unwrap(); let col = a.columns.iter().find(|c| c.info.type_id == TypeId::of::<Vec2>()).unwrap();
let bmut = FetchBorrowMut::<Vec2> { let mut bmut = FetchBorrowMut::<Vec2> {
ptr: Some(col.borrow_mut_ptr()), col,
size: size_of::<Vec2>(), size: size_of::<Vec2>(),
_phantom: PhantomData, _phantom: PhantomData,
}; };
let item = unsafe { bmut.get_item(crate::ArchetypeEntityId(0)) };
// ensure only one mutable borrow can be done at a time
assert!(col.try_borrow_mut_ptr().is_err()); assert!(col.try_borrow_mut_ptr().is_err());
drop(bmut); drop(item);
assert!(col.try_borrow_mut_ptr().is_ok()); assert!(col.try_borrow_mut_ptr().is_ok());
} }
} }