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
|
||||
/// 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,
|
||||
}
|
||||
|
||||
impl<'a> Fetch<'a> for FetchDynamicType<'a> {
|
||||
impl<'a> Fetch<'a> for FetchDynamicTypeUnsafe {
|
||||
type Item = DynamicType;
|
||||
|
||||
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 {
|
||||
let ptr = self.col.borrow_ptr();
|
||||
let ptr = unsafe { self.col.as_ref() }.borrow_ptr();
|
||||
let ptr = NonNull::new_unchecked(ptr.as_ptr()
|
||||
.add(entity.0 as usize * self.info.layout().size()));
|
||||
|
||||
|
@ -66,13 +71,13 @@ impl QueryDynamicType {
|
|||
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())
|
||||
.expect("You ignored 'can_visit_archetype'!");
|
||||
|
||||
FetchDynamicType {
|
||||
col,
|
||||
info: self.info,
|
||||
FetchDynamicTypeUnsafe {
|
||||
col: NonNull::from(col),
|
||||
info: self.info
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,25 @@
|
|||
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> {
|
||||
world: &'a World,
|
||||
queries: Vec<QueryDynamicType>
|
||||
/// Stores the state of a dynamic view.
|
||||
///
|
||||
/// 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> {
|
||||
pub fn new(world: &'a World) -> Self {
|
||||
impl DynamicViewState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
world,
|
||||
queries: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -20,45 +27,38 @@ impl<'a> DynamicView<'a> {
|
|||
pub fn push(&mut self, dyn_query: QueryDynamicType) {
|
||||
self.queries.push(dyn_query);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
pub fn into_iter(self) -> DynamicViewStateIter {
|
||||
DynamicViewStateIter {
|
||||
queries: self.queries,
|
||||
fetchers: Vec::new(),
|
||||
archetypes,
|
||||
next_archetype: 0,
|
||||
component_indices: 0..0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DynamicViewIter<'a> {
|
||||
pub world: &'a World,
|
||||
/// A view iterator on dynamic types.
|
||||
///
|
||||
/// 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 fetchers: Vec<FetchDynamicType<'a>>,
|
||||
pub archetypes: Vec<&'a Archetype>,
|
||||
pub next_archetype: usize,
|
||||
pub component_indices: Range<u64>,
|
||||
fetchers: Vec<FetchDynamicTypeUnsafe>,
|
||||
next_archetype: usize,
|
||||
component_indices: Range<u64>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for DynamicViewIter<'a> {
|
||||
type Item = Vec<DynamicType>;
|
||||
impl DynamicViewStateIter {
|
||||
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 {
|
||||
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) {
|
||||
|
@ -75,13 +75,13 @@ impl<'a> Iterator for DynamicViewIter<'a> {
|
|||
|
||||
return Some(fetch_res);
|
||||
} else {
|
||||
if self.next_archetype >= self.archetypes.len() {
|
||||
if self.next_archetype >= 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) };
|
||||
let arch = unsafe { archetypes.get_unchecked(arch_id) };
|
||||
|
||||
if arch.entity_ids.is_empty() {
|
||||
continue;
|
||||
|
@ -92,7 +92,7 @@ impl<'a> Iterator for DynamicViewIter<'a> {
|
|||
}
|
||||
|
||||
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();
|
||||
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)]
|
||||
mod tests {
|
||||
use std::{alloc::Layout, ptr::NonNull};
|
||||
|
||||
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]
|
||||
fn single_dynamic_view() {
|
||||
|
|
Loading…
Reference in New Issue