ecs: create a DynamicViewState that can be used to create a dynamic view without dealing with lifetimes
ci/woodpecker/push/debug Pipeline failed
Details
ci/woodpecker/push/debug Pipeline failed
Details
This commit is contained in:
parent
60ec62c558
commit
12c8ece418
|
@ -19,16 +19,21 @@ impl DynamicType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct that fetches some dynamic type.
|
|
||||||
|
/// A struct that fetches a dynamic type.
|
||||||
///
|
///
|
||||||
/// Currently it can only fetch from archetypes, later it will be able to fetch dynamic
|
/// Currently it can only fetch from archetypes, later it will be able to fetch dynamic
|
||||||
/// resources as well. Its meant to be a single Fetcher for all dynamic types.
|
/// resources as well. Its meant to be a single Fetcher for all dynamic types.
|
||||||
pub struct FetchDynamicType<'a> {
|
///
|
||||||
pub col: &'a ComponentColumn,
|
/// # Safety
|
||||||
|
/// Internally, this struct has a `NonNull<ComponentColumn>`. You must ensure that the column
|
||||||
|
/// is not dropped while this is still alive.
|
||||||
|
pub struct FetchDynamicTypeUnsafe {
|
||||||
|
pub col: NonNull<ComponentColumn>,
|
||||||
pub info: ComponentInfo,
|
pub info: ComponentInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Fetch<'a> for FetchDynamicType<'a> {
|
impl<'a> Fetch<'a> for FetchDynamicTypeUnsafe {
|
||||||
type Item = DynamicType;
|
type Item = DynamicType;
|
||||||
|
|
||||||
fn dangling() -> Self {
|
fn dangling() -> Self {
|
||||||
|
@ -36,7 +41,7 @@ impl<'a> Fetch<'a> for FetchDynamicType<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_item(&mut self, entity: crate::ArchetypeEntityId) -> Self::Item {
|
unsafe fn get_item(&mut self, entity: crate::ArchetypeEntityId) -> Self::Item {
|
||||||
let ptr = self.col.borrow_ptr();
|
let ptr = unsafe { self.col.as_ref() }.borrow_ptr();
|
||||||
let ptr = NonNull::new_unchecked(ptr.as_ptr()
|
let ptr = NonNull::new_unchecked(ptr.as_ptr()
|
||||||
.add(entity.0 as usize * self.info.layout().size()));
|
.add(entity.0 as usize * self.info.layout().size()));
|
||||||
|
|
||||||
|
@ -66,13 +71,13 @@ impl QueryDynamicType {
|
||||||
archetype.has_column(self.info.type_id())
|
archetype.has_column(self.info.type_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> FetchDynamicType<'a> {
|
pub unsafe fn fetch<'a>(&self, _world: &'a World, _arch_id: crate::archetype::ArchetypeId, archetype: &'a crate::archetype::Archetype) -> FetchDynamicTypeUnsafe {
|
||||||
let col = archetype.get_column(self.info.type_id())
|
let col = archetype.get_column(self.info.type_id())
|
||||||
.expect("You ignored 'can_visit_archetype'!");
|
.expect("You ignored 'can_visit_archetype'!");
|
||||||
|
|
||||||
FetchDynamicType {
|
FetchDynamicTypeUnsafe {
|
||||||
col,
|
col: NonNull::from(col),
|
||||||
info: self.info,
|
info: self.info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,25 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{World, Archetype, ArchetypeEntityId, ArchetypeId, query::Fetch};
|
use crate::{query::Fetch, Archetype, ArchetypeEntityId, ArchetypeId, World};
|
||||||
|
|
||||||
use super::{QueryDynamicType, FetchDynamicType, DynamicType};
|
use super::{DynamicType, FetchDynamicTypeUnsafe, QueryDynamicType};
|
||||||
|
|
||||||
pub struct DynamicView<'a> {
|
/// Stores the state of a dynamic view.
|
||||||
world: &'a World,
|
///
|
||||||
queries: Vec<QueryDynamicType>
|
/// See [`DynamicView`].
|
||||||
|
///
|
||||||
|
/// This backs [`DynamicView`] which you should probably use. The only reason you would use this
|
||||||
|
/// instead is if you cant borrow the world when storing this type, and its iterators.
|
||||||
|
/// [`DynamicViewState`] provides an 'iterator' of [`DynamicViewStateIter`], which requires you to
|
||||||
|
/// provide a world borrow on each `next` of the iterator. View [`DynamicViewStateIter`] for more
|
||||||
|
/// info.
|
||||||
|
pub struct DynamicViewState {
|
||||||
|
pub(crate) queries: Vec<QueryDynamicType>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DynamicView<'a> {
|
impl DynamicViewState {
|
||||||
pub fn new(world: &'a World) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
world,
|
|
||||||
queries: Vec::new(),
|
queries: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,45 +27,38 @@ impl<'a> DynamicView<'a> {
|
||||||
pub fn push(&mut self, dyn_query: QueryDynamicType) {
|
pub fn push(&mut self, dyn_query: QueryDynamicType) {
|
||||||
self.queries.push(dyn_query);
|
self.queries.push(dyn_query);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoIterator for DynamicView<'a> {
|
pub fn into_iter(self) -> DynamicViewStateIter {
|
||||||
type Item = Vec<DynamicType>;
|
DynamicViewStateIter {
|
||||||
|
|
||||||
type IntoIter = DynamicViewIter<'a>;
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
let archetypes = self.world.archetypes.values().collect();
|
|
||||||
|
|
||||||
DynamicViewIter {
|
|
||||||
world: self.world,
|
|
||||||
queries: self.queries,
|
queries: self.queries,
|
||||||
fetchers: Vec::new(),
|
fetchers: Vec::new(),
|
||||||
archetypes,
|
|
||||||
next_archetype: 0,
|
next_archetype: 0,
|
||||||
component_indices: 0..0,
|
component_indices: 0..0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DynamicViewIter<'a> {
|
/// A view iterator on dynamic types.
|
||||||
pub world: &'a World,
|
///
|
||||||
|
/// You will likely want to use [`DynamicViewIter`] unless you need to store the iterator
|
||||||
|
/// without also borrowing from the world. [`DynamicViewStateIter`] doesn't
|
||||||
|
/// actually implement [`Iterator`] since it requires a `&World` to be provided to it
|
||||||
|
/// each time `next` is ran (see [`DynamicViewStateIter::next`]).
|
||||||
|
pub struct DynamicViewStateIter {
|
||||||
pub queries: Vec<QueryDynamicType>,
|
pub queries: Vec<QueryDynamicType>,
|
||||||
pub fetchers: Vec<FetchDynamicType<'a>>,
|
fetchers: Vec<FetchDynamicTypeUnsafe>,
|
||||||
pub archetypes: Vec<&'a Archetype>,
|
next_archetype: usize,
|
||||||
pub next_archetype: usize,
|
component_indices: Range<u64>,
|
||||||
pub component_indices: Range<u64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for DynamicViewIter<'a> {
|
impl DynamicViewStateIter {
|
||||||
type Item = Vec<DynamicType>;
|
pub fn next(&mut self, world: &World) -> Option<Vec<DynamicType>> {
|
||||||
|
let archetypes = world.archetypes.values().collect::<Vec<_>>();
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(entity_index) = self.component_indices.next() {
|
if let Some(entity_index) = self.component_indices.next() {
|
||||||
let mut fetch_res = vec![];
|
let mut fetch_res = vec![];
|
||||||
|
|
||||||
//let fetcher = self.fetcher.as_mut().unwrap();
|
|
||||||
for fetcher in self.fetchers.iter_mut() {
|
for fetcher in self.fetchers.iter_mut() {
|
||||||
let entity_index = ArchetypeEntityId(entity_index);
|
let entity_index = ArchetypeEntityId(entity_index);
|
||||||
if !fetcher.can_visit_item(entity_index) {
|
if !fetcher.can_visit_item(entity_index) {
|
||||||
|
@ -75,13 +75,13 @@ impl<'a> Iterator for DynamicViewIter<'a> {
|
||||||
|
|
||||||
return Some(fetch_res);
|
return Some(fetch_res);
|
||||||
} else {
|
} else {
|
||||||
if self.next_archetype >= self.archetypes.len() {
|
if self.next_archetype >= archetypes.len() {
|
||||||
return None; // ran out of archetypes to go through
|
return None; // ran out of archetypes to go through
|
||||||
}
|
}
|
||||||
|
|
||||||
let arch_id = self.next_archetype;
|
let arch_id = self.next_archetype;
|
||||||
self.next_archetype += 1;
|
self.next_archetype += 1;
|
||||||
let arch = unsafe { self.archetypes.get_unchecked(arch_id) };
|
let arch = unsafe { archetypes.get_unchecked(arch_id) };
|
||||||
|
|
||||||
if arch.entity_ids.is_empty() {
|
if arch.entity_ids.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -92,7 +92,7 @@ impl<'a> Iterator for DynamicViewIter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fetchers = self.queries.iter()
|
self.fetchers = self.queries.iter()
|
||||||
.map(|q| unsafe { q.fetch(self.world, ArchetypeId(arch_id as u64), arch) } )
|
.map(|q| unsafe { q.fetch(world, ArchetypeId(arch_id as u64), arch) } )
|
||||||
.collect();
|
.collect();
|
||||||
self.component_indices = 0..arch.entity_ids.len() as u64;
|
self.component_indices = 0..arch.entity_ids.len() as u64;
|
||||||
}
|
}
|
||||||
|
@ -100,13 +100,101 @@ impl<'a> Iterator for DynamicViewIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A view of dynamic types (types that are not known to Rust).
|
||||||
|
///
|
||||||
|
/// This view gives you the ability to iterate over types that are unknown to Rust, which we call
|
||||||
|
/// dynamic types. This is great for embedding with a scripting language (*cough* *cough* WASM)
|
||||||
|
/// since Rust doesn't actually need to know the types of what its iterating over.
|
||||||
|
pub struct DynamicView<'a> {
|
||||||
|
world: &'a World,
|
||||||
|
inner: DynamicViewState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DynamicView<'a> {
|
||||||
|
pub fn new(world: &'a World) -> Self {
|
||||||
|
Self {
|
||||||
|
world,
|
||||||
|
inner: DynamicViewState::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, dyn_query: QueryDynamicType) {
|
||||||
|
self.inner.queries.push(dyn_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A view iterator on dynamic types.
|
||||||
|
///
|
||||||
|
/// This view gives you the ability to iterate over types that are completely unknown to Rust.
|
||||||
|
/// This works great for a embedding with a scripting language (*cough* *cough* WASM) since
|
||||||
|
/// Rust doesn't actually need to know the types of what its iterating over.
|
||||||
|
impl<'a> IntoIterator for DynamicView<'a> {
|
||||||
|
type Item = Vec<DynamicType>;
|
||||||
|
|
||||||
|
type IntoIter = DynamicViewIter<'a>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
let archetypes = self.world.archetypes.values().collect();
|
||||||
|
|
||||||
|
DynamicViewIter {
|
||||||
|
world: self.world,
|
||||||
|
archetypes,
|
||||||
|
inner: self.inner.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DynamicViewIter<'a> {
|
||||||
|
pub world: &'a World,
|
||||||
|
pub archetypes: Vec<&'a Archetype>,
|
||||||
|
inner: DynamicViewStateIter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for DynamicViewIter<'a> {
|
||||||
|
type Item = Vec<DynamicType>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.inner.next(&self.world)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{alloc::Layout, ptr::NonNull};
|
use std::{alloc::Layout, ptr::NonNull};
|
||||||
|
|
||||||
use crate::{World, ComponentInfo, DynTypeId, DynamicBundle, query::dynamic::QueryDynamicType};
|
use crate::{World, ComponentInfo, DynTypeId, DynamicBundle, query::dynamic::QueryDynamicType};
|
||||||
|
|
||||||
use super::DynamicView;
|
use super::{DynamicView, DynamicViewState};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_dynamic_view_state() {
|
||||||
|
let comp_layout = Layout::new::<u32>();
|
||||||
|
let comp_info = ComponentInfo::new_unknown(Some("u32".to_string()), DynTypeId::Unknown(100), 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 = DynamicViewState::new();
|
||||||
|
view.push(query);
|
||||||
|
|
||||||
|
let mut view_iter = view.into_iter();
|
||||||
|
while let Some(view_row) = view_iter.next(&world) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_dynamic_view() {
|
fn single_dynamic_view() {
|
||||||
|
|
Loading…
Reference in New Issue