Create queries and views

This commit is contained in:
SeanOMik 2023-11-25 18:43:11 -05:00
parent f62f21e69f
commit 92e284e625
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
10 changed files with 711 additions and 114 deletions

View File

@ -31,7 +31,9 @@
"test", "test",
"--no-run", "--no-run",
"--bin=lyra-ecs", "--bin=lyra-ecs",
"--package=lyra-ecs" "--package=lyra-ecs",
"--",
"--nocapture"
], ],
"filter": { "filter": {
"name": "lyra-ecs", "name": "lyra-ecs",

View File

@ -1,55 +1,96 @@
use std::any::{Any, TypeId}; use std::{any::{Any, TypeId, type_name}, ptr::{NonNull, self}, alloc::{self, Layout, alloc}, mem::size_of};
use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component::Component}; use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component::Component, component_info::ComponentInfo};
pub trait ComponentColumn: Any { pub struct ComponentColumn {
fn as_any(&self) -> &dyn Any; pub data: NonNull<u8>,
fn as_any_mut(&mut self) -> &mut dyn Any; pub capacity: usize,
fn new_empty_column(&self) -> Box<dyn ComponentColumn>; pub info: ComponentInfo,
fn is_same_type(&self, column: &dyn ComponentColumn) -> bool; pub entry_size: usize,
fn len(&self) -> usize;
fn append(&mut self, column: &mut dyn ComponentColumn);
fn component_type_id(&self) -> TypeId;
// used for debugging
fn component_type_name(&self) -> String;
} }
impl<T: Component> ComponentColumn for Vec<T> { impl ComponentColumn {
fn as_any(&self) -> &dyn Any { /// Creates an invalid component column. Do not attempt to use it.
self pub unsafe fn dangling() -> Self {
ComponentColumn {
data: NonNull::dangling(),
capacity: 0,
info: ComponentInfo::new::<()>(),
entry_size: 0,
}
} }
fn as_any_mut(&mut self) -> &mut dyn Any { pub unsafe fn alloc(component_layout: Layout, capacity: usize) -> NonNull<u8> {
self let new_layout = Layout::from_size_align(
component_layout.size().checked_mul(capacity).unwrap(),
component_layout.align()
).unwrap();
if let Some(data) = NonNull::new(alloc(new_layout)) {
data
} else {
alloc::handle_alloc_error(new_layout)
}
} }
fn new_empty_column(&self) -> Box<dyn ComponentColumn> { pub unsafe fn new(info: ComponentInfo, capacity: usize) -> Self {
Box::new(Vec::<T>::new()) let data = ComponentColumn::alloc(info.layout, capacity);
let size = info.layout.size();
Self {
data,
capacity,
info,
entry_size: size,
}
} }
fn is_same_type(&self, column: &dyn ComponentColumn) -> bool { /// Creates an empty column of the same type
column.as_any().downcast_ref::<Self>().is_some() 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,
}
} }
fn len(&self) -> usize { /// Set a component from pointer at an entity index.
Vec::len(self) ///
/// # Safety
///
/// This column must have space to fit the component, if it does not have room it will panic.
pub unsafe fn set_at(&mut self, entity_index: usize, comp_src: NonNull<u8>) {
assert!(entity_index < self.capacity);
let dest = NonNull::new_unchecked(self.data.as_ptr().add(entity_index * self.entry_size));
ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), self.entry_size);
} }
fn append(&mut self, column: &mut dyn ComponentColumn) { /// Get a component at an entities index.
let column: &mut Self = column.as_any_mut().downcast_mut() ///
.expect("Attempt at appending an different column type!"); /// # Safety
///
self.append(column); /// This column MUST have the entity. If it does not, it WILL NOT panic and will cause UB.
pub unsafe fn get<T>(&self, entity_index: usize) -> &T {
let p = self.data.as_ptr()
.cast::<T>()
.add(entity_index * self.entry_size);
&*p
} }
fn component_type_id(&self) -> TypeId { /// Get a component at an entities index.
self.first().unwrap().type_id() ///
} /// # Safety
///
fn component_type_name(&self) -> String { /// This column must have the entity.
//self.first().unwrap().type_id() pub unsafe fn get_mut<T>(&mut self, entity_index: usize) -> &mut T {
std::any::type_name::<T>().to_string() let p = self.data.as_ptr()
.cast::<T>()
.add(entity_index * self.entry_size);
&mut *p
} }
} }
@ -68,24 +109,25 @@ impl ArchetypeId {
pub struct Archetype { pub struct Archetype {
pub(crate) id: ArchetypeId, pub(crate) id: ArchetypeId,
entities: Vec<Entity>, pub(crate) entities: Vec<Entity>,
pub(crate) columns: Vec<Box<dyn ComponentColumn>>, pub(crate) columns: Vec<ComponentColumn>,
} }
/// The default capacity of the columns
const DEFAULT_CAPACITY: usize = 32;
impl Archetype { impl Archetype {
/// Create a new archetype from another archetype and add a column /// Create a new archetype from another archetype and add a column
pub fn new_archetype_add<T: Component>(new_id: ArchetypeId, archetype: &Archetype) -> Archetype { pub fn new_archetype_add<T: Component>(new_id: ArchetypeId, archetype: &Archetype) -> Archetype {
let mut columns: Vec<_> = archetype let mut columns: Vec<_> = archetype
.columns .columns
.iter() .iter()
.map(|c| c.new_empty_column()) .map(|c| unsafe { c.create_empty(DEFAULT_CAPACITY) })
.collect(); .collect();
assert!(columns // Make sure a column for the new component does not exist
.iter() assert_ne!(true, columns.iter().any(|c| c.info.type_id == TypeId::of::<T>()) );
.find(|column| column.as_any().is::<Vec<T>>()) columns.push(unsafe { ComponentColumn::new(ComponentInfo::new::<T>(), DEFAULT_CAPACITY) });
.is_none());
columns.push(Box::new(Vec::<T>::new()));
Archetype { Archetype {
id: new_id, id: new_id,
@ -99,12 +141,12 @@ impl Archetype {
let mut columns: Vec<_> = archetype let mut columns: Vec<_> = archetype
.columns .columns
.iter() .iter()
.map(|c| c.new_empty_column()) .map(|c| unsafe { c.create_empty(DEFAULT_CAPACITY) })
.collect(); .collect();
let idx = columns let idx = columns
.iter() .iter()
.position(|column| column.as_any().is::<Vec<T>>()) .position(|column| column.info.type_id == TypeId::of::<T>())
.unwrap(); .unwrap();
columns.remove(idx); columns.remove(idx);
@ -115,7 +157,11 @@ impl Archetype {
} }
} }
pub fn from_columns(new_id: ArchetypeId, columns: Vec<Box<dyn ComponentColumn>>) -> Archetype { pub fn from_bundle_info(new_id: ArchetypeId, bundle_info: Vec<ComponentInfo>) -> Archetype {
let columns = bundle_info.into_iter().map(|i| {
unsafe { ComponentColumn::new(i, DEFAULT_CAPACITY) }
}).collect();
Archetype { Archetype {
id: new_id, id: new_id,
entities: Vec::new(), entities: Vec::new(),
@ -124,64 +170,42 @@ impl Archetype {
} }
pub fn get_component_mut<T: Component>(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> { pub fn get_component_mut<T: Component>(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> {
for col in self.columns.iter_mut() { todo!()
if col.as_any().is::<Vec<T>>() {
let components: &mut Vec<T> = col.as_any_mut().downcast_mut().unwrap();
return components.get_mut(entity.0 as usize);
}
}
None
} }
pub fn get_component<T: Component>(&self, entity: ArchetypeEntityId) -> Option<&T> { pub fn get_entity_component<T: Component>(&self, entity: ArchetypeEntityId) -> Option<&T> {
for col in self.columns.iter() { let type_id = TypeId::of::<T>();
if col.as_ref().as_any().is::<Vec<T>>() {
let components: &Vec<T> = col.as_any().downcast_ref().unwrap(); self.columns.iter().find(|c| c.info.type_id == type_id)
.map(|c| unsafe { c.get(entity.0 as usize) })
return components.get(entity.0 as usize);
}
}
None
} }
pub fn get_component_column<T: Component>(&self) -> Option<&Vec<T>> { pub fn get_component_column<T: Component>(&self) -> Option<&Vec<T>> {
let col = self.columns.iter().find(|c| c.as_any().is::<Vec<T>>())?; todo!()
col.as_any().downcast_ref()
} }
pub(crate) fn add_entity(&mut self, components: Vec<Box<dyn ComponentColumn>>) -> ArchetypeEntityId { /// Add an entity and its component bundle to the Archetype
let mut created_entity: Option<ArchetypeEntityId> = None; ///
/// # Safety:
///
/// Archetype must contain all of the components
pub(crate) fn add_entity<B>(&mut self, entity: Entity, bundle: B) -> ArchetypeEntityId
where
B: Bundle
{
let entity_index = self.entities.len();
self.entities.push(entity);
for mut component in components.into_iter() { bundle.takefn(|data, type_id, size| {
for col in self.columns.iter_mut() { let col = self.columns.iter_mut().find(|c| c.info.type_id == type_id).unwrap();
if col.is_same_type(component.as_ref()) { unsafe { col.set_at(entity_index, data); }
match created_entity { });
Some(e) => {
assert!(e.0 == col.len() as u64); ArchetypeEntityId(entity_index as u64)
},
None => {
created_entity = Some(ArchetypeEntityId(col.len() as u64));
}
}
col.append(component.as_mut());
}
}
}
created_entity.expect("Failure to create entity!")
} }
/// 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<TypeId>) -> bool { pub(crate) fn is_archetype_for(&self, types: Vec<TypeId>) -> bool {
let types_iter = types.into_iter(); self.columns.iter().all(|c| types.contains(&c.info.type_id))
self.columns
.iter()
.map(|c| c.component_type_id())
.eq(types_iter)
} }
} }

View File

@ -1,6 +1,6 @@
use std::any::{TypeId, Any}; use std::{any::{TypeId, Any}, cell::Ref, ptr::NonNull, mem::size_of};
use crate::{archetype::ComponentColumn, component::Component}; use crate::{archetype::{ComponentColumn, Archetype}, component::Component, component_info::ComponentInfo};
pub trait Bundle { pub trait Bundle {
// Get a list of type ids that this bundle is storing // Get a list of type ids that this bundle is storing
@ -8,10 +8,35 @@ pub trait Bundle {
/// Take components into a list. /// Take components into a list.
/// The return value could be seen as a list of a list of components, but that inner 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. /// only contains a single value to make it easier to add it to an archetype.
fn take_components(self) -> Vec<Box<dyn ComponentColumn>>; //fn take_components(self) -> Vec<Box<dyn ComponentColumn>>;
//fn from_component_columns(columns: Vec<&Box<dyn ComponentColumn>>) -> Self;
//fn from_archetype(archetype: &Archetype) -> Self;
fn info(&self) -> Vec<ComponentInfo>;
/// 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<u8>, TypeId, usize));
} }
macro_rules! impl_bundle_tuple { impl<C1: Component> Bundle for (C1,) {
fn types(&self) -> Vec<TypeId> {
vec![self.0.type_id()]
}
fn info(&self) -> Vec<ComponentInfo> {
vec![ComponentInfo::new::<C1>()]
}
fn takefn(self, mut cb: impl FnMut(NonNull<u8>, TypeId, usize)) {
let (c1, ) = self;
cb(NonNull::from(&c1).cast(), TypeId::of::<C1>(), size_of::<C1>());
}
}
/* macro_rules! impl_bundle_tuple {
( $(($name: ident, $index: tt))+ ) => ( ( $(($name: ident, $index: tt))+ ) => (
impl<$($name: Component),+> Bundle for ($($name,)+) { impl<$($name: Component),+> Bundle for ($($name,)+) {
fn types(&self) -> Vec<TypeId> { fn types(&self) -> Vec<TypeId> {
@ -21,13 +46,23 @@ macro_rules! impl_bundle_tuple {
fn take_components(self) -> Vec<Box<dyn ComponentColumn>> { fn take_components(self) -> Vec<Box<dyn ComponentColumn>> {
vec![$(Box::new(vec![self.$index])),+] vec![$(Box::new(vec![self.$index])),+]
} }
fn from_component_columns(columns: Vec<&Box<dyn ComponentColumn>>) -> Self {
let mut chains = Vec::new();
for col in columns.iter() {
col.
}
todo!()
}
} }
); );
} } */
// hopefully 16 components in a bundle is enough // hopefully 16 components in a bundle is enough
impl_bundle_tuple! { (C1, 0) } //impl_bundle_tuple! { (C1, 0) }
impl_bundle_tuple! { (C1, 0) (C2, 1) } /* 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) }
impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) } 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) }
@ -41,3 +76,4 @@ impl_bundle_tuple! { (C1, 0) (C2, 1) (C3, 2) (C4, 3) (C5, 4) (C6, 5) (C7, 6) (C8
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) }
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) }
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) } 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) }
*/

View File

@ -0,0 +1,18 @@
use std::{any::{TypeId, type_name}, alloc::Layout};
#[derive(Clone, Debug)]
pub struct ComponentInfo {
pub type_id: TypeId,
pub name: String,
pub layout: Layout,
}
impl ComponentInfo {
pub fn new<T: 'static>() -> Self {
Self {
type_id: TypeId::of::<T>(),
name: type_name::<T>().to_string(),
layout: Layout::new::<T>(),
}
}
}

View File

@ -1,9 +1,12 @@
//#![feature(cell_leak)]
use crate::world::World; use crate::world::World;
mod archetype; mod archetype;
mod world; mod world;
mod bundle; mod bundle;
mod component; mod component;
mod query;
mod component_info;
#[derive(Debug)] #[derive(Debug)]
pub struct Position2d(i32, i32); pub struct Position2d(i32, i32);
@ -25,7 +28,14 @@ fn main() {
println!("\nstart of querying!\n"); println!("\nstart of querying!\n");
for pos in world.query::<Position2d>() { /* for pos in world.query::<Position2d>() {
println!("Queried Position2d: {:?}", pos);
} */
let mut q = world.query_better();
q.with_component::<Position2d>();
for pos in q.run::<Position2d>() {
println!("Queried Position2d: {:?}", pos); println!("Queried Position2d: {:?}", pos);
} }
} }

View File

@ -0,0 +1,204 @@
use std::{marker::PhantomData, any::TypeId, ptr::NonNull};
use super::{Fetch, Query};
pub struct FetchBorrow<'a, T> {
ptr: NonNull<u8>,
size: usize,
_phantom: PhantomData<&'a T>
}
impl<'a, T> Fetch<'a> for FetchBorrow<'a, T>
where
T: 'a,
{
type Item = &'a T;
fn create_empty() -> Self {
FetchBorrow {
ptr: NonNull::dangling(),
size: 0,
_phantom: PhantomData::default()
}
}
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
let ptr = NonNull::new_unchecked(self.ptr.as_ptr()
.add(entity.0 as usize * self.size))
.cast();
&*ptr.as_ptr()
}
}
pub struct QueryBorrow<T> {
type_id: TypeId,
_phantom: PhantomData<T>
}
impl<T> Query for QueryBorrow<T>
where
T: 'static
{
type Item<'a> = &'a T;
type Fetch<'a> = FetchBorrow<'a, T>;
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
}
unsafe fn fetch<'a>(&self, _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)
.expect("You ignored 'can_visit_archetype'!");
let col_data = col.data;
FetchBorrow {
ptr: NonNull::new_unchecked(col_data.as_ptr()),
size: col.info.layout.size(),
_phantom: PhantomData,
}
}
}
pub struct FetchBorrowMut<'a, T> {
ptr: NonNull<u8>,
size: usize,
_phantom: PhantomData<&'a T>
}
impl<'a, T> Fetch<'a> for FetchBorrowMut<'a, T>
where
T: 'a,
{
type Item = &'a mut T;
fn create_empty() -> Self {
FetchBorrowMut {
ptr: NonNull::dangling(),
size: 0,
_phantom: PhantomData::default()
}
}
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
let ptr = NonNull::new_unchecked(self.ptr.as_ptr()
.add(entity.0 as usize * self.size))
.cast();
&mut *ptr.as_ptr()
}
}
pub struct QueryBorrowMut<T> {
type_id: TypeId,
_phantom: PhantomData<T>
}
impl<T> Query for QueryBorrowMut<T>
where
T: 'static
{
type Item<'a> = &'a mut T;
type Fetch<'a> = FetchBorrowMut<'a, T>;
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
archetype.columns.iter().any(|c| c.info.type_id == self.type_id)
}
unsafe fn fetch<'a>(&self, _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)
.expect("You ignored 'can_visit_archetype'!");
let col_data = col.data;
FetchBorrowMut {
ptr: NonNull::new_unchecked(col_data.as_ptr()),
size: col.info.layout.size(),
_phantom: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use std::any::TypeId;
use crate::{world::World, archetype::Archetype, query::View};
use super::{QueryBorrow, QueryBorrowMut};
#[derive(Clone, Copy, Debug, Default)]
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
pub fn new(x: f32, y: f32) -> Self {
Self {
x,
y,
}
}
}
/// Creates a world with two entities, one at Vec(10, 50) and
/// the other at Vec2(25, 30).
fn prepare_world() -> World {
let mut world = World::new();
world.spawn((Vec2::new(10.0, 50.0),));
world.spawn((Vec2::new(25.0, 30.0),));
world
}
#[test]
fn borrow_query() {
let world = prepare_world();
let borrow = QueryBorrow::<Vec2> {
type_id: TypeId::of::<Vec2>(),
_phantom: std::marker::PhantomData,
};
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
let v = View::new(borrow, archetypes);
for e in v.into_iter() {
println!("Found entity at {:?}", e);
}
}
#[test]
fn borrow_mut_query() {
let world = prepare_world();
let borrow = QueryBorrowMut::<Vec2> {
type_id: TypeId::of::<Vec2>(),
_phantom: std::marker::PhantomData,
};
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
let v = View::new(borrow, archetypes);
let mut orig = vec![];
for v in v.into_iter() {
orig.push(v.clone());
v.x += 10.0;
v.y += 10.0;
}
// Now make sure the changes were actually made
let borrow = QueryBorrow::<Vec2> {
type_id: TypeId::of::<Vec2>(),
_phantom: std::marker::PhantomData,
};
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
let v = View::new(borrow, archetypes);
for (new, orig) in v.into_iter().zip(orig.iter()) {
assert!(new.x - orig.x == 10.0);
assert!(new.y - orig.y == 10.0);
}
println!("They were modified!");
}
}

View File

@ -0,0 +1,40 @@
use crate::{world::Entity, archetype::{Archetype, ArchetypeId}};
use super::{Fetch, Query};
pub struct EntitiesFetch<'a> {
entities: &'a [Entity],
}
impl<'a> Fetch<'a> for EntitiesFetch<'a> {
type Item = Entity;
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
let e = *self.entities.get_unchecked(entity.0 as usize);
e
}
fn create_empty() -> Self {
Self {
entities: &[],
}
}
}
pub struct Entities;
impl Query for Entities {
type Item<'a> = Entity;
type Fetch<'a> = EntitiesFetch<'a>;
fn can_visit_archetype(&self, archetype: &Archetype) -> bool {
true
}
unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a> {
EntitiesFetch {
entities: &archetype.entities,
}
}
}

152
lyra-ecs/src/query/mod.rs Normal file
View File

@ -0,0 +1,152 @@
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}};
pub mod view;
pub use view::*;
pub mod entities;
pub use entities::*;
pub mod borrow;
pub use borrow::*;
pub struct QuerySimple<'a> {
//entities: Iter<Entity
archetypes: Vec<&'a Archetype>,
type_ids: Vec<TypeId>,
}
impl<'a> QuerySimple<'a> {
pub fn new(archetypes: Vec<&'a Archetype>) -> Self {
Self {
archetypes,
type_ids: Vec::new(),
}
}
pub fn with_component<T: Any>(&mut self) {
let type_id = TypeId::of::<T>();
self.type_ids.push(type_id);
}
pub fn run<C1: Component>(&self) -> impl Iterator<Item = &C1>
{
//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::<C1>()
.expect("Failure to downcast component column"))
.collect(); */
let entities = self.archetypes
.iter()
.filter_map(|a| a.get_component_column::<C1>())
.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;
}
}
/// A [`Fetch`]er implementation gets data out of an archetype.
pub trait Fetch<'a> {
/// The type that this Fetch yields
type Item: 'a;
/// Returns true if the entity should be visited or skipped.
fn can_visit_item(&mut self, entity: ArchetypeEntityId) -> bool {
let _ = entity; // ignore compiler warning
true
}
/// Creates an empty Fetch. DO NOT try to `get_item` on this
fn create_empty() -> Self;
unsafe fn get_item(&mut self, entity: ArchetypeEntityId) -> Self::Item;
}
pub trait Query {
/// The item that this query yields
type Item<'a>: 'a;
/// The fetcher used for this query
type Fetch<'a>: Fetch<'a, Item = Self::Item<'a>>;
/// Returns true if the archetype should be visited or skipped.
fn can_visit_archetype(&self, archetype: &Archetype) -> bool;
unsafe fn fetch<'a>(&self, arch_id: ArchetypeId, archetype: &'a Archetype) -> Self::Fetch<'a>;
}
#[cfg(test)]
mod tests {
use crate::{world::World, archetype::Archetype};
use super::{View, Entities};
#[derive(Clone, Copy, Debug, Default)]
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
pub fn new(x: f32, y: f32) -> Self {
Self {
x,
y,
}
}
}
#[test]
fn simple_view() {
let mut world = World::new();
world.spawn((Vec2::new(10.0, 50.0),));
world.spawn((Vec2::new(25.0, 30.0),));
let entities = Entities {};
let archetypes: Vec<&Archetype> = world.archetypes.values().collect();
let v = View::new(entities, archetypes);
for e in v.into_iter() {
println!("Got entity! {:?}", e);
}
}
}

View File

@ -0,0 +1,89 @@
use std::ops::Range;
use crate::{archetype::{Archetype, ArchetypeId}, world::ArchetypeEntityId};
use super::{Query, Fetch};
pub struct View<'a, Q: Query> {
query: Q,
archetypes: Vec<&'a Archetype>,
}
impl<'a, Q> View<'a, Q>
where
Q: Query,
{
pub fn new(query: Q, archetypes: Vec<&'a Archetype>) -> Self {
Self {
query,
archetypes,
}
}
}
impl<'a, Q> IntoIterator for View<'a, Q>
where
Q: Query,
{
type Item = Q::Item<'a>;
type IntoIter = ViewIter<'a, Q>;
fn into_iter(self) -> Self::IntoIter {
ViewIter {
query: self.query,
fetcher: Q::Fetch::create_empty(),
archetypes: self.archetypes,
next_archetype: 0,
component_indices: 0..0,
}
}
}
pub struct ViewIter<'a, Q: Query> {
query: Q,
fetcher: Q::Fetch<'a>,
archetypes: Vec<&'a Archetype>,
next_archetype: usize,
component_indices: Range<u64>,
}
impl<'a, Q> Iterator for ViewIter<'a, Q>
where
Q: Query,
{
type Item = Q::Item<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(entity_index) = self.component_indices.next() {
let entity_index = ArchetypeEntityId(entity_index);
if !self.fetcher.can_visit_item(entity_index) {
continue;
} else {
let i = unsafe { self.fetcher.get_item(entity_index) };
return Some(i);
}
} else {
if self.next_archetype >= self.archetypes.len() {
return None; // ran out of archetypes to go through
}
let arch_id = self.next_archetype;
self.next_archetype += 1;
let arch = unsafe { self.archetypes.get_unchecked(arch_id) };
if arch.entities.len() == 0 {
continue;
}
if !self.query.can_visit_archetype(arch) {
continue;
}
self.fetcher = unsafe { self.query.fetch(ArchetypeId(arch_id as u64), arch) };
self.component_indices = 0..arch.entities.len() as u64;
}
}
}
}

View File

@ -1,7 +1,7 @@
use std::{collections::{HashMap, VecDeque}, any::{Any, TypeId}}; use std::{collections::{HashMap, VecDeque}, any::{Any, TypeId}};
use std::slice::Iter; use std::slice::Iter;
use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component}; use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component, query::QuerySimple};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct EntityId(pub u64); pub struct EntityId(pub u64);
@ -11,18 +11,19 @@ pub struct EntityId(pub u64);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ArchetypeEntityId(pub u64); pub struct ArchetypeEntityId(pub u64);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Entity { pub struct Entity {
id: EntityId, id: EntityId,
generation: u64, generation: u64,
} }
struct Record { pub struct Record {
id: ArchetypeId, id: ArchetypeId,
index: ArchetypeEntityId, index: ArchetypeEntityId,
} }
pub struct World { pub struct World {
archetypes: HashMap<ArchetypeId, Archetype>, pub(crate) archetypes: HashMap<ArchetypeId, Archetype>,
next_archetype_id: ArchetypeId, next_archetype_id: ArchetypeId,
entity_index: HashMap<EntityId, Record>, entity_index: HashMap<EntityId, Record>,
dead_entities: VecDeque<Entity>, dead_entities: VecDeque<Entity>,
@ -68,9 +69,7 @@ impl World {
.find(|a| a.is_archetype_for(bundle_types.clone())); .find(|a| a.is_archetype_for(bundle_types.clone()));
if let Some(archetype) = archetype { if let Some(archetype) = archetype {
// take components from the bundle and add it to the archetype let arche_idx = archetype.add_entity(new_entity, bundle);
let columns = bundle.take_components();
let arche_idx = archetype.add_entity(columns);
// Create entity record and store it // Create entity record and store it
let record = Record { let record = Record {
@ -82,11 +81,10 @@ impl World {
} }
// create a new archetype if one isn't found // create a new archetype if one isn't found
else { else {
let columns = bundle.take_components();
// create archetype // create archetype
let new_arch_id = self.next_archetype_id.increment(); let new_arch_id = self.next_archetype_id.increment();
let archetype = Archetype::from_columns(new_arch_id, columns); let mut archetype = Archetype::from_bundle_info(new_arch_id, bundle.info());
let entity_arch_id = archetype.add_entity(new_entity, bundle);
// store archetype // store archetype
self.archetypes.insert(new_arch_id, archetype); self.archetypes.insert(new_arch_id, archetype);
@ -95,7 +93,7 @@ impl World {
let record = Record { let record = Record {
id: new_arch_id, id: new_arch_id,
// this is the first entity in the archetype // this is the first entity in the archetype
index: ArchetypeEntityId(0), index: entity_arch_id,
}; };
self.entity_index.insert(new_entity.id, record); self.entity_index.insert(new_entity.id, record);
@ -108,7 +106,7 @@ impl World {
let record = self.entity_index.get(&entity.id)?; let record = self.entity_index.get(&entity.id)?;
let archetype = self.archetypes.get(&record.id)?; let archetype = self.archetypes.get(&record.id)?;
archetype.get_component(record.index) archetype.get_entity_component(record.index)
} }
pub fn query<T: Component>(&self) -> impl Iterator<Item = &T> { pub fn query<T: Component>(&self) -> impl Iterator<Item = &T> {
@ -118,10 +116,34 @@ impl World {
.flatten() .flatten()
} }
pub fn query_better(&self) -> QuerySimple {
let archetypes = self.archetypes.values().collect();
QuerySimple::new(archetypes)
}
/* pub fn query_m<B: Bundle>(&self) -> impl Iterator<Item = &T> { /* pub fn query_m<B: Bundle>(&self) -> impl Iterator<Item = &T> {
self.archetypes self.archetypes
.iter() .iter()
.filter_map(|(_, a)| a.get_component_column::<T>()) .filter_map(|(_, a)| a.get_component_column::<T>())
.flatten() .flatten()
} */ } */
}
#[cfg(test)]
mod tests {
use super::World;
struct Vec2 {
x: f32,
y: f32,
}
#[test]
fn spawning_entity() {
let mut world = World::new();
let _e = world.spawn((Vec2 {
x: 10.0,
y: 15.0,
}, ));
}
} }