From 2c718231ed7aa9ff00a986b9bf4a901e5235b27f Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sun, 26 Nov 2023 00:56:30 -0500 Subject: [PATCH] Implement query for tuples of query types --- lyra-ecs/src/archetype.rs | 77 +------------- lyra-ecs/src/bundle.rs | 84 +++++++--------- lyra-ecs/src/main.rs | 18 ---- lyra-ecs/src/query/borrow.rs | 8 +- lyra-ecs/src/query/entities.rs | 18 +--- lyra-ecs/src/query/mod.rs | 80 ++------------- lyra-ecs/src/query/tuple.rs | 179 +++++++++++++++++++++++++++++++++ lyra-ecs/src/query/view.rs | 2 +- lyra-ecs/src/tests.rs | 17 ++++ lyra-ecs/src/world.rs | 28 +----- 10 files changed, 260 insertions(+), 251 deletions(-) create mode 100644 lyra-ecs/src/query/tuple.rs diff --git a/lyra-ecs/src/archetype.rs b/lyra-ecs/src/archetype.rs index b9d592b..df97f2b 100644 --- a/lyra-ecs/src/archetype.rs +++ b/lyra-ecs/src/archetype.rs @@ -1,6 +1,6 @@ -use std::{any::{Any, TypeId, type_name}, ptr::{NonNull, self}, alloc::{self, Layout, alloc}, mem::size_of}; +use std::{any::TypeId, ptr::{NonNull, self}, alloc::{self, Layout, alloc}}; -use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component::Component, component_info::ComponentInfo}; +use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component_info::ComponentInfo}; pub struct ComponentColumn { pub data: NonNull, @@ -9,6 +9,7 @@ pub struct ComponentColumn { pub entry_size: usize, } +#[allow(dead_code)] impl ComponentColumn { /// Creates an invalid component column. Do not attempt to use it. pub unsafe fn dangling() -> Self { @@ -45,19 +46,6 @@ impl ComponentColumn { } } - /// Creates an empty column of the same type - pub unsafe fn create_empty(&self, capacity: usize) -> Self { - let data = ComponentColumn::alloc(self.info.layout, capacity); - - let size = self.info.layout.size(); - Self { - data, - capacity, - info: self.info.clone(), - entry_size: size, - } - } - /// Set a component from pointer at an entity index. /// /// # Safety @@ -117,46 +105,6 @@ pub struct Archetype { const DEFAULT_CAPACITY: usize = 32; impl Archetype { - /// Create a new archetype from another archetype and add a column - pub fn new_archetype_add(new_id: ArchetypeId, archetype: &Archetype) -> Archetype { - let mut columns: Vec<_> = archetype - .columns - .iter() - .map(|c| unsafe { c.create_empty(DEFAULT_CAPACITY) }) - .collect(); - - // Make sure a column for the new component does not exist - assert_ne!(true, columns.iter().any(|c| c.info.type_id == TypeId::of::()) ); - columns.push(unsafe { ComponentColumn::new(ComponentInfo::new::(), DEFAULT_CAPACITY) }); - - Archetype { - id: new_id, - entities: Vec::new(), - columns, - } - } - - /// Create a new archetype from another archetype and remove a column - pub fn new_archetype_remove(new_id: ArchetypeId, archetype: &Archetype) -> Archetype { - let mut columns: Vec<_> = archetype - .columns - .iter() - .map(|c| unsafe { c.create_empty(DEFAULT_CAPACITY) }) - .collect(); - - let idx = columns - .iter() - .position(|column| column.info.type_id == TypeId::of::()) - .unwrap(); - columns.remove(idx); - - Archetype { - id: new_id, - entities: Vec::new(), - columns, - } - } - pub fn from_bundle_info(new_id: ArchetypeId, bundle_info: Vec) -> Archetype { let columns = bundle_info.into_iter().map(|i| { unsafe { ComponentColumn::new(i, DEFAULT_CAPACITY) } @@ -169,21 +117,6 @@ impl Archetype { } } - pub fn get_component_mut(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> { - todo!() - } - - pub fn get_entity_component(&self, entity: ArchetypeEntityId) -> Option<&T> { - let type_id = TypeId::of::(); - - self.columns.iter().find(|c| c.info.type_id == type_id) - .map(|c| unsafe { c.get(entity.0 as usize) }) - } - - pub fn get_component_column(&self) -> Option<&Vec> { - todo!() - } - /// Add an entity and its component bundle to the Archetype /// /// # Safety: @@ -196,7 +129,7 @@ impl Archetype { let entity_index = self.entities.len(); self.entities.push(entity); - bundle.takefn(|data, type_id, size| { + bundle.take(|data, type_id, _size| { let col = self.columns.iter_mut().find(|c| c.info.type_id == type_id).unwrap(); unsafe { col.set_at(entity_index, data); } }); @@ -204,7 +137,7 @@ impl Archetype { ArchetypeEntityId(entity_index as u64) } - /// returns a boolean indicating whether this archetype can store the TypeIds given + /// Returns a boolean indicating whether this archetype can store the TypeIds given pub(crate) fn is_archetype_for(&self, types: Vec) -> bool { self.columns.iter().all(|c| types.contains(&c.info.type_id)) } diff --git a/lyra-ecs/src/bundle.rs b/lyra-ecs/src/bundle.rs index 9fbacdb..da779cd 100644 --- a/lyra-ecs/src/bundle.rs +++ b/lyra-ecs/src/bundle.rs @@ -1,27 +1,22 @@ -use std::{any::{TypeId, Any}, cell::Ref, ptr::NonNull, mem::size_of}; +use std::{any::{TypeId, Any}, ptr::NonNull, mem::size_of}; -use crate::{archetype::{ComponentColumn, Archetype}, component::Component, component_info::ComponentInfo}; +use crate::{component::Component, component_info::ComponentInfo}; pub trait Bundle { - // Get a list of type ids that this bundle is storing - fn types(&self) -> Vec; - /// Take components into a list. - /// The return value could be seen as a list of a list of components, but that inner list - /// only contains a single value to make it easier to add it to an archetype. - //fn take_components(self) -> Vec>; - - //fn from_component_columns(columns: Vec<&Box>) -> Self; - //fn from_archetype(archetype: &Archetype) -> Self; + /// Get a list of type ids that this bundle is storing + fn type_ids(&self) -> Vec; + /// Get ComponentInfo's for the components in this bundle fn info(&self) -> Vec; /// Take the bundle by calling the closure with pointers to each component, its type and size. /// The closure is expected to take ownership of the pointer. - fn takefn(self, cb: impl FnMut(NonNull, TypeId, usize)); + fn take(self, f: impl FnMut(NonNull, TypeId, usize)); } +// The macro below can implement this for us, but this is here for development impl Bundle for (C1,) { - fn types(&self) -> Vec { + fn type_ids(&self) -> Vec { vec![self.0.type_id()] } @@ -29,51 +24,50 @@ impl Bundle for (C1,) { vec![ComponentInfo::new::()] } - fn takefn(self, mut cb: impl FnMut(NonNull, TypeId, usize)) { + fn take(self, mut f: impl FnMut(NonNull, TypeId, usize)) { let (c1, ) = self; - cb(NonNull::from(&c1).cast(), TypeId::of::(), size_of::()); + f(NonNull::from(&c1).cast(), TypeId::of::(), size_of::()); } } -/* macro_rules! impl_bundle_tuple { - ( $(($name: ident, $index: tt))+ ) => ( +macro_rules! impl_bundle_tuple { + ( $($name: ident),+ ) => ( + #[allow(non_snake_case)] impl<$($name: Component),+> Bundle for ($($name,)+) { - fn types(&self) -> Vec { - vec![$(self.$index.type_id()),+] + fn type_ids(&self) -> Vec { + // these names wont follow rust convention, but its a macro so deal with it + let ($($name),+) = self; + vec![$($name.type_id()),+] } - fn take_components(self) -> Vec> { - vec![$(Box::new(vec![self.$index])),+] + fn info(&self) -> Vec { + vec![$(ComponentInfo::new::<$name>()),+] } - fn from_component_columns(columns: Vec<&Box>) -> Self { - let mut chains = Vec::new(); + fn take(self, mut f: impl FnMut(NonNull, TypeId, usize)) { + // these names wont follow rust convention, but its a macro so deal with it + let ($($name),+) = self; - for col in columns.iter() { - col. - } - - todo!() + $(f(NonNull::from(&$name).cast(), TypeId::of::<$name>(), size_of::<$name>());)+ } } ); -} */ +} // hopefully 16 components in a bundle is enough -//impl_bundle_tuple! { (C1, 0) } -/* impl_bundle_tuple! { (C1, 0) (C2, 1) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) (C14, 13) } -impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8, 7) (C9, 8) (C10, 9) (C11, 10) (C12, 11) (C13, 12) (C14, 13) (C15, 14) } - */ \ No newline at end of file +impl_bundle_tuple! { C1, C2 } +impl_bundle_tuple! { C1, C2, C3 } +impl_bundle_tuple! { C1, C2, C3, C4 } +impl_bundle_tuple! { C1, C2, C3, C4, C5 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15 } +impl_bundle_tuple! { C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16 } \ No newline at end of file diff --git a/lyra-ecs/src/main.rs b/lyra-ecs/src/main.rs index 5fb0381..690d95a 100644 --- a/lyra-ecs/src/main.rs +++ b/lyra-ecs/src/main.rs @@ -16,25 +16,7 @@ pub struct Position2d(i32, i32); fn main() { let mut world = World::new(); - - let pos = Position2d(50, 50); - let e = world.spawn((pos,)); - - if let Some(pos) = world.get_component::(e) { - println!("Got Position2d: {:?}", pos); - } else { - println!("no component found :("); - } let pos = Position2d(836, 348); let _e = world.spawn((pos,)); - - println!("\nstart of querying!\n"); - - let mut q = world.query_better(); - q.with_component::(); - - for pos in q.run::() { - println!("Queried Position2d: {:?}", pos); - } } diff --git a/lyra-ecs/src/query/borrow.rs b/lyra-ecs/src/query/borrow.rs index 522d3ed..99ec9dc 100644 --- a/lyra-ecs/src/query/borrow.rs +++ b/lyra-ecs/src/query/borrow.rs @@ -1,8 +1,6 @@ use std::{marker::PhantomData, any::TypeId, ptr::NonNull}; -use crate::component::Component; - -use super::{Fetch, Query, AsQuery, IntoQuery, DefaultQuery}; +use super::{Fetch, Query, AsQuery, DefaultQuery}; pub struct FetchBorrow<'a, T> { ptr: NonNull, @@ -16,7 +14,7 @@ where { type Item = &'a T; - fn create_empty() -> Self { + fn dangling() -> Self { FetchBorrow { ptr: NonNull::dangling(), size: 0, @@ -103,7 +101,7 @@ where { type Item = &'a mut T; - fn create_empty() -> Self { + fn dangling() -> Self { FetchBorrowMut { ptr: NonNull::dangling(), size: 0, diff --git a/lyra-ecs/src/query/entities.rs b/lyra-ecs/src/query/entities.rs index a8bcb8e..6156a1e 100644 --- a/lyra-ecs/src/query/entities.rs +++ b/lyra-ecs/src/query/entities.rs @@ -1,6 +1,6 @@ use crate::{world::Entity, archetype::{Archetype, ArchetypeId}}; -use super::{Fetch, Query, DefaultQuery, AsQuery}; +use super::{Fetch, Query}; pub struct EntitiesFetch<'a> { entities: &'a [Entity], @@ -14,7 +14,7 @@ impl<'a> Fetch<'a> for EntitiesFetch<'a> { e } - fn create_empty() -> Self { + fn dangling() -> Self { Self { entities: &[], } @@ -29,22 +29,14 @@ impl Query for Entities { type Fetch<'a> = EntitiesFetch<'a>; fn can_visit_archetype(&self, archetype: &Archetype) -> bool { + let _ = archetype; // ignore unused warnings true } unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a> { + let _ = arch_id; // ignore unused warnings EntitiesFetch { entities: &archetype.entities, } } -} - -/* impl AsQuery for Entities { - type Query = Entities; -} - -impl DefaultQuery for Entities { - fn default_query() -> Self { - Entities - } -} */ \ No newline at end of file +} \ No newline at end of file diff --git a/lyra-ecs/src/query/mod.rs b/lyra-ecs/src/query/mod.rs index cdd4e2e..03e98fe 100644 --- a/lyra-ecs/src/query/mod.rs +++ b/lyra-ecs/src/query/mod.rs @@ -1,85 +1,19 @@ -use std::{any::{TypeId, Any}, cell::RefCell, rc::Rc, collections::{HashMap, VecDeque}, io::Read, slice::Iter, ops::Range}; - -use crate::{archetype::{Archetype, ComponentColumn, ArchetypeId}, bundle::Bundle, component::Component, world::{Record, EntityId, ArchetypeEntityId}}; +use crate::{archetype::{Archetype, ArchetypeId}, world::ArchetypeEntityId}; pub mod view; pub use view::*; pub mod entities; +#[allow(unused_imports)] pub use entities::*; pub mod borrow; +#[allow(unused_imports)] pub use borrow::*; -pub struct QuerySimple<'a> { - //entities: Iter, - type_ids: Vec, -} - -impl<'a> QuerySimple<'a> { - pub fn new(archetypes: Vec<&'a Archetype>) -> Self { - Self { - archetypes, - type_ids: Vec::new(), - } - } - - pub fn with_component(&mut self) { - let type_id = TypeId::of::(); - self.type_ids.push(type_id); - } - - pub fn run(&self) -> impl Iterator - { - //let mut columns = Vec::new(); - - /* for type_id in self.type_ids.iter() { - for arch in self.archetypes.iter() { - if let Some(col) = arch.columns - .iter().find(|c| c.component_type_id() == type_id.clone()) { - - columns.push(col); - } - } - } - - let mut entities: Vec<&C1> = columns.iter().map(|bx| bx.as_any().downcast_ref::() - .expect("Failure to downcast component column")) - .collect(); */ - - let entities = self.archetypes - .iter() - .filter_map(|a| a.get_component_column::()) - .flatten(); - - - /* let columns = self.type_ids - .iter() - .map(|type_id| { - let a = self.archetypes - .iter() - .filter_map(|arch| { - arch.columns - .iter() - .find(|c| c.component_type_id() == type_id.clone()) - }); - }); */ - - /* self.type_ids - .iter() - .map(|type_id| { - self.archetypes - .iter() - .map(|arch| { - arch.get_component_column_typeid(type_id.clone()) - }) - }); */ - - - return entities; - } -} +pub mod tuple; +#[allow(unused_imports)] +pub use tuple::*; /// A [`Fetch`]er implementation gets data out of an archetype. pub trait Fetch<'a> { @@ -93,7 +27,7 @@ pub trait Fetch<'a> { } /// Creates an empty Fetch. DO NOT try to `get_item` on this - fn create_empty() -> Self; + fn dangling() -> Self; unsafe fn get_item(&mut self, entity: ArchetypeEntityId) -> Self::Item; } diff --git a/lyra-ecs/src/query/tuple.rs b/lyra-ecs/src/query/tuple.rs new file mode 100644 index 0000000..7e3a5b7 --- /dev/null +++ b/lyra-ecs/src/query/tuple.rs @@ -0,0 +1,179 @@ +use super::{Query, Fetch, AsQuery, DefaultQuery}; + +// Technically all of these implementations for a 2-sized tuple +// can be implemented by the macro near the end of the file, but +// these are left here for development. + +impl<'a, F1, F2> Fetch<'a> for (F1, F2) +where + F1: Fetch<'a>, + F2: Fetch<'a>, +{ + type Item = (F1::Item, F2::Item); + + fn dangling() -> Self { + (F1::dangling(), F2::dangling()) + } + + fn can_visit_item(&mut self, entity: crate::world::ArchetypeEntityId) -> bool { + let (f1, f2) = self; + f1.can_visit_item(entity) && f2.can_visit_item(entity) + } + + unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { + let (f1, f2) = self; + ( f1.get_item(entity), f2.get_item(entity) ) + } +} + +impl Query for (Q1, Q2) +where + Q1: Query, + Q2: Query, +{ + type Item<'a> = (Q1::Item<'a>, Q2::Item<'a>); + + type Fetch<'a> = (Q1::Fetch<'a>, Q2::Fetch<'a>); + + fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { + let (q1, q2) = self; + q1.can_visit_archetype(archetype) && q2.can_visit_archetype(archetype) + } + + unsafe fn fetch<'a>(&self, arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> { + let (q1, q2) = self; + ( q1.fetch(arch_id, archetype), q2.fetch(arch_id, archetype) ) + } +} + +impl AsQuery for (Q1, Q2) +where + Q1: AsQuery, + Q2: AsQuery, +{ + type Query = (Q1::Query, Q2::Query); +} + +impl DefaultQuery for (Q1, Q2) +where + Q1: DefaultQuery, + Q2: DefaultQuery, +{ + fn default_query() -> (Q1::Query, Q2::Query) { + ( Q1::default_query(), Q2::default_query() ) + } +} + +macro_rules! impl_bundle_tuple { + ( $($name: ident),+ ) => ( + #[allow(non_snake_case)] + impl<'a, $($name: Fetch<'a>),+> Fetch<'a> for ($($name,)+) { + type Item = ($($name::Item,)+); + + fn dangling() -> Self { + ( $($name::dangling(),)+ ) + } + + fn can_visit_item(&mut self, entity: crate::world::ArchetypeEntityId) -> bool { + let ( $($name,)+ ) = self; + + // this is the only way I could figure out how to do an 'and' + let bools = vec![$($name.can_visit_item(entity),)+]; + bools.iter().all(|b| *b) + } + + unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { + let ( $($name,)+ ) = self; + ( $($name.get_item(entity),)+ ) + } + } + + #[allow(non_snake_case)] + impl<$($name: Query),+> Query for ($($name,)+) { + type Item<'a> = ($($name::Item<'a>,)+); + type Fetch<'a> = ($($name::Fetch<'a>,)+); + + fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { + let ( $($name,)+ ) = self; + + // this is the only way I could figure out how to do an 'and' + let bools = vec![$($name.can_visit_archetype(archetype),)+]; + bools.iter().all(|b| *b) + } + + unsafe fn fetch<'a>(&self, arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> { + let ( $($name,)+ ) = self; + ( $($name.fetch(arch_id, archetype),)+ ) + } + } + + impl<$($name: AsQuery),+> AsQuery for ($($name,)+) { + type Query = ($($name::Query,)+); + } + + impl<$($name: DefaultQuery),+> DefaultQuery for ($($name,)+) { + fn default_query() -> ($($name::Query,)+) { + ( $($name::default_query(),)+ ) + } + } + ); +} + +// Hopefully up to 16 queries in a SINGLE view is enough +impl_bundle_tuple! { Q1, Q2, Q3 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15 } +impl_bundle_tuple! { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, Q16 } + +#[cfg(test)] +mod tests { + use crate::{world::World, tests::{Vec2, Vec3}}; + + #[test] + fn tuple_queries() { + let mut world = World::new(); + + let comps = &[ + ( + Vec2 { + x: 10.0, + y: 15.0, + }, + Vec3 { + x: 83.0, + y: 38.0, + z: 98.0, + } + ), + ( + Vec2 { + x: 152.0, + y: 3585.0, + }, + Vec3 { + x: 43.0, + y: 29.0, + z: 30.0, + } + ), + ]; + + world.spawn(comps[0]); + world.spawn(comps[1]); + + for (pos2, pos3) in world.view::<(&Vec2, &Vec3)>() { + println!("Entity at {:?} and {:?}", pos2, pos3); + assert!(comps.contains(&( pos2.clone(), pos3.clone() ))); + } + } +} \ No newline at end of file diff --git a/lyra-ecs/src/query/view.rs b/lyra-ecs/src/query/view.rs index 9fa5323..a50e763 100644 --- a/lyra-ecs/src/query/view.rs +++ b/lyra-ecs/src/query/view.rs @@ -32,7 +32,7 @@ where fn into_iter(self) -> Self::IntoIter { ViewIter { query: self.query, - fetcher: Q::Fetch::create_empty(), + fetcher: Q::Fetch::dangling(), archetypes: self.archetypes, next_archetype: 0, component_indices: 0..0, diff --git a/lyra-ecs/src/tests.rs b/lyra-ecs/src/tests.rs index d8d87e7..589db5b 100644 --- a/lyra-ecs/src/tests.rs +++ b/lyra-ecs/src/tests.rs @@ -13,4 +13,21 @@ impl Vec2 { y, } } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] +pub struct Vec3 { + pub x: f32, + pub y: f32, + pub z: f32, +} + +impl Vec3 { + pub fn new(x: f32, y: f32, z: f32) -> Self { + Self { + x, + y, + z + } + } } \ No newline at end of file diff --git a/lyra-ecs/src/world.rs b/lyra-ecs/src/world.rs index 7de0e57..25278e9 100644 --- a/lyra-ecs/src/world.rs +++ b/lyra-ecs/src/world.rs @@ -1,7 +1,6 @@ -use std::{collections::{HashMap, VecDeque}, any::{Any, TypeId}}; -use std::slice::Iter; +use std::collections::{HashMap, VecDeque}; -use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component, query::{QuerySimple, ViewIter, IntoQuery, View, AsQuery, DefaultQuery}}; +use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component, query::{ViewIter, View, DefaultQuery}}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct EntityId(pub u64); @@ -60,7 +59,7 @@ impl World { where B: Bundle { - let bundle_types = bundle.types(); + let bundle_types = bundle.type_ids(); let new_entity = self.get_new_entity(); // try to find an archetype @@ -102,30 +101,11 @@ impl World { new_entity } - pub fn get_component(&self, entity: Entity) -> Option<&T> { - let record = self.entity_index.get(&entity.id)?; - let archetype = self.archetypes.get(&record.id)?; - - archetype.get_entity_component(record.index) - } - pub fn view<'a, T: 'static + Component + DefaultQuery>(&'a self) -> ViewIter<'a, T::Query> { let archetypes = self.archetypes.values().collect(); let v = View::new(T::default_query(), archetypes); v.into_iter() } - - pub fn query_better(&self) -> QuerySimple { - let archetypes = self.archetypes.values().collect(); - QuerySimple::new(archetypes) - } - - /* pub fn query_m(&self) -> impl Iterator { - self.archetypes - .iter() - .filter_map(|(_, a)| a.get_component_column::()) - .flatten() - } */ } #[cfg(test)] @@ -144,7 +124,7 @@ mod tests { } #[test] - fn query_entities() { + fn world_view_entities() { let mut world = World::new(); world.spawn((Vec2 { x: 10.0,