diff --git a/lyra-ecs/src/archetype.rs b/lyra-ecs/src/archetype.rs index e6853ec..d9577db 100644 --- a/lyra-ecs/src/archetype.rs +++ b/lyra-ecs/src/archetype.rs @@ -18,9 +18,8 @@ impl Drop for ComponentColumn { let data = data.as_ptr(); unsafe { - // layout of current alloc - let layout = Layout::from_size_align_unchecked(self.info.layout.size() * self.capacity, - self.info.layout.align()); + // TODO: trigger drop on the components + let layout = self.info.layout(); dealloc(data, layout); } } @@ -42,7 +41,7 @@ impl ComponentColumn { } pub unsafe fn new(info: ComponentInfo, capacity: usize) -> Self { - let data = ComponentColumn::alloc(info.layout, capacity); + let data = ComponentColumn::alloc(info.layout(), capacity); Self { data: RefCell::new(data), @@ -64,7 +63,7 @@ impl ComponentColumn { let mut data = self.data.borrow_mut(); let data = data.deref_mut(); - let size = self.info.layout.size(); + let size = self.info.layout().size(); let dest = NonNull::new_unchecked(data.as_ptr().add(entity_index * size)); ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), size); @@ -87,27 +86,28 @@ impl ComponentColumn { Ref::map(data, |data| { let ptr = NonNull::new_unchecked(data.as_ptr() - .add(entity_index * self.info.layout.size())) + .add(entity_index * self.info.layout().size())) .cast(); &*ptr.as_ptr() }) } - /// Get a component at an entities index. + /// Get a mutable borrow to the component at an entities index, ticking the entity. /// /// # Safety /// /// This column must have the entity. - pub unsafe fn get_mut(&mut self, entity_index: usize, tick: &Tick) -> &mut T { + pub unsafe fn get_mut(&mut self, entity_index: usize, tick: &Tick) -> RefMut { self.entity_ticks[entity_index].tick_to(tick); - let mut data = self.data.borrow_mut(); - let data = data.deref_mut(); + let data = self.data.borrow_mut(); - let p = data.as_ptr() - .cast::() - .add(entity_index * self.info.layout.size()); - &mut *p + RefMut::map(data, |data| { + let ptr = NonNull::new_unchecked(data.as_ptr() + .add(entity_index * self.info.layout().size())) + .cast(); + &mut *ptr.as_ptr() + }) } /// Grow the column to fit `new_capacity` amount of components. @@ -125,17 +125,19 @@ impl ComponentColumn { let mut data = self.data.borrow_mut(); - let mut new_ptr = Self::alloc(self.info.layout, new_capacity); + let layout = self.info.layout(); + let mut new_ptr = Self::alloc(layout, new_capacity); if self.len > 0 { - ptr::copy_nonoverlapping(data.as_ptr(), new_ptr.as_ptr(), self.len * self.info.layout.size()); + ptr::copy_nonoverlapping(data.as_ptr(), new_ptr.as_ptr(), self.len * layout.size()); } // dont attempt to free if we weren't able to store anything anyway if self.capacity != 0 { + // create a layout with the same alignment, but expand the size of the buffer. let old_layout = Layout::from_size_align_unchecked( - self.info.layout.size().checked_mul(self.capacity).unwrap(), - self.info.layout.align() + layout.size().checked_mul(self.capacity).unwrap(), + layout.align() ); mem::swap(data.deref_mut(), &mut new_ptr); @@ -154,7 +156,7 @@ impl ComponentColumn { let mut data = self.data.borrow_mut(); let data = data.deref_mut(); - let size = self.info.layout.size(); + let size = self.info.layout().size(); let mut old_comp_ptr = NonNull::new_unchecked(data.as_ptr() .add(entity_index * size)); @@ -328,13 +330,14 @@ impl Archetype { /// Returns a boolean indicating whether this archetype can store the TypeIds given pub fn is_archetype_for(&self, types: &Vec) -> bool { if types.len() == self.columns.len() { - self.columns.iter().all(|c| types.contains(&c.info.type_id)) + self.columns.iter().all(|c| types.contains(&c.info.type_id())) } else { false } } /// Returns a boolean indicating whether this archetype has a column for `comp_type` - pub fn has_column(&self, comp_type: DynTypeId) -> bool { - self.columns.iter().any(|c| comp_type == c.info.type_id) + pub fn has_column>(&self, comp_type: I) -> bool { + let comp_type = comp_type.into(); + self.columns.iter().any(|c| comp_type == c.info.type_id()) } /// Returns a boolean indicating whether this archetype is empty or not. @@ -368,7 +371,7 @@ impl Archetype { /// Attempts to find the column storing components of `type_id` pub fn get_column>(&self, type_id: I) -> Option<&ComponentColumn> { let type_id = type_id.into(); - self.columns.iter().find(|c| c.info.type_id == type_id) + self.columns.iter().find(|c| c.info.type_id() == type_id) } /// Returns a mutable borrow to a component column for `type_id`. @@ -376,7 +379,7 @@ impl Archetype { /// Note: This does not modify the tick for the column! pub fn get_column_mut>(&mut self, type_id: I) -> Option<&mut ComponentColumn> { let type_id = type_id.into(); - self.columns.iter_mut().find(|c| c.info.type_id == type_id) + self.columns.iter_mut().find(|c| c.info.type_id() == type_id) } /// Reserves a slot in the columns for an entity and returns the index of that reserved spot diff --git a/lyra-ecs/src/bundle.rs b/lyra-ecs/src/bundle.rs index 85bc4ae..31d1952 100644 --- a/lyra-ecs/src/bundle.rs +++ b/lyra-ecs/src/bundle.rs @@ -143,7 +143,7 @@ impl DynamicBundle { impl Bundle for DynamicBundle { fn type_ids(&self) -> Vec { - self.bundle.iter().map(|b| b.1.type_id).collect() + self.bundle.iter().map(|b| b.1.type_id()).collect() } fn info(&self) -> Vec { @@ -152,7 +152,7 @@ impl Bundle for DynamicBundle { fn take(self, mut f: impl FnMut(NonNull, DynTypeId, usize)) { for (data, info) in self.bundle.iter() { - f(*data, info.type_id, info.layout.size()); + f(*data, info.type_id(), info.layout().size()); } } diff --git a/lyra-ecs/src/component_info.rs b/lyra-ecs/src/component_info.rs index a819f72..e363494 100644 --- a/lyra-ecs/src/component_info.rs +++ b/lyra-ecs/src/component_info.rs @@ -54,8 +54,8 @@ impl DynTypeId { /// Some information about a component. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ComponentInfo { - pub type_id: DynTypeId, - pub(crate) layout: Layout, + type_id: DynTypeId, + layout: Layout, } impl ComponentInfo { @@ -77,4 +77,12 @@ impl ComponentInfo { layout, } } + + pub fn type_id(&self) -> DynTypeId { + self.type_id + } + + pub fn layout(&self) -> Layout { + self.layout + } } \ No newline at end of file diff --git a/lyra-ecs/src/query/borrow.rs b/lyra-ecs/src/query/borrow.rs index f1cc5de..d5a1493 100644 --- a/lyra-ecs/src/query/borrow.rs +++ b/lyra-ecs/src/query/borrow.rs @@ -1,13 +1,12 @@ use std::{marker::PhantomData, ptr::NonNull, cell::{Ref, RefMut}}; -use crate::{world::World, ComponentColumn, DynTypeId, Tick, Component}; +use crate::{World, ComponentColumn, DynTypeId, Tick, Component}; use super::{Fetch, Query, AsQuery}; /// Fetcher for borrowing components from archetypes. pub struct FetchBorrow<'a, T> { col: &'a ComponentColumn, - size: usize, _phantom: PhantomData<&'a T> } @@ -22,13 +21,7 @@ where } unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { - let ptr = self.col.borrow_ptr(); - Ref::map(ptr, |ptr| { - let ptr = NonNull::new_unchecked(ptr.as_ptr() - .add(entity.0 as usize * self.size)) - .cast(); - &*ptr.as_ptr() - }) + self.col.get(entity.0 as _) } } @@ -81,17 +74,16 @@ where } fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { - archetype.columns.iter().any(|c| c.info.type_id == self.type_id) + archetype.has_column(self.type_id) } unsafe fn fetch<'a>(&self, _world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { let _ = tick; - let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id) + let col = archetype.get_column(self.type_id) .expect("You ignored 'can_visit_archetype'!"); FetchBorrow { col, - size: col.info.layout.size(), _phantom: PhantomData, } } @@ -108,7 +100,6 @@ impl AsQuery for &T { /// A fetcher for mutably borrowing components from archetypes. pub struct FetchBorrowMut<'a, T> { col: NonNull, - size: usize, tick: Tick, _phantom: PhantomData<&'a T> } @@ -125,15 +116,7 @@ where unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { let col = unsafe { self.col.as_mut() }; - col.entity_ticks[entity.0 as usize] = self.tick; - let ptr = col.borrow_mut_ptr(); - - RefMut::map(ptr, |ptr| { - let ptr = NonNull::new_unchecked(ptr.as_ptr() - .add(entity.0 as usize * self.size)) - .cast(); - &mut *ptr.as_ptr() - }) + col.get_mut(entity.0 as _, &self.tick) } } @@ -188,13 +171,12 @@ where } fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { - archetype.columns.iter().any(|c| c.info.type_id == self.type_id) + archetype.has_column(self.type_id) } unsafe fn fetch<'a>(&self, _world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { - let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id) + let col = archetype.get_column(self.type_id) .expect("You ignored 'can_visit_archetype'!"); - let layout_size = col.info.layout.size(); let col = NonNull::from(col); // TODO: find a way to get the component column mutable with a borrowed archetype so its tick can be updated. @@ -202,7 +184,6 @@ where FetchBorrowMut { col, - size: layout_size, tick, _phantom: PhantomData, } @@ -219,9 +200,9 @@ impl AsQuery for &mut T { #[cfg(test)] mod tests { - use std::{mem::size_of, marker::PhantomData, ptr::NonNull}; + use std::{marker::PhantomData, ptr::NonNull}; - use crate::{archetype::{Archetype, ArchetypeId}, bundle::Bundle, query::{Fetch, ViewState}, tests::Vec2, world::World, DynTypeId, Entity, EntityId, Tick}; + use crate::{archetype::{Archetype, ArchetypeId}, bundle::Bundle, query::{Fetch, ViewState}, tests::Vec2, World, DynTypeId, Entity, EntityId, Tick}; use super::{QueryBorrow, QueryBorrowMut, FetchBorrowMut}; @@ -298,12 +279,11 @@ mod tests { }, (Vec2::rand(),), &Tick::default()); } - let col = a.columns.iter().find(|c| c.info.type_id == DynTypeId::of::()).unwrap(); + let col = a.get_column(DynTypeId::of::()).unwrap(); let mut bmut = FetchBorrowMut:: { col: NonNull::from(col), tick: Tick::default(), - size: size_of::(), _phantom: PhantomData, }; let item = unsafe { bmut.get_item(crate::ArchetypeEntityId(0)) }; diff --git a/lyra-ecs/src/query/dynamic/mod.rs b/lyra-ecs/src/query/dynamic/mod.rs index 9ef43fc..7d0a343 100644 --- a/lyra-ecs/src/query/dynamic/mod.rs +++ b/lyra-ecs/src/query/dynamic/mod.rs @@ -1,6 +1,6 @@ use std::ptr::NonNull; -use crate::{world::World, ComponentColumn, ComponentInfo}; +use crate::{World, ComponentColumn, ComponentInfo}; mod view; pub use view::*; @@ -15,7 +15,7 @@ pub struct DynamicType { impl DynamicType { pub fn is(&self) -> bool { - self.info.type_id.is::() + self.info.type_id().is::() } } @@ -38,7 +38,7 @@ impl<'a> Fetch<'a> for FetchDynamicType<'a> { unsafe fn get_item(&mut self, entity: crate::ArchetypeEntityId) -> Self::Item { let ptr = self.col.borrow_ptr(); let ptr = NonNull::new_unchecked(ptr.as_ptr() - .add(entity.0 as usize * self.info.layout.size())); + .add(entity.0 as usize * self.info.layout().size())); DynamicType { info: self.info, @@ -63,11 +63,11 @@ impl QueryDynamicType { } pub fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { - archetype.has_column(self.info.type_id) + archetype.has_column(self.info.type_id()) } pub unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> FetchDynamicType<'a> { - let col = archetype.columns.iter().find(|c| c.info.type_id == self.info.type_id) + let col = archetype.get_column(self.info.type_id()) .expect("You ignored 'can_visit_archetype'!"); FetchDynamicType { diff --git a/lyra-ecs/src/query/dynamic/view.rs b/lyra-ecs/src/query/dynamic/view.rs index e2cbd8c..107a429 100644 --- a/lyra-ecs/src/query/dynamic/view.rs +++ b/lyra-ecs/src/query/dynamic/view.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crate::{world::World, Archetype, ArchetypeEntityId, ArchetypeId, query::Fetch}; +use crate::{World, Archetype, ArchetypeEntityId, ArchetypeId, query::Fetch}; use super::{QueryDynamicType, FetchDynamicType, DynamicType}; @@ -104,7 +104,7 @@ impl<'a> Iterator for DynamicViewIter<'a> { mod tests { use std::{alloc::Layout, ptr::NonNull}; - use crate::{world::World, ComponentInfo, DynTypeId, DynamicBundle, query::dynamic::QueryDynamicType}; + use crate::{World, ComponentInfo, DynTypeId, DynamicBundle, query::dynamic::QueryDynamicType}; use super::DynamicView; diff --git a/lyra-ecs/src/query/entities.rs b/lyra-ecs/src/query/entities.rs index 95f2137..9f2cef6 100644 --- a/lyra-ecs/src/query/entities.rs +++ b/lyra-ecs/src/query/entities.rs @@ -1,4 +1,4 @@ -use crate::{archetype::Archetype, world::World, Entity}; +use crate::{archetype::Archetype, World, Entity}; use super::{Fetch, Query, AsQuery}; diff --git a/lyra-ecs/src/query/mod.rs b/lyra-ecs/src/query/mod.rs index 02c5e62..a71e5c8 100644 --- a/lyra-ecs/src/query/mod.rs +++ b/lyra-ecs/src/query/mod.rs @@ -125,7 +125,7 @@ impl AsQuery for () { #[cfg(test)] mod tests { - use crate::{world::World, archetype::Archetype, tests::Vec2}; + use crate::{World, archetype::Archetype, tests::Vec2}; use super::{ViewState, Entities}; diff --git a/lyra-ecs/src/query/resource.rs b/lyra-ecs/src/query/resource.rs index 1f20667..328f2b2 100644 --- a/lyra-ecs/src/query/resource.rs +++ b/lyra-ecs/src/query/resource.rs @@ -1,6 +1,6 @@ use std::{marker::PhantomData, cell::{Ref, RefMut}}; -use crate::{world::World, resource::ResourceObject}; +use crate::{World, resource::ResourceObject}; use super::{Query, Fetch, AsQuery}; @@ -192,7 +192,7 @@ impl<'a, T: ResourceObject> AsQuery for ResMut<'a, T> { mod tests { use std::ops::{Deref, DerefMut}; - use crate::{query::{Res, ResMut}, tests::{Vec2, Vec3}, world::World}; + use crate::{query::{Res, ResMut}, tests::{Vec2, Vec3}, World}; struct SomeCounter(u32); diff --git a/lyra-ecs/src/query/tick.rs b/lyra-ecs/src/query/tick.rs index f2f4376..b942c79 100644 --- a/lyra-ecs/src/query/tick.rs +++ b/lyra-ecs/src/query/tick.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use crate::{ComponentColumn, Tick, DynTypeId, world::World}; +use crate::{ComponentColumn, Tick, DynTypeId, World}; use super::{Query, Fetch, AsQuery}; @@ -90,11 +90,11 @@ where } fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { - archetype.columns.iter().any(|c| c.info.type_id == self.type_id) + archetype.has_column(self.type_id) } unsafe fn fetch<'a>(&self, _world: &'a World, archetype: &'a crate::archetype::Archetype, _tick: crate::Tick) -> Self::Fetch<'a> { - let col = archetype.columns.iter().find(|c| c.info.type_id == self.type_id) + let col = archetype.get_column(self.type_id) .expect("You ignored 'can_visit_archetype'!"); FetchTickOf { diff --git a/lyra-ecs/src/query/tuple.rs b/lyra-ecs/src/query/tuple.rs index 13ab692..2d423cb 100644 --- a/lyra-ecs/src/query/tuple.rs +++ b/lyra-ecs/src/query/tuple.rs @@ -1,4 +1,4 @@ -use crate::world::World; +use crate::World; use super::{Query, Fetch, AsQuery}; @@ -175,7 +175,7 @@ impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14 #[cfg(test)] mod tests { - use crate::{world::World, tests::{Vec2, Vec3}}; + use crate::{World, tests::{Vec2, Vec3}}; #[test] fn tuple_queries() { diff --git a/lyra-ecs/src/relation/relate_pair.rs b/lyra-ecs/src/relation/relate_pair.rs index 1ab8f96..429554e 100644 --- a/lyra-ecs/src/relation/relate_pair.rs +++ b/lyra-ecs/src/relation/relate_pair.rs @@ -1,4 +1,4 @@ -use std::{any::TypeId, cell::Ref, marker::PhantomData}; +use std::{any::{Any, TypeId}, cell::Ref, marker::PhantomData}; use crate::{query::{AsQuery, Fetch, Query}, Archetype, ComponentColumn, Entity, World}; @@ -69,8 +69,7 @@ where unsafe fn fetch<'a>(&self, _world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { let _ = tick; - let tyid = crate::DynTypeId::Rust(TypeId::of::>()); - let col = archetype.columns.iter().find(|c| c.info.type_id == tyid) + let col = archetype.get_column(self.type_id()) .expect("You ignored 'can_visit_archetype'!"); FetchRelatePair { diff --git a/lyra-ecs/src/relation/relates_to.rs b/lyra-ecs/src/relation/relates_to.rs index e6588f6..ad04311 100644 --- a/lyra-ecs/src/relation/relates_to.rs +++ b/lyra-ecs/src/relation/relates_to.rs @@ -70,14 +70,12 @@ where } fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { - let tyid = crate::DynTypeId::Rust(TypeId::of::>()); - archetype.has_column(tyid) + archetype.has_column(TypeId::of::>()) } unsafe fn fetch<'a>(&self, _world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { let _ = tick; - let tyid = crate::DynTypeId::Rust(TypeId::of::>()); - let col = archetype.columns.iter().find(|c| c.info.type_id == tyid) + let col = archetype.get_column(TypeId::of::>()) .expect("You ignored 'can_visit_archetype'!"); FetchRelatesTo { diff --git a/lyra-ecs/src/system/batched.rs b/lyra-ecs/src/system/batched.rs index d924d0f..73a945c 100644 --- a/lyra-ecs/src/system/batched.rs +++ b/lyra-ecs/src/system/batched.rs @@ -1,4 +1,4 @@ -use lyra_ecs::world::World; +use lyra_ecs::World; use crate::Access; diff --git a/lyra-ecs/src/system/criteria.rs b/lyra-ecs/src/system/criteria.rs index e7dcf07..d0a2868 100644 --- a/lyra-ecs/src/system/criteria.rs +++ b/lyra-ecs/src/system/criteria.rs @@ -1,6 +1,6 @@ use std::ptr::NonNull; -use lyra_ecs::world::World; +use lyra_ecs::World; /// An enum that is used to control if the Criteria was met or not. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] diff --git a/lyra-ecs/src/system/fn_sys.rs b/lyra-ecs/src/system/fn_sys.rs index b9079fd..c768161 100644 --- a/lyra-ecs/src/system/fn_sys.rs +++ b/lyra-ecs/src/system/fn_sys.rs @@ -1,7 +1,7 @@ use std::{any::Any, marker::PhantomData, ptr::NonNull}; use paste::paste; -use crate::{world::World, Access, ResourceObject, query::{Query, ViewState, ResMut, Res}}; +use crate::{World, Access, ResourceObject, query::{Query, ViewState, ResMut, Res}}; use super::{System, IntoSystem}; @@ -239,7 +239,7 @@ impl FnArgFetcher for ResMut<'_, R> { mod tests { use std::ptr::NonNull; - use crate::{tests::{Vec2, Vec3}, world::World, query::{QueryBorrow, ViewState, ResMut}}; + use crate::{tests::{Vec2, Vec3}, World, query::{QueryBorrow, ViewState, ResMut}}; use super::{System, IntoSystem}; struct SomeCounter(u32); diff --git a/lyra-ecs/src/system/graph.rs b/lyra-ecs/src/system/graph.rs index 4dd9044..73fbc17 100644 --- a/lyra-ecs/src/system/graph.rs +++ b/lyra-ecs/src/system/graph.rs @@ -2,7 +2,7 @@ use std::{collections::{HashMap, VecDeque, HashSet}, ptr::NonNull}; use super::System; -use crate::{world::World, CommandQueue, Commands}; +use crate::{World, CommandQueue, Commands}; #[derive(thiserror::Error, Debug)] pub enum GraphExecutorError { @@ -140,7 +140,7 @@ impl GraphExecutor { mod tests { use std::ptr::NonNull; - use crate::{query::{ResMut, View}, system::IntoSystem, world::World}; + use crate::{query::{ResMut, View}, system::IntoSystem, World}; use super::GraphExecutor; diff --git a/lyra-ecs/src/system/mod.rs b/lyra-ecs/src/system/mod.rs index 0471b89..625a166 100644 --- a/lyra-ecs/src/system/mod.rs +++ b/lyra-ecs/src/system/mod.rs @@ -1,6 +1,6 @@ use std::ptr::NonNull; -use crate::{world::World, Access}; +use crate::{World, Access}; mod graph; pub use graph::*; diff --git a/lyra-ecs/src/world.rs b/lyra-ecs/src/world.rs index bc38646..6ea08a6 100644 --- a/lyra-ecs/src/world.rs +++ b/lyra-ecs/src/world.rs @@ -143,7 +143,7 @@ impl World { let record = self.entities.entity_record(entity).unwrap(); let current_arch = self.archetypes.get(&record.id).unwrap(); - let mut col_types: Vec = current_arch.columns.iter().map(|c| c.info.type_id).collect(); + let mut col_types: Vec = current_arch.columns.iter().map(|c| c.info.type_id()).collect(); let orig_col = col_types.clone(); col_types.extend(bundle.type_ids()); @@ -158,7 +158,7 @@ impl World { for (col_type, (col_ptr, col_info)) in orig_col.into_iter().zip(col_ptrs.into_iter()) { unsafe { let ptr = NonNull::new_unchecked(col_ptr.as_ptr() - .add(res_index.0 as usize * col_info.layout.size())); + .add(res_index.0 as usize * col_info.layout().size())); let col = arch.get_column_mut(col_type).unwrap(); col.set_at(res_index.0 as _, ptr, tick); }