Simple dynamic views
This commit is contained in:
parent
a1ca2789ce
commit
a68b0a7fb4
|
@ -280,6 +280,11 @@ impl Archetype {
|
||||||
self.columns.iter().all(|c| types.contains(&c.info.type_id))
|
self.columns.iter().all(|c| types.contains(&c.info.type_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a boolean indicating whether this archetype has a column for `comp_type`
|
||||||
|
pub(crate) fn has_column(&self, comp_type: DynTypeId) -> bool {
|
||||||
|
self.columns.iter().any(|c| comp_type == c.info.type_id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a boolean indicating whether this archetype is empty or not.
|
/// Returns a boolean indicating whether this archetype is empty or not.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.entities.is_empty()
|
self.entities.is_empty()
|
||||||
|
|
|
@ -61,10 +61,10 @@ impl DynTypeId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct ComponentInfo {
|
pub struct ComponentInfo {
|
||||||
pub type_id: DynTypeId,
|
pub type_id: DynTypeId,
|
||||||
pub name: String,
|
//pub name: String,
|
||||||
pub layout: MemoryLayout,
|
pub layout: MemoryLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ impl ComponentInfo {
|
||||||
pub fn new<T: 'static>() -> Self {
|
pub fn new<T: 'static>() -> Self {
|
||||||
Self {
|
Self {
|
||||||
type_id: DynTypeId::from(TypeId::of::<T>()),
|
type_id: DynTypeId::from(TypeId::of::<T>()),
|
||||||
name: type_name::<T>().to_string(),
|
//name: type_name::<T>().to_string(),
|
||||||
layout: MemoryLayout::from(Layout::new::<T>()),
|
layout: MemoryLayout::from(Layout::new::<T>()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ impl ComponentInfo {
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
type_id: type_id.into(),
|
type_id: type_id.into(),
|
||||||
name: name.to_string(),
|
//name: name.to_string(),
|
||||||
layout,
|
layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
use std::ptr::NonNull;
|
|
||||||
|
|
||||||
use crate::{Fetch, world::World, Query};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash)]
|
|
||||||
enum TypeId {
|
|
||||||
Rust(std::any::TypeId),
|
|
||||||
Unknown(u128),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash)]
|
|
||||||
pub struct DynamicTypeInfo {
|
|
||||||
id: TypeId,
|
|
||||||
size: usize,
|
|
||||||
alignment: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Data that is unknown to rust
|
|
||||||
pub struct DynamicType {
|
|
||||||
info: DynamicTypeInfo,
|
|
||||||
ptr: NonNull<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FetchDynamicType {
|
|
||||||
info: Option<DynamicTypeInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Fetch<'a> for FetchDynamicType {
|
|
||||||
type Item = DynamicType;
|
|
||||||
|
|
||||||
fn dangling() -> Self {
|
|
||||||
Self {
|
|
||||||
info: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_item(&mut self, entity: crate::ArchetypeEntityId) -> Self::Item {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct QueryDynamicType {
|
|
||||||
info: DynamicTypeInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Query for QueryDynamicType {
|
|
||||||
type Item<'a> = DynamicType;
|
|
||||||
|
|
||||||
type Fetch<'a> = FetchDynamicType;
|
|
||||||
|
|
||||||
const ALWAYS_FETCHES: bool = false;
|
|
||||||
|
|
||||||
fn new() -> Self {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_visit_archetype(&self, _archetype: &crate::archetype::Archetype) -> bool {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn fetch<'a>(&self, world: &'a World, _arch_id: crate::archetype::ArchetypeId, _archetype: &'a crate::archetype::Archetype) -> Self::Fetch<'a> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
use std::{ptr::NonNull, cell::Ref};
|
||||||
|
|
||||||
|
use crate::{Fetch, world::World, Query, ComponentColumn, ComponentInfo};
|
||||||
|
|
||||||
|
pub mod view;
|
||||||
|
pub use view::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash)]
|
||||||
|
enum TypeId {
|
||||||
|
Rust(std::any::TypeId),
|
||||||
|
Unknown(u128),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data that rust does not know the type of
|
||||||
|
pub struct DynamicType {
|
||||||
|
pub info: ComponentInfo,
|
||||||
|
pub ptr: NonNull<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FetchDynamicType<'a> {
|
||||||
|
col: &'a ComponentColumn,
|
||||||
|
info: ComponentInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Fetch<'a> for FetchDynamicType<'a> {
|
||||||
|
type Item = DynamicType;
|
||||||
|
|
||||||
|
fn dangling() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
DynamicType {
|
||||||
|
info: self.info,
|
||||||
|
ptr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DynamicQuery: Query {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A query for receiving a dynamic type.
|
||||||
|
///
|
||||||
|
/// There are no Ref or RefMut variants since this fetches the pointer to the component.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct QueryDynamicType {
|
||||||
|
info: ComponentInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QueryDynamicType {
|
||||||
|
pub fn from_info(info: ComponentInfo) -> Self {
|
||||||
|
Self {
|
||||||
|
info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Query for QueryDynamicType {
|
||||||
|
type Item<'a> = DynamicType;
|
||||||
|
|
||||||
|
type Fetch<'a> = FetchDynamicType<'a>;
|
||||||
|
|
||||||
|
const ALWAYS_FETCHES: bool = false;
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
panic!("QueryDynamicType does not implement QueryDefault, this should not have been called")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
|
||||||
|
archetype.has_column(self.info.type_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.info.type_id)
|
||||||
|
.expect("You ignored 'can_visit_archetype'!");
|
||||||
|
|
||||||
|
FetchDynamicType {
|
||||||
|
col,
|
||||||
|
info: self.info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use crate::{world::World, Archetype, Query, ArchetypeEntityId, Fetch, ArchetypeId};
|
||||||
|
|
||||||
|
use super::{DynamicQuery, QueryDynamicType, FetchDynamicType};
|
||||||
|
|
||||||
|
pub struct DynamicView<'a> {
|
||||||
|
world: &'a World,
|
||||||
|
queries: Vec<QueryDynamicType>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DynamicView<'a> {
|
||||||
|
pub fn new(world: &'a World) -> Self {
|
||||||
|
Self {
|
||||||
|
world,
|
||||||
|
queries: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, dyn_query: QueryDynamicType) {
|
||||||
|
self.queries.push(dyn_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for DynamicView<'a> {
|
||||||
|
type Item = Vec<<QueryDynamicType as Query>::Item<'a>>;
|
||||||
|
|
||||||
|
type IntoIter = DynamicViewIter<'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
let archetypes = self.world.archetypes.values().collect();
|
||||||
|
|
||||||
|
DynamicViewIter {
|
||||||
|
world: self.world,
|
||||||
|
queries: self.queries,
|
||||||
|
fetchers: Vec::new(),
|
||||||
|
archetypes: archetypes,
|
||||||
|
next_archetype: 0,
|
||||||
|
component_indices: 0..0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DynamicViewIter<'a> {
|
||||||
|
world: &'a World,
|
||||||
|
queries: Vec<QueryDynamicType>,
|
||||||
|
fetchers: Vec<FetchDynamicType<'a>>,
|
||||||
|
archetypes: Vec<&'a Archetype>,
|
||||||
|
next_archetype: usize,
|
||||||
|
component_indices: Range<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for DynamicViewIter<'a> {
|
||||||
|
type Item = Vec<<QueryDynamicType as Query>::Item<'a>>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
loop {
|
||||||
|
if let Some(entity_index) = self.component_indices.next() {
|
||||||
|
let mut fetch_res = vec![];
|
||||||
|
|
||||||
|
//let fetcher = self.fetcher.as_mut().unwrap();
|
||||||
|
for fetcher in self.fetchers.iter_mut() {
|
||||||
|
let entity_index = ArchetypeEntityId(entity_index);
|
||||||
|
if !fetcher.can_visit_item(entity_index) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
let i = unsafe { fetcher.get_item(entity_index) };
|
||||||
|
fetch_res.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fetch_res.len() != self.fetchers.len() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(fetch_res);
|
||||||
|
} 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.queries.iter().any(|q| !q.can_visit_archetype(arch)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fetchers = self.queries.iter()
|
||||||
|
.map(|q| unsafe { q.fetch(self.world, ArchetypeId(arch_id as u64), arch) } )
|
||||||
|
.collect();
|
||||||
|
self.component_indices = 0..arch.entities.len() as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{alloc::Layout, ptr::NonNull};
|
||||||
|
|
||||||
|
use crate::{world::World, MemoryLayout, ComponentInfo, DynTypeId, DynamicBundle, dynamic::{DynamicQuery, QueryDynamicType}};
|
||||||
|
|
||||||
|
use super::DynamicView;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_dynamic_view() {
|
||||||
|
let comp_layout = MemoryLayout::from(Layout::new::<u32>());
|
||||||
|
let comp_info = ComponentInfo::new_unknown(DynTypeId::Unknown(100), "u32", comp_layout);
|
||||||
|
|
||||||
|
let mut dynamic_bundle = DynamicBundle::default();
|
||||||
|
let comp = 50u32;
|
||||||
|
let ptr = NonNull::from(&comp).cast::<u8>();
|
||||||
|
dynamic_bundle.push_unknown(ptr, comp_info.clone());
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.spawn(dynamic_bundle);
|
||||||
|
|
||||||
|
let query = QueryDynamicType::from_info(comp_info);
|
||||||
|
let mut view = DynamicView::new(&world);
|
||||||
|
view.push(query);
|
||||||
|
|
||||||
|
for view_row in view.into_iter() {
|
||||||
|
assert_eq!(view_row.len(), 1);
|
||||||
|
|
||||||
|
let mut row_iter = view_row.iter();
|
||||||
|
|
||||||
|
let dynamic_type = row_iter.next().unwrap();
|
||||||
|
|
||||||
|
let component_data = unsafe { dynamic_type.ptr.cast::<u32>().as_ref() };
|
||||||
|
assert_eq!(*component_data, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,8 +20,6 @@ pub mod resource;
|
||||||
pub use resource::*;
|
pub use resource::*;
|
||||||
|
|
||||||
pub mod dynamic;
|
pub mod dynamic;
|
||||||
#[allow(unused_imports)]
|
|
||||||
pub use dynamic::*;
|
|
||||||
|
|
||||||
/// A [`Fetch`]er implementation gets data out of an archetype.
|
/// A [`Fetch`]er implementation gets data out of an archetype.
|
||||||
pub trait Fetch<'a> {
|
pub trait Fetch<'a> {
|
||||||
|
|
Loading…
Reference in New Issue