Simple dynamic views

This commit is contained in:
SeanOMik 2023-12-09 14:39:01 -05:00
parent a1ca2789ce
commit a68b0a7fb4
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
6 changed files with 236 additions and 71 deletions

View File

@ -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()

View File

@ -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,
}
}

View File

@ -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!()
}
}

View File

@ -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,
}
}
}

View File

@ -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);
}
}
}

View File

@ -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> {