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))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
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 type_id: DynTypeId,
|
||||
pub name: String,
|
||||
//pub name: String,
|
||||
pub layout: MemoryLayout,
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ impl ComponentInfo {
|
|||
pub fn new<T: 'static>() -> Self {
|
||||
Self {
|
||||
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>()),
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ impl ComponentInfo {
|
|||
{
|
||||
Self {
|
||||
type_id: type_id.into(),
|
||||
name: name.to_string(),
|
||||
//name: name.to_string(),
|
||||
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 mod dynamic;
|
||||
#[allow(unused_imports)]
|
||||
pub use dynamic::*;
|
||||
|
||||
/// A [`Fetch`]er implementation gets data out of an archetype.
|
||||
pub trait Fetch<'a> {
|
||||
|
|
Loading…
Reference in New Issue