From 20711bb9480e9b6a83b8ddd8c15c3022d2968459 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Tue, 27 Jun 2023 00:17:12 +0200 Subject: [PATCH 01/52] wip: fetch transforms --- src/component.rs | 6 +- src/fetch/mod.rs | 1 + src/fetch/modified.rs | 176 +++++++++++++++++++++++++++++++++++++++++ src/fetch/read_only.rs | 2 +- 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 src/fetch/modified.rs diff --git a/src/component.rs b/src/component.rs index ca7d48bc..97a9d564 100644 --- a/src/component.rs +++ b/src/component.rs @@ -143,7 +143,11 @@ crate::component! { pub(crate) dummy, } -/// Defines a strongly typed component +/// Defines a strongly typed component. +/// +/// Implements a *Read* fetch when used as part of a query +/// +/// Use `.as_mut()` to get a *Write* fetch. pub struct Component { key: ComponentKey, marker: PhantomData, diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 872945a3..f3e521ba 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -6,6 +6,7 @@ mod copied; mod entity_ref; mod ext; mod maybe_mut; +pub mod modified; mod opt; mod read_only; mod relations; diff --git a/src/fetch/modified.rs b/src/fetch/modified.rs new file mode 100644 index 00000000..aaa24c31 --- /dev/null +++ b/src/fetch/modified.rs @@ -0,0 +1,176 @@ +use crate::{filter::ChangeFilter, Component, ComponentValue, Fetch, FetchItem}; + +use super::{FmtQuery, PreparedFetch}; + +/// Transforms any supported fetch or collection of fetch into a fetch which filters modified +/// items. +pub trait ModifiedFetch: for<'w> Fetch<'w> { + type Modified: for<'x> Fetch<'x> + for<'y> FetchItem<'y, Item = >::Item>; + fn transform_modified(self) -> Self::Modified; +} + +impl ModifiedFetch for Component { + type Modified = ChangeFilter; + fn transform_modified(self) -> Self::Modified { + self.modified() + } +} + +impl ModifiedFetch for (A, B) { + type Modified = Union<(A::Modified, B::Modified)>; + fn transform_modified(self) -> Self::Modified { + Union((self.0.transform_modified(), self.1.transform_modified())) + } +} + +/// A specific kind of `or` combinator which only *or* combines the returned entities, but not the +/// component filters. This allows the filters to return fetch items side by side like the wrapped +/// fetch would, since all constituent fetches are satisfied, but not necessarily all their entities. +/// +/// This is most useful for change queries, where you care about about *any* change, but still +/// require the entity to have all the components, and have them returned despite not all having +/// changed. +pub struct Union(pub T); +impl<'w, A: Fetch<'w>, B: Fetch<'w>> Fetch<'w> for Union<(A, B)> { + const MUTABLE: bool = A::MUTABLE | B::MUTABLE; + + type Prepared = Union<(A::Prepared, B::Prepared)>; + + fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { + let inner = &self.0; + Some(Union((inner.0.prepare(data)?, inner.1.prepare(data)?))) + } + + fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { + let inner = &self.0; + inner.0.filter_arch(arch) && inner.1.filter_arch(arch) + } + + fn access(&self, data: super::FetchAccessData, dst: &mut Vec) { + let inner = &self.0; + inner.0.access(data, dst); + inner.1.access(data, dst); + } + + fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let inner = &self.0; + let mut s = f.debug_tuple("Union"); + s.field(&FmtQuery(&inner.0)); + s.field(&FmtQuery(&inner.1)); + + s.finish() + } +} + +impl<'w, A: PreparedFetch<'w>, B: PreparedFetch<'w>> PreparedFetch<'w> for Union<(A, B)> { + type Item = (A::Item, B::Item); + + unsafe fn fetch(&'w mut self, slot: usize) -> Self::Item { + let inner = &mut self.0; + (inner.0.fetch(slot), inner.1.fetch(slot)) + } + + unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { + let inner = &mut self.0; + + [(inner.0.filter_slots(slots)), (inner.1.filter_slots(slots))] + .into_iter() + .min() + .unwrap_or_default() + } + + fn set_visited(&mut self, slots: crate::archetype::Slice) { + let inner = &mut self.0; + inner.0.set_visited(slots); + inner.1.set_visited(slots); + } +} + +impl<'q, A: FetchItem<'q>, B: FetchItem<'q>> FetchItem<'q> for Union<(A, B)> { + type Item = (A::Item, B::Item); +} + +#[cfg(test)] +mod tests { + + use alloc::string::ToString; + use itertools::Itertools; + + use crate::{component, entity_ids, CommandBuffer, Entity, Query, World}; + + use super::*; + + #[test] + fn query_modified() { + component! { + a: i32, + b: String, + other: (), + } + + let mut world = World::new(); + + let id1 = Entity::builder() + .set(a(), 0) + .set(b(), "Hello".into()) + .spawn(&mut world); + + let id2 = Entity::builder() + .set(a(), 1) + .set(b(), "World".into()) + .spawn(&mut world); + + let id3 = Entity::builder() + // .set(a(), 0) + .set(b(), "There".into()) + .spawn(&mut world); + + // Force to a different archetype + let id4 = Entity::builder() + .set(a(), 2) + .set(b(), "!".into()) + .tag(other()) + .spawn(&mut world); + + let mut query = Query::new((entity_ids(), (a(), b()).transform_modified())); + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [ + (id1, (&0, &"Hello".to_string())), + (id2, (&1, &"World".to_string())), + (id4, (&2, &"!".to_string())) + ] + ); + + assert_eq!(query.borrow(&world).iter().collect_vec(), []); + + // Get mut *without* a mut deref is not a change + assert_eq!(*world.get_mut(id2, a()).unwrap(), 1); + + assert_eq!(query.borrow(&world).iter().collect_vec(), []); + + *world.get_mut(id2, a()).unwrap() = 5; + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [(id2, (&5, &"World".to_string()))] + ); + + // Adding the required component to id3 will cause it to be picked up by the query + let mut cmd = CommandBuffer::new(); + cmd.set(id3, a(), -1).apply(&mut world).unwrap(); + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [(id3, (&-1, &"There".to_string()))] + ); + + cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap(); + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [(id3, (&-1, &":P".to_string()))] + ); + } +} diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index 56d12ae3..b8d70cec 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -4,7 +4,7 @@ use super::PreparedFetch; /// A fetch which only yields items which can freely *alias*. /// -/// This makes the `fetch` method *safer* to implement and can be called with a covariant lifetimes. +/// This makes the `fetch` method *safer* to implement and can be called with a covariant lifetime. pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { /// Fetch the shared item from the given slot /// From e5e9f7ed9b301ad429524bc0f27e7196a0c31fa1 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Tue, 27 Jun 2023 22:34:48 +0200 Subject: [PATCH 02/52] feat: implement modified transform for tuples --- src/fetch/ext.rs | 16 +++++ src/fetch/modified.rs | 159 +++++++++++++++++++++++------------------- 2 files changed, 102 insertions(+), 73 deletions(-) diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index 432e9d9f..862932d0 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -7,6 +7,7 @@ use super::{ as_deref::AsDeref, cloned::Cloned, copied::Copied, + modified::ModifiedFetch, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, Satisfied, Source, @@ -134,6 +135,21 @@ pub trait FetchExt: Sized { { Source::new(self, FromRelation::new(relation)) } + + /// Transform the fetch into a fetch where each constituent part tracks and yields for changes. + /// + /// This is different from E.g; `(a().modified(), b().modified())` as it implies only when + /// *both* `a` and `b` are modified in the same iteration, which is seldom useful. + /// + /// This means will yield *any* of `a` *or* `b` are modified. + /// + /// Works for in combination with `opt`, `copy` etc constituents. + fn modified(self) -> Self::Modified + where + Self: ModifiedFetch, + { + self.transform_modified() + } } impl FetchExt for F where F: for<'x> Fetch<'x> {} diff --git a/src/fetch/modified.rs b/src/fetch/modified.rs index aaa24c31..31f1d47c 100644 --- a/src/fetch/modified.rs +++ b/src/fetch/modified.rs @@ -1,4 +1,4 @@ -use crate::{filter::ChangeFilter, Component, ComponentValue, Fetch, FetchItem}; +use crate::{filter::ChangeFilter, Component, ComponentValue, EntityIds, Fetch, FetchItem}; use super::{FmtQuery, PreparedFetch}; @@ -16,89 +16,24 @@ impl ModifiedFetch for Component { } } -impl ModifiedFetch for (A, B) { - type Modified = Union<(A::Modified, B::Modified)>; - fn transform_modified(self) -> Self::Modified { - Union((self.0.transform_modified(), self.1.transform_modified())) - } -} - -/// A specific kind of `or` combinator which only *or* combines the returned entities, but not the -/// component filters. This allows the filters to return fetch items side by side like the wrapped +/// Unionized the slot-level filter of two fetches, but requires the individual fetches to still +/// match. +/// +/// This allows the filters to return fetch items side by side like the wrapped /// fetch would, since all constituent fetches are satisfied, but not necessarily all their entities. /// /// This is most useful for change queries, where you care about about *any* change, but still /// require the entity to have all the components, and have them returned despite not all having /// changed. pub struct Union(pub T); -impl<'w, A: Fetch<'w>, B: Fetch<'w>> Fetch<'w> for Union<(A, B)> { - const MUTABLE: bool = A::MUTABLE | B::MUTABLE; - - type Prepared = Union<(A::Prepared, B::Prepared)>; - - fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { - let inner = &self.0; - Some(Union((inner.0.prepare(data)?, inner.1.prepare(data)?))) - } - - fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { - let inner = &self.0; - inner.0.filter_arch(arch) && inner.1.filter_arch(arch) - } - - fn access(&self, data: super::FetchAccessData, dst: &mut Vec) { - let inner = &self.0; - inner.0.access(data, dst); - inner.1.access(data, dst); - } - - fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let inner = &self.0; - let mut s = f.debug_tuple("Union"); - s.field(&FmtQuery(&inner.0)); - s.field(&FmtQuery(&inner.1)); - - s.finish() - } -} - -impl<'w, A: PreparedFetch<'w>, B: PreparedFetch<'w>> PreparedFetch<'w> for Union<(A, B)> { - type Item = (A::Item, B::Item); - - unsafe fn fetch(&'w mut self, slot: usize) -> Self::Item { - let inner = &mut self.0; - (inner.0.fetch(slot), inner.1.fetch(slot)) - } - - unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { - let inner = &mut self.0; - - [(inner.0.filter_slots(slots)), (inner.1.filter_slots(slots))] - .into_iter() - .min() - .unwrap_or_default() - } - - fn set_visited(&mut self, slots: crate::archetype::Slice) { - let inner = &mut self.0; - inner.0.set_visited(slots); - inner.1.set_visited(slots); - } -} - -impl<'q, A: FetchItem<'q>, B: FetchItem<'q>> FetchItem<'q> for Union<(A, B)> { - type Item = (A::Item, B::Item); -} #[cfg(test)] mod tests { - use alloc::string::ToString; + use alloc::string::{String, ToString}; use itertools::Itertools; - use crate::{component, entity_ids, CommandBuffer, Entity, Query, World}; - - use super::*; + use crate::{component, entity_ids, CommandBuffer, Entity, FetchExt, Query, World}; #[test] fn query_modified() { @@ -132,7 +67,7 @@ mod tests { .tag(other()) .spawn(&mut world); - let mut query = Query::new((entity_ids(), (a(), b()).transform_modified())); + let mut query = Query::new((entity_ids(), (a(), b()).modified())); assert_eq!( query.borrow(&world).iter().collect_vec(), @@ -174,3 +109,81 @@ mod tests { ); } } +macro_rules! tuple_impl { + ($($idx: tt => $ty: ident),*) => { + impl<'w, $($ty: Fetch<'w>,)*> Fetch<'w> for Union<($($ty,)*)> { + const MUTABLE: bool = $($ty::MUTABLE )||*; + + type Prepared = Union<($($ty::Prepared,)*)>; + + fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { + let inner = &self.0; + Some(Union(($(inner.$idx.prepare(data)?,)*))) + } + + fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { + let inner = &self.0; + $(inner.$idx.filter_arch(arch))&&* + } + + fn access(&self, data: super::FetchAccessData, dst: &mut alloc::vec::Vec) { + let inner = &self.0; + $(inner.$idx.access(data, dst);)* + } + + fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let inner = &self.0; + let mut s = f.debug_tuple("Union"); + $(s.field(&FmtQuery(&inner.$idx));)* + + s.finish() + } + } + + + impl<'w, $($ty: PreparedFetch<'w>,)* > PreparedFetch<'w> for Union<($($ty,)*)> { + type Item = ($($ty::Item,)*); + + unsafe fn fetch(&'w mut self, slot: usize) -> Self::Item { + let inner = &mut self.0; + ($(inner.$idx.fetch(slot), )*) + } + + unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { + let inner = &mut self.0; + + [$(inner.$idx.filter_slots(slots)),*] + .into_iter() + .min() + .unwrap_or_default() + } + + fn set_visited(&mut self, slots: crate::archetype::Slice) { + let inner = &mut self.0; + $(inner.$idx.set_visited(slots);)* + } + } + + impl<'q, $($ty: FetchItem<'q>,)*> FetchItem<'q> for Union<($($ty,)*)> { + type Item = ($($ty::Item,)*); + } + + + impl<$($ty: ModifiedFetch,)*> ModifiedFetch for ($($ty,)*) { + type Modified = Union<($($ty::Modified,)*)>; + fn transform_modified(self) -> Self::Modified { + Union(($(self.$idx.transform_modified(),)*)) + } + } + }; + + +} + +tuple_impl! { 0 => A } +tuple_impl! { 0 => A, 1 => B } +tuple_impl! { 0 => A, 1 => B, 2 => C } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H } From 1a665300351d25d35cef16c3ca6550005026cd0c Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Tue, 27 Jun 2023 22:48:28 +0200 Subject: [PATCH 03/52] chore: split filters into more modules --- src/fetch/mod.rs | 2 +- src/fetch/modified.rs | 2 +- src/filter/constant.rs | 151 +++++++++++++++++++ src/filter/mod.rs | 320 +---------------------------------------- src/filter/set.rs | 180 +++++++++++++++++++++++ 5 files changed, 339 insertions(+), 316 deletions(-) create mode 100644 src/filter/constant.rs create mode 100644 src/filter/set.rs diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index f3e521ba..199c2f23 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -6,7 +6,7 @@ mod copied; mod entity_ref; mod ext; mod maybe_mut; -pub mod modified; +mod modified; mod opt; mod read_only; mod relations; diff --git a/src/fetch/modified.rs b/src/fetch/modified.rs index 31f1d47c..78155fca 100644 --- a/src/fetch/modified.rs +++ b/src/fetch/modified.rs @@ -1,4 +1,4 @@ -use crate::{filter::ChangeFilter, Component, ComponentValue, EntityIds, Fetch, FetchItem}; +use crate::{filter::ChangeFilter, Component, ComponentValue, Fetch, FetchItem}; use super::{FmtQuery, PreparedFetch}; diff --git a/src/filter/constant.rs b/src/filter/constant.rs new file mode 100644 index 00000000..7cb7dfc2 --- /dev/null +++ b/src/filter/constant.rs @@ -0,0 +1,151 @@ +use crate::{ + archetype::{Archetype, Slice}, + fetch::{FetchAccessData, FetchPrepareData, PreparedFetch}, + system::Access, + Fetch, FetchItem, +}; +use alloc::vec::Vec; +use core::fmt::{self, Formatter}; + +#[derive(Debug, Clone)] +/// A filter that yields, well, nothing +pub struct Nothing; + +impl<'q> FetchItem<'q> for Nothing { + type Item = (); +} + +impl<'a> Fetch<'a> for Nothing { + const MUTABLE: bool = false; + + type Prepared = Nothing; + + #[inline(always)] + fn prepare(&self, _: FetchPrepareData) -> Option { + Some(Nothing) + } + + #[inline(always)] + fn filter_arch(&self, _: &Archetype) -> bool { + false + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "false") + } + + fn access(&self, _data: FetchAccessData, _dst: &mut Vec) {} +} + +impl<'q> PreparedFetch<'q> for Nothing { + type Item = (); + + unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} +} + +/// Yields all entities +#[derive(Debug, Clone)] +pub struct All; + +impl<'q> FetchItem<'q> for All { + type Item = (); +} + +impl<'w> Fetch<'w> for All { + const MUTABLE: bool = false; + + type Prepared = All; + + fn prepare(&'w self, _: FetchPrepareData<'w>) -> Option { + Some(All) + } + + fn filter_arch(&self, _: &Archetype) -> bool { + true + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "true") + } + + fn access(&self, _: FetchAccessData, _: &mut Vec) {} +} + +impl<'q> PreparedFetch<'q> for All { + type Item = (); + + unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} +} + +impl<'q> FetchItem<'q> for Slice { + type Item = (); +} + +impl<'w> Fetch<'w> for Slice { + const MUTABLE: bool = false; + + type Prepared = Self; + + fn prepare(&'w self, _: FetchPrepareData<'w>) -> Option { + Some(*self) + } + + fn filter_arch(&self, _: &Archetype) -> bool { + true + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "slice {:?}", self) + } + + #[inline] + fn access(&self, _: FetchAccessData, _: &mut Vec) {} +} + +impl<'q> PreparedFetch<'q> for Slice { + type Item = (); + + #[inline] + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + + #[inline] + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + self.intersect(&slots) + } +} + +impl<'q> FetchItem<'q> for bool { + type Item = bool; +} + +impl<'w> Fetch<'w> for bool { + const MUTABLE: bool = false; + + type Prepared = Self; + + #[inline(always)] + fn prepare(&'w self, _: FetchPrepareData) -> Option { + Some(*self) + } + + #[inline(always)] + fn filter_arch(&self, _: &Archetype) -> bool { + *self + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self) + } + + #[inline] + fn access(&self, _: FetchAccessData, _: &mut Vec) {} +} + +impl<'q> PreparedFetch<'q> for bool { + type Item = bool; + + #[inline] + unsafe fn fetch(&mut self, _: usize) -> Self::Item { + *self + } +} diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 553b6c6e..c1189997 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -1,7 +1,9 @@ mod change; mod cmp; -use alloc::vec::Vec; +mod constant; +mod set; +use alloc::vec::Vec; use core::{ any::type_name, fmt::{self, Formatter}, @@ -12,13 +14,15 @@ use core::{ use crate::{ archetype::{Archetype, Slice, Slot}, component_info, - fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch}, + fetch::{FetchAccessData, FetchPrepareData, PreparedFetch}, system::Access, ArchetypeSearcher, ComponentKey, Entity, Fetch, FetchItem, }; pub use change::*; pub use cmp::{Cmp, Equal, Greater, GreaterEq, Less, LessEq}; +pub use constant::*; +pub use set::*; macro_rules! gen_bitops { ($ty:ident[$($p: tt),*]) => { @@ -169,282 +173,6 @@ gen_bitops! { Cmp[A,B]; } -#[derive(Debug, Clone)] -/// And combinator -pub struct And { - pub(crate) left: L, - pub(crate) right: R, -} - -impl And { - /// Creates a new and filter - pub fn new(left: L, right: R) -> Self { - Self { left, right } - } -} - -impl<'q, L, R> FetchItem<'q> for And -where - L: FetchItem<'q>, - R: FetchItem<'q>, -{ - type Item = (L::Item, R::Item); -} - -impl<'w, L, R> Fetch<'w> for And -where - L: Fetch<'w>, - R: Fetch<'w>, -{ - const MUTABLE: bool = false; - - type Prepared = And; - - #[inline] - fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { - Some(And { - left: self.left.prepare(data)?, - right: self.right.prepare(data)?, - }) - } - - fn filter_arch(&self, arch: &Archetype) -> bool { - self.left.filter_arch(arch) && self.right.filter_arch(arch) - } - - fn access(&self, data: FetchAccessData, dst: &mut Vec) { - self.left.access(data, dst); - self.right.access(data, dst); - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.left.describe(f)?; - f.write_str(" & ")?; - self.right.describe(f)?; - - Ok(()) - } - - fn searcher(&self, searcher: &mut crate::ArchetypeSearcher) { - self.left.searcher(searcher); - self.right.searcher(searcher); - } -} - -impl<'q, L, R> PreparedFetch<'q> for And -where - L: PreparedFetch<'q>, - R: PreparedFetch<'q>, -{ - type Item = (L::Item, R::Item); - - #[inline] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - (self.left.fetch(slot), self.right.fetch(slot)) - } - - fn set_visited(&mut self, slots: Slice) { - self.left.set_visited(slots); - self.right.set_visited(slots); - } - - #[inline] - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let l = self.left.filter_slots(slots); - - self.right.filter_slots(l) - } -} - -#[derive(Debug, Clone)] -/// Or filter combinator -pub struct Or(pub T); - -#[derive(Debug, Clone)] -/// Negate a filter -pub struct Not(pub T); - -impl<'q, T> FetchItem<'q> for Not { - type Item = (); -} - -impl<'w, T> Fetch<'w> for Not -where - T: Fetch<'w>, -{ - const MUTABLE: bool = true; - - type Prepared = Not>; - - fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { - Some(Not(self.0.prepare(data))) - } - - fn filter_arch(&self, arch: &Archetype) -> bool { - !self.0.filter_arch(arch) - } - - #[inline] - fn access(&self, data: FetchAccessData, dst: &mut Vec) { - self.0.access(data, dst) - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "!{:?}", FmtQuery(&self.0)) - } -} - -impl<'q, F> PreparedFetch<'q> for Not> -where - F: PreparedFetch<'q>, -{ - type Item = (); - - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} - - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - if let Some(fetch) = &mut self.0 { - let v = fetch.filter_slots(slots); - - slots.difference(v).unwrap() - } else { - slots - } - } -} - -impl ops::BitOr for Not { - type Output = Or<(Self, R)>; - - fn bitor(self, rhs: R) -> Self::Output { - Or((self, rhs)) - } -} - -impl ops::BitAnd for Not { - type Output = (Self, R); - - fn bitand(self, rhs: R) -> Self::Output { - (self, rhs) - } -} - -impl ops::Not for Not { - type Output = T; - - fn not(self) -> Self::Output { - self.0 - } -} - -#[derive(Debug, Clone)] -/// A filter that yields, well, nothing -pub struct Nothing; - -impl<'q> FetchItem<'q> for Nothing { - type Item = (); -} - -impl<'q> FetchItem<'q> for All { - type Item = (); -} - -impl<'a> Fetch<'a> for Nothing { - const MUTABLE: bool = false; - - type Prepared = Nothing; - - #[inline(always)] - fn prepare(&self, _: FetchPrepareData) -> Option { - Some(Nothing) - } - - #[inline(always)] - fn filter_arch(&self, _: &Archetype) -> bool { - false - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "false") - } - - fn access(&self, _data: FetchAccessData, _dst: &mut Vec) {} -} - -/// Yields all entities -#[derive(Debug, Clone)] -pub struct All; - -impl<'w> Fetch<'w> for All { - const MUTABLE: bool = false; - - type Prepared = All; - - fn prepare(&'w self, _: FetchPrepareData<'w>) -> Option { - Some(All) - } - - fn filter_arch(&self, _: &Archetype) -> bool { - true - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "true") - } - - fn access(&self, _: FetchAccessData, _: &mut Vec) {} -} - -impl<'q> PreparedFetch<'q> for All { - type Item = (); - - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} -} - -impl<'q> PreparedFetch<'q> for Nothing { - type Item = (); - - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} -} - -impl<'q> FetchItem<'q> for Slice { - type Item = (); -} - -impl<'w> Fetch<'w> for Slice { - const MUTABLE: bool = false; - - type Prepared = Self; - - fn prepare(&'w self, _: FetchPrepareData<'w>) -> Option { - Some(*self) - } - - fn filter_arch(&self, _: &Archetype) -> bool { - true - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "slice {:?}", self) - } - - #[inline] - fn access(&self, _: FetchAccessData, _: &mut Vec) {} -} - -impl<'q> PreparedFetch<'q> for Slice { - type Item = (); - - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} - - #[inline] - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - self.intersect(&slots) - } -} - #[derive(Debug, Clone)] /// Iterator which yields slices which match the underlying filter pub struct FilterIter { @@ -705,42 +433,6 @@ impl<'a> Fetch<'a> for WithoutRelation { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'q> FetchItem<'q> for bool { - type Item = bool; -} - -impl<'w> Fetch<'w> for bool { - const MUTABLE: bool = false; - - type Prepared = Self; - - #[inline(always)] - fn prepare(&'w self, _: FetchPrepareData) -> Option { - Some(*self) - } - - #[inline(always)] - fn filter_arch(&self, _: &Archetype) -> bool { - *self - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self) - } - - #[inline] - fn access(&self, _: FetchAccessData, _: &mut Vec) {} -} - -impl<'q> PreparedFetch<'q> for bool { - type Item = bool; - - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item { - *self - } -} - /// Allows a fetch to be used by reference. pub struct RefFetch<'a, F>(pub(crate) &'a F); diff --git a/src/filter/set.rs b/src/filter/set.rs new file mode 100644 index 00000000..ec9f72b8 --- /dev/null +++ b/src/filter/set.rs @@ -0,0 +1,180 @@ +use crate::{ + archetype::{Archetype, Slice, Slot}, + fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch}, + system::Access, + Fetch, FetchItem, +}; +use alloc::vec::Vec; +use core::{ + fmt::{self, Formatter}, + ops, +}; + +#[derive(Debug, Clone)] +/// And combinator +pub struct And { + pub(crate) left: L, + pub(crate) right: R, +} + +impl And { + /// Creates a new and filter + pub fn new(left: L, right: R) -> Self { + Self { left, right } + } +} + +impl<'q, L, R> FetchItem<'q> for And +where + L: FetchItem<'q>, + R: FetchItem<'q>, +{ + type Item = (L::Item, R::Item); +} + +impl<'w, L, R> Fetch<'w> for And +where + L: Fetch<'w>, + R: Fetch<'w>, +{ + const MUTABLE: bool = false; + + type Prepared = And; + + #[inline] + fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { + Some(And { + left: self.left.prepare(data)?, + right: self.right.prepare(data)?, + }) + } + + fn filter_arch(&self, arch: &Archetype) -> bool { + self.left.filter_arch(arch) && self.right.filter_arch(arch) + } + + fn access(&self, data: FetchAccessData, dst: &mut Vec) { + self.left.access(data, dst); + self.right.access(data, dst); + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.left.describe(f)?; + f.write_str(" & ")?; + self.right.describe(f)?; + + Ok(()) + } + + fn searcher(&self, searcher: &mut crate::ArchetypeSearcher) { + self.left.searcher(searcher); + self.right.searcher(searcher); + } +} + +impl<'q, L, R> PreparedFetch<'q> for And +where + L: PreparedFetch<'q>, + R: PreparedFetch<'q>, +{ + type Item = (L::Item, R::Item); + + #[inline] + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + (self.left.fetch(slot), self.right.fetch(slot)) + } + + fn set_visited(&mut self, slots: Slice) { + self.left.set_visited(slots); + self.right.set_visited(slots); + } + + #[inline] + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + let l = self.left.filter_slots(slots); + + self.right.filter_slots(l) + } +} + +#[derive(Debug, Clone)] +/// Or filter combinator +pub struct Or(pub T); + +#[derive(Debug, Clone)] +/// Negate a filter +pub struct Not(pub T); + +impl<'q, T> FetchItem<'q> for Not { + type Item = (); +} + +impl<'w, T> Fetch<'w> for Not +where + T: Fetch<'w>, +{ + const MUTABLE: bool = true; + + type Prepared = Not>; + + fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { + Some(Not(self.0.prepare(data))) + } + + fn filter_arch(&self, arch: &Archetype) -> bool { + !self.0.filter_arch(arch) + } + + #[inline] + fn access(&self, data: FetchAccessData, dst: &mut Vec) { + self.0.access(data, dst) + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "!{:?}", FmtQuery(&self.0)) + } +} + +impl<'q, F> PreparedFetch<'q> for Not> +where + F: PreparedFetch<'q>, +{ + type Item = (); + + #[inline] + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + if let Some(fetch) = &mut self.0 { + let v = fetch.filter_slots(slots); + + slots.difference(v).unwrap() + } else { + slots + } + } +} + +impl ops::BitOr for Not { + type Output = Or<(Self, R)>; + + fn bitor(self, rhs: R) -> Self::Output { + Or((self, rhs)) + } +} + +impl ops::BitAnd for Not { + type Output = (Self, R); + + fn bitand(self, rhs: R) -> Self::Output { + (self, rhs) + } +} + +impl ops::Not for Not { + type Output = T; + + fn not(self) -> Self::Output { + self.0 + } +} From 6e42b9338f694d0f52fed029819e833f14f32f44 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Tue, 27 Jun 2023 22:51:41 +0200 Subject: [PATCH 04/52] chore: move union to filter modules --- src/fetch/mod.rs | 65 ------------------- src/fetch/modified.rs | 110 ++++++-------------------------- src/filter/set.rs | 145 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 156 deletions(-) diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 199c2f23..50958295 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -286,8 +286,6 @@ impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { } } -use crate::filter::Or; - // Implement for tuples macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { @@ -403,69 +401,6 @@ macro_rules! tuple_impl { $((self.$idx).searcher(searcher));* } } - - - // ----- OR ----- - impl<'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { - type Item = (); - } - - impl<'w, $($ty, )*> Fetch<'w> for Or<($($ty,)*)> - where $($ty: Fetch<'w>,)* - { - const MUTABLE: bool = $($ty::MUTABLE )|*; - type Prepared = Or<($(Option<$ty::Prepared>,)*)>; - - fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { - let inner = &self.0; - Some( Or(($(inner.$idx.prepare(data),)*)) ) - } - - fn filter_arch(&self, arch: &Archetype) -> bool { - let inner = &self.0; - $(inner.$idx.filter_arch(arch))||* - } - - fn access(&self, data: FetchAccessData, dst: &mut Vec) { - $(self.0.$idx.access(data, dst);)* - } - - fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut s = f.debug_tuple("Or"); - let inner = &self.0; - $( - s.field(&FmtQuery(&inner.$idx)); - )* - s.finish() - } - } - - - impl<'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)> - where $($ty: PreparedFetch<'q>,)* - { - type Item = (); - - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let inner = &mut self.0; - - [ - $( inner.$idx.filter_slots(slots)),* - ] - .into_iter() - .min() - .unwrap_or_default() - - } - - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} - - fn set_visited(&mut self, slots: Slice) { - $( self.0.$idx.set_visited(slots);)* - } - - } }; } diff --git a/src/fetch/modified.rs b/src/fetch/modified.rs index 78155fca..5e3187d8 100644 --- a/src/fetch/modified.rs +++ b/src/fetch/modified.rs @@ -1,6 +1,4 @@ -use crate::{filter::ChangeFilter, Component, ComponentValue, Fetch, FetchItem}; - -use super::{FmtQuery, PreparedFetch}; +use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch, FetchItem}; /// Transforms any supported fetch or collection of fetch into a fetch which filters modified /// items. @@ -16,16 +14,24 @@ impl ModifiedFetch for Component { } } -/// Unionized the slot-level filter of two fetches, but requires the individual fetches to still -/// match. -/// -/// This allows the filters to return fetch items side by side like the wrapped -/// fetch would, since all constituent fetches are satisfied, but not necessarily all their entities. -/// -/// This is most useful for change queries, where you care about about *any* change, but still -/// require the entity to have all the components, and have them returned despite not all having -/// changed. -pub struct Union(pub T); +macro_rules! tuple_impl { + ($($idx: tt => $ty: ident),*) => { + impl<$($ty: ModifiedFetch,)*> ModifiedFetch for ($($ty,)*) { + type Modified = Union<($($ty::Modified,)*)>; + fn transform_modified(self) -> Self::Modified { + Union(($(self.$idx.transform_modified(),)*)) + } + } + }; +} + +tuple_impl! { 0 => A } +tuple_impl! { 0 => A, 1 => B } +tuple_impl! { 0 => A, 1 => B, 2 => C } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H } #[cfg(test)] mod tests { @@ -109,81 +115,3 @@ mod tests { ); } } -macro_rules! tuple_impl { - ($($idx: tt => $ty: ident),*) => { - impl<'w, $($ty: Fetch<'w>,)*> Fetch<'w> for Union<($($ty,)*)> { - const MUTABLE: bool = $($ty::MUTABLE )||*; - - type Prepared = Union<($($ty::Prepared,)*)>; - - fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { - let inner = &self.0; - Some(Union(($(inner.$idx.prepare(data)?,)*))) - } - - fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { - let inner = &self.0; - $(inner.$idx.filter_arch(arch))&&* - } - - fn access(&self, data: super::FetchAccessData, dst: &mut alloc::vec::Vec) { - let inner = &self.0; - $(inner.$idx.access(data, dst);)* - } - - fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let inner = &self.0; - let mut s = f.debug_tuple("Union"); - $(s.field(&FmtQuery(&inner.$idx));)* - - s.finish() - } - } - - - impl<'w, $($ty: PreparedFetch<'w>,)* > PreparedFetch<'w> for Union<($($ty,)*)> { - type Item = ($($ty::Item,)*); - - unsafe fn fetch(&'w mut self, slot: usize) -> Self::Item { - let inner = &mut self.0; - ($(inner.$idx.fetch(slot), )*) - } - - unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { - let inner = &mut self.0; - - [$(inner.$idx.filter_slots(slots)),*] - .into_iter() - .min() - .unwrap_or_default() - } - - fn set_visited(&mut self, slots: crate::archetype::Slice) { - let inner = &mut self.0; - $(inner.$idx.set_visited(slots);)* - } - } - - impl<'q, $($ty: FetchItem<'q>,)*> FetchItem<'q> for Union<($($ty,)*)> { - type Item = ($($ty::Item,)*); - } - - - impl<$($ty: ModifiedFetch,)*> ModifiedFetch for ($($ty,)*) { - type Modified = Union<($($ty::Modified,)*)>; - fn transform_modified(self) -> Self::Modified { - Union(($(self.$idx.transform_modified(),)*)) - } - } - }; - - -} - -tuple_impl! { 0 => A } -tuple_impl! { 0 => A, 1 => B } -tuple_impl! { 0 => A, 1 => B, 2 => C } -tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D } -tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E } -tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F } -tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H } diff --git a/src/filter/set.rs b/src/filter/set.rs index ec9f72b8..4ec4b158 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -178,3 +178,148 @@ impl ops::Not for Not { self.0 } } + +/// Unionized the slot-level filter of two fetches, but requires the individual fetches to still +/// match. +/// +/// This allows the filters to return fetch items side by side like the wrapped +/// fetch would, since all constituent fetches are satisfied, but not necessarily all their entities. +/// +/// This is most useful for change queries, where you care about about *any* change, but still +/// require the entity to have all the components, and have them returned despite not all having +/// changed. +pub struct Union(pub T); + +macro_rules! tuple_impl { + ($($idx: tt => $ty: ident),*) => { + // Union + impl<'w, $($ty: Fetch<'w>,)*> Fetch<'w> for Union<($($ty,)*)> { + const MUTABLE: bool = $($ty::MUTABLE )||*; + + type Prepared = Union<($($ty::Prepared,)*)>; + + fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { + let inner = &self.0; + Some(Union(($(inner.$idx.prepare(data)?,)*))) + } + + fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { + let inner = &self.0; + $(inner.$idx.filter_arch(arch))&&* + } + + fn access(&self, data: super::FetchAccessData, dst: &mut alloc::vec::Vec) { + let inner = &self.0; + $(inner.$idx.access(data, dst);)* + } + + fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let inner = &self.0; + let mut s = f.debug_tuple("Union"); + $(s.field(&FmtQuery(&inner.$idx));)* + + s.finish() + } + } + + + impl<'w, $($ty: PreparedFetch<'w>,)* > PreparedFetch<'w> for Union<($($ty,)*)> { + type Item = ($($ty::Item,)*); + + unsafe fn fetch(&'w mut self, slot: usize) -> Self::Item { + let inner = &mut self.0; + ($(inner.$idx.fetch(slot), )*) + } + + unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { + let inner = &mut self.0; + + [$(inner.$idx.filter_slots(slots)),*] + .into_iter() + .min() + .unwrap_or_default() + } + + fn set_visited(&mut self, slots: crate::archetype::Slice) { + let inner = &mut self.0; + $(inner.$idx.set_visited(slots);)* + } + } + + impl<'q, $($ty: FetchItem<'q>,)*> FetchItem<'q> for Union<($($ty,)*)> { + type Item = ($($ty::Item,)*); + } + + // Or + impl<'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { + type Item = (); + } + + impl<'w, $($ty, )*> Fetch<'w> for Or<($($ty,)*)> + where $($ty: Fetch<'w>,)* + { + const MUTABLE: bool = $($ty::MUTABLE )|*; + type Prepared = Or<($(Option<$ty::Prepared>,)*)>; + + fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { + let inner = &self.0; + Some( Or(($(inner.$idx.prepare(data),)*)) ) + } + + fn filter_arch(&self, arch: &Archetype) -> bool { + let inner = &self.0; + $(inner.$idx.filter_arch(arch))||* + } + + fn access(&self, data: FetchAccessData, dst: &mut Vec) { + $(self.0.$idx.access(data, dst);)* + } + + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut s = f.debug_tuple("Or"); + let inner = &self.0; + $( + s.field(&FmtQuery(&inner.$idx)); + )* + s.finish() + } + } + + + impl<'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)> + where $($ty: PreparedFetch<'q>,)* + { + type Item = (); + + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + let inner = &mut self.0; + + [ + $( inner.$idx.filter_slots(slots)),* + ] + .into_iter() + .min() + .unwrap_or_default() + + } + + #[inline] + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + + fn set_visited(&mut self, slots: Slice) { + $( self.0.$idx.set_visited(slots);)* + } + + } + }; + + +} + +tuple_impl! { 0 => A } +tuple_impl! { 0 => A, 1 => B } +tuple_impl! { 0 => A, 1 => B, 2 => C } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F } +tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H } From 03573b616f78d5c2451cbc703158edb01303d087 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Tue, 27 Jun 2023 23:29:11 +0200 Subject: [PATCH 05/52] fix!: reduce `And` nesting in query filter parameter BREAKING: `Query<(Component, Mutable), And>` will become `Query<(Component, Mutable), (All, With)>` This is mostly only relevant if you explicitly store queries, when using queries the `filter` parameter can be ignored with `_` and is generally preferred as it allows adding a filter without modifying the argument type as well. --- asteroids/src/main.rs | 115 +++++++++++++++++++++++++----------------- src/filter/mod.rs | 4 +- src/filter/set.rs | 48 ++++++++---------- src/query/mod.rs | 38 ++++++++++---- src/query/walk.rs | 2 +- src/serialize/ser.rs | 2 +- src/util/mod.rs | 16 ++++++ 7 files changed, 136 insertions(+), 89 deletions(-) diff --git a/asteroids/src/main.rs b/asteroids/src/main.rs index a20090d6..594661ca 100644 --- a/asteroids/src/main.rs +++ b/asteroids/src/main.rs @@ -1,13 +1,12 @@ use anyhow::{Context, Result}; -use itertools::Itertools; -use std::f32::consts::TAU; -use tracing_subscriber::{prelude::*, registry}; - use flax::{ + component, entity_ids, events::{EventKind, EventSubscriber}, - filter::{All, And, With}, - *, + BoxedSystem, CommandBuffer, Component, Debuggable, Entity, EntityBorrow, EntityBuilder, + EntityIds, Fetch, FetchExt, Mutable, Opt, OptOr, Query, QueryBorrow, Schedule, SharedResource, + System, World, }; +use itertools::Itertools; use macroquad::{ color::hsl_to_rgb, math::*, @@ -18,8 +17,11 @@ use macroquad::{ window::{clear_background, next_frame, screen_height, screen_width}, }; use rand::{rngs::StdRng, Rng, SeedableRng}; +use std::f32::consts::TAU; +use tracing_subscriber::{prelude::*, registry}; use tracing_tree::HierarchicalLayer; +// Declare the components that will be used. component! { position: Vec2 => [ Debuggable ], rotation: f32 => [ Debuggable ], @@ -57,45 +59,6 @@ component! { } -/// Macroquad has unsound race conditions, as such, use a mock shared -/// context -#[derive(Hash, Debug, Clone)] -struct GraphicsContext; - -#[derive(Debug, Clone)] -enum Shape { - Polygon { radius: f32, sides: u8 }, - Circle { radius: f32 }, - Triangle(Vec2, Vec2, Vec2), -} - -impl Shape { - pub fn draw(&self, view: &Mat3, pos: Vec2, rot: f32, color: Color) { - match *self { - Shape::Circle { radius } => { - let pos = view.transform_point2(pos); - let radius = view.transform_vector2(Vec2::splat(radius)).x; - draw_circle(pos.x, pos.y, radius, color) - } - Shape::Polygon { radius, sides } => { - let pos = view.transform_point2(pos); - let radius = view.transform_vector2(Vec2::splat(radius)).x; - - draw_poly(pos.x, pos.y, sides, radius, rot, color) - } - Shape::Triangle(v1, v2, v3) => { - let transform = *view * Mat3::from_scale_angle_translation(Vec2::ONE, rot, pos); - - let v1 = transform.transform_point2(v1); - let v2 = transform.transform_point2(v2); - let v3 = transform.transform_point2(v3); - - draw_triangle(v1, v2, v3, color) - } - } - } -} - #[macroquad::main("Asteroids")] async fn main() -> Result<()> { registry().with(HierarchicalLayer::default()).init(); @@ -115,6 +78,8 @@ async fn main() -> Result<()> { ); // Setup everything required for the game logic and physics + // + // Two different schedules will run independently of each other at different rates. let mut physics_schedule = Schedule::builder() .with_system(player_system(dt)) .with_system(camera_system(dt)) @@ -169,6 +134,7 @@ async fn main() -> Result<()> { const ASTEROID_SIZE: f32 = 40.0; +/// Create the central player ship fn create_player() -> EntityBuilder { Entity::builder() .set_default(position()) @@ -284,6 +250,7 @@ fn create_explosion( }) } +/// Updates each particle in the world fn particle_system() -> BoxedSystem { System::builder() .with_name("particle_system") @@ -301,6 +268,9 @@ fn particle_system() -> BoxedSystem { .boxed() } +/// System which makes the camera track the player smoothly. +/// +/// Uses two different queries, one for the player and one for the camera. fn camera_system(dt: f32) -> BoxedSystem { System::builder() .with(Query::new((position(), velocity())).with(player())) @@ -310,7 +280,7 @@ fn camera_system(dt: f32) -> BoxedSystem { camera().as_mut(), ))) .build( - move |mut players: QueryBorrow<(Component, Component), And>, + move |mut players: QueryBorrow<(Component, Component), _>, mut cameras: QueryBorrow<(Mutable, Mutable, Mutable)>| -> Result<()> { if let Some((player_pos, player_vel)) = players.first() { @@ -336,6 +306,44 @@ fn camera_system(dt: f32) -> BoxedSystem { .boxed() } +/// Macroquad has unsound race conditions, as such, use a mock shared +/// context +#[derive(Hash, Debug, Clone)] +struct GraphicsContext; + +#[derive(Debug, Clone)] +enum Shape { + Polygon { radius: f32, sides: u8 }, + Circle { radius: f32 }, + Triangle(Vec2, Vec2, Vec2), +} + +impl Shape { + pub fn draw(&self, view: &Mat3, pos: Vec2, rot: f32, color: Color) { + match *self { + Shape::Circle { radius } => { + let pos = view.transform_point2(pos); + let radius = view.transform_vector2(Vec2::splat(radius)).x; + draw_circle(pos.x, pos.y, radius, color) + } + Shape::Polygon { radius, sides } => { + let pos = view.transform_point2(pos); + let radius = view.transform_vector2(Vec2::splat(radius)).x; + + draw_poly(pos.x, pos.y, sides, radius, rot, color) + } + Shape::Triangle(v1, v2, v3) => { + let transform = *view * Mat3::from_scale_angle_translation(Vec2::ONE, rot, pos); + + let v1 = transform.transform_point2(v1); + let v2 = transform.transform_point2(v2); + let v3 = transform.transform_point2(v3); + + draw_triangle(v1, v2, v3, color) + } + } + } +} struct Collision { a: Entity, b: Entity, @@ -383,6 +391,7 @@ fn lifetime_system(dt: f32) -> BoxedSystem { .boxed() } +/// N-body collision system fn collision_system() -> BoxedSystem { System::builder() .with_name("collision_system") @@ -468,7 +477,11 @@ const SHIP_TURN: f32 = 2.0; const WEAPON_COOLDOWN: f32 = 0.2; const PLUME_COOLDOWN: f32 = 0.02; +/// Sometimes a query can grow to a very large tuple. Using a struct helps with naming the fields +/// and refactoring. #[derive(Fetch)] +// Ensures the fetch item is debuggable +#[fetch(Debug)] struct PlayerQuery { id: EntityIds, player: Component<()>, @@ -509,6 +522,7 @@ fn player_system(dt: f32) -> BoxedSystem { current_plume_cooldown -= dt; for player in &mut q { + dbg!(&player); *player.invincibility = (*player.invincibility - 0.02).max(0.0); *player.difficulty = (*player.material * 0.001).max(1.0); @@ -552,6 +566,8 @@ fn player_system(dt: f32) -> BoxedSystem { ) .boxed() } + +/// Kill of out of bounds entities relative to the player fn despawn_out_of_bounds() -> BoxedSystem { System::builder() .with_name("despawn_out_of_bounds") @@ -572,6 +588,7 @@ fn despawn_out_of_bounds() -> BoxedSystem { .boxed() } +/// Deferred despawn dead entities (including players) fn despawn_dead() -> BoxedSystem { System::builder() .with_name("despawn_dead") @@ -609,6 +626,7 @@ fn despawn_dead() -> BoxedSystem { .boxed() } +/// Spawn random asteroids near the player up to a maximum concurrent count fn spawn_asteroids(max_count: usize) -> BoxedSystem { System::builder() .with_name("spawn_asteroids") @@ -711,6 +729,7 @@ impl TransformQuery { } } +/// Draw each entity with a shape on the screen fn draw_shapes() -> BoxedSystem { System::builder() .with_name("draw_asteroids") @@ -734,6 +753,10 @@ fn draw_shapes() -> BoxedSystem { .boxed() } +/// Draws the score board by querying the ecs world for the data it needs. +/// +/// For more complex Uis, consider having a look at [`violet`](https://github.com/ten3roberts/violet) +/// which uses `flax` fn draw_ui() -> BoxedSystem { System::builder() .with_name("draw_ui") diff --git a/src/filter/mod.rs b/src/filter/mod.rs index c1189997..20d7b429 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -40,7 +40,7 @@ macro_rules! gen_bitops { type Output = And; fn bitand(self, rhs: R) -> Self::Output { - And::new(self, rhs) + And(self, rhs) } } @@ -663,7 +663,7 @@ mod tests { let a = PreparedKindFilter::new((), changes_1.as_slice(), 1); let b = PreparedKindFilter::new((), changes_2.as_slice(), 2); - let filter = And { left: a, right: b }; + let filter = And(a, b); // Use a brute force BTreeSet for solving it let chunks_set = slots diff --git a/src/filter/set.rs b/src/filter/set.rs index 4ec4b158..3006270b 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -10,19 +10,14 @@ use core::{ ops, }; -#[derive(Debug, Clone)] /// And combinator -pub struct And { - pub(crate) left: L, - pub(crate) right: R, -} - -impl And { - /// Creates a new and filter - pub fn new(left: L, right: R) -> Self { - Self { left, right } - } -} +/// +/// **Note**: A normal tuple will and-combine and can thus be used instead. +/// +/// The difference is that additional *bitops* such as `|` and `~` for convenience works on this type +/// to combine it with other filters. This is because of orphan rules. +#[derive(Debug, Clone)] +pub struct And(pub L, pub R); impl<'q, L, R> FetchItem<'q> for And where @@ -43,32 +38,29 @@ where #[inline] fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { - Some(And { - left: self.left.prepare(data)?, - right: self.right.prepare(data)?, - }) + Some(And(self.0.prepare(data)?, self.1.prepare(data)?)) } fn filter_arch(&self, arch: &Archetype) -> bool { - self.left.filter_arch(arch) && self.right.filter_arch(arch) + self.0.filter_arch(arch) && self.1.filter_arch(arch) } fn access(&self, data: FetchAccessData, dst: &mut Vec) { - self.left.access(data, dst); - self.right.access(data, dst); + self.0.access(data, dst); + self.1.access(data, dst); } fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.left.describe(f)?; + self.0.describe(f)?; f.write_str(" & ")?; - self.right.describe(f)?; + self.1.describe(f)?; Ok(()) } fn searcher(&self, searcher: &mut crate::ArchetypeSearcher) { - self.left.searcher(searcher); - self.right.searcher(searcher); + self.0.searcher(searcher); + self.1.searcher(searcher); } } @@ -81,19 +73,19 @@ where #[inline] unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - (self.left.fetch(slot), self.right.fetch(slot)) + (self.0.fetch(slot), self.1.fetch(slot)) } fn set_visited(&mut self, slots: Slice) { - self.left.set_visited(slots); - self.right.set_visited(slots); + self.0.set_visited(slots); + self.1.set_visited(slots); } #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let l = self.left.filter_slots(slots); + let l = self.0.filter_slots(slots); - self.right.filter_slots(l) + self.1.filter_slots(l) } } diff --git a/src/query/mod.rs b/src/query/mod.rs index c998604c..67db51b5 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -15,8 +15,9 @@ use core::fmt::Debug; use crate::{ archetype::Slot, fetch::FmtQuery, - filter::{All, And, BatchSize, Filtered, With, WithRelation, Without, WithoutRelation}, + filter::{All, BatchSize, Filtered, With, WithRelation, Without, WithoutRelation}, system::Access, + util::TupleCombine, Component, ComponentValue, Entity, Fetch, FetchItem, RelationExt, World, }; use alloc::vec::Vec; @@ -192,11 +193,14 @@ where { /// Adds a new filter to the query. /// This filter is and:ed with the existing filters. - pub fn filter(self, filter: G) -> Query, S> { + pub fn filter(self, filter: G) -> Query + where + F: TupleCombine, + { Query { fetch: Filtered::new( self.fetch.fetch, - And::new(self.fetch.filter, filter), + self.fetch.filter.push_right(filter), self.fetch.include_components, ), change_tick: self.change_tick, @@ -206,7 +210,10 @@ where } /// Limits the size of each batch using [`QueryBorrow::iter_batched`] - pub fn batch_size(self, size: Slot) -> Query, S> { + pub fn batch_size(self, size: Slot) -> Query + where + F: TupleCombine, + { self.filter(BatchSize(size)) } @@ -214,7 +221,10 @@ where pub fn with_relation( self, rel: impl RelationExt, - ) -> Query, S> { + ) -> Query + where + F: TupleCombine, + { self.filter(rel.with_relation()) } @@ -222,20 +232,26 @@ where pub fn without_relation( self, rel: impl RelationExt, - ) -> Query, S> { + ) -> Query + where + F: TupleCombine, + { self.filter(rel.without_relation()) } /// Shortcut for filter(without) - pub fn without( - self, - component: Component, - ) -> Query, S> { + pub fn without(self, component: Component) -> Query + where + F: TupleCombine, + { self.filter(component.without()) } /// Shortcut for filter(with) - pub fn with(self, component: Component) -> Query, S> { + pub fn with(self, component: Component) -> Query + where + F: TupleCombine, + { self.filter(component.with()) } diff --git a/src/query/walk.rs b/src/query/walk.rs index 9666e7e5..5034b685 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -50,7 +50,7 @@ where GraphQuery { fetch: Filtered::new( self.fetch.fetch, - And::new(self.fetch.filter, filter), + And(self.fetch.filter, filter), self.fetch.include_components, ), relation: self.relation, diff --git a/src/serialize/ser.rs b/src/serialize/ser.rs index 6a0e5a75..25c2370b 100644 --- a/src/serialize/ser.rs +++ b/src/serialize/ser.rs @@ -86,7 +86,7 @@ where pub fn with_filter(self, filter: G) -> SerializeBuilder> { SerializeBuilder { slots: self.slots, - filter: And::new(self.filter, filter), + filter: And(self.filter, filter), } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 705979f5..6a214a48 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,6 +1,8 @@ // Needed in macro expansion #![allow(unused_parens)] +use crate::filter::All; + /// Allows pushing onto a tuple pub trait TupleCombine { /// The resulting right push @@ -76,3 +78,17 @@ mod test { assert_eq!(t, (5,)); } } + +impl TupleCombine for All { + type PushRight = (All, T); + + type PushLeft = (T, All); + + fn push_right(self, value: T) -> Self::PushRight { + (self, value) + } + + fn push_left(self, value: T) -> Self::PushLeft { + (value, self) + } +} From a566303281d745d74b9f87b31e4de6f41dddc0ef Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Tue, 27 Jun 2023 23:40:04 +0200 Subject: [PATCH 06/52] fix: typos in README.md --- README.md | 14 +++++++------- src/lib.rs | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a0ba617c..22b8d227 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ See a live demo of asteroids using wasm [here](https://ten3roberts.github.io/fla let mut query = Query::new((health().as_mut(), regen())); - // Apply health regen for all match entites + // Apply health regeneration for all matched entites for (health, regen) in &mut query.borrow(&world) { *health = (*health + regen).min(100.0); } @@ -134,16 +134,16 @@ let child1 = Entity::builder() ## Comparison to other ECS -Compared to other ecs implementations, a component is simply another `Entity` +Compared to other ECS implementations, a component is simply another `Entity` identifier to which data is attached. This means the same "type" can be added to an entity multiple times. A limitation of existing implementations such as [specs](https://github.com/amethyst/specs), [planck](https://github.com/jojolepro/planck_ecs/), or [hecs](https://github.com/Ralith/hecs) is that newtype wrappers need to be created to allow components of the same inner type to coexist. This leads to having to forward all trait implementations trough e.g -`derive-more` or dereferencing the newtypes during usage. +`derive-more` or dereferencing the *newtypes* during usage. -By making components separate from the type the components can work together without deref or +By making components separate from the type the components can work together without `deref` or newtype construction. ```rust @@ -165,7 +165,7 @@ inserted as components. This fixes subtle bugs which come by having the type dictate the component, such as inserting an `Arc` instead of just `Type`, which leads to subsequent systems not finding the `Type` on the entity. -Having statically declared componenents makes the rust type system disallow +Using statically declared components makes the rust type system disallow these cases and catches these bugs earlier. ## Motivation @@ -175,12 +175,12 @@ library, and the author [Ralith](https://github.com/Ralith) has been wonderful i contributions and inquiries. Despite this, I often made subtle bugs with *similar* types. The game engine was -cluttered with gigantic newtypes for `Velocity`, `Position` with many deref +cluttered with gigantic newtypes for `Velocity`, `Position` with many *deref* coercions in order to coexist. ## Unsafe This library makes use of unsafe for type erasure and the allocation in storage -of ComponentBuffers and Archetypes. +of `ComponentBuffer`s and `Archetype`s. diff --git a/src/lib.rs b/src/lib.rs index c332c29a..47b746ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ //! //! let mut query = Query::new((health().as_mut(), regen())); //! -//! // Apply health regen for all match entites +//! // Apply health regeneration for all matched entites //! for (health, regen) in &mut query.borrow(&world) { //! *health = (*health + regen).min(100.0); //! } @@ -137,16 +137,16 @@ //! //! ## Comparison to other ECS //! -//! Compared to other ecs implementations, a component is simply another `Entity` +//! Compared to other ECS implementations, a component is simply another `Entity` //! identifier to which data is attached. This means the same "type" can be added to //! an entity multiple times. //! //! A limitation of existing implementations such as [specs](https://github.com/amethyst/specs), [planck](https://github.com/jojolepro/planck_ecs/), or [hecs](https://github.com/Ralith/hecs) is that newtype wrappers need to be created to allow components of the same inner type to coexist. //! //! This leads to having to forward all trait implementations trough e.g -//! `derive-more` or dereferencing the newtypes during usage. +//! `derive-more` or dereferencing the *newtypes* during usage. //! -//! By making components separate from the type the components can work together without deref or +//! By making components separate from the type the components can work together without `deref` or //! newtype construction. //! //! ```rust @@ -175,7 +175,7 @@ //! dictate the component, such as inserting an `Arc` instead of just `Type`, //! which leads to subsequent systems not finding the `Type` on the entity. //! -//! Having statically declared componenents makes the rust type system disallow +//! Using statically declared components makes the rust type system disallow //! these cases and catches these bugs earlier. //! //! ## Motivation @@ -185,12 +185,12 @@ //! contributions and inquiries. //! //! Despite this, I often made subtle bugs with *similar* types. The game engine was -//! cluttered with gigantic newtypes for `Velocity`, `Position` with many deref +//! cluttered with gigantic newtypes for `Velocity`, `Position` with many *deref* //! coercions in order to coexist. //! //! ## Unsafe //! This library makes use of unsafe for type erasure and the allocation in storage -//! of ComponentBuffers and Archetypes. +//! of `ComponentBuffer`s and `Archetype`s. #![warn(missing_docs)] #![deny(rustdoc::broken_intra_doc_links)] From ce9b9d3c8994fa3153ae1f23b356afb36603c5c7 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Thu, 29 Jun 2023 23:34:52 +0200 Subject: [PATCH 07/52] feat: use trait to support Union filter for foreign types --- README.md | 5 +- flax-derive/src/lib.rs | 60 +++++++++++++---- src/archetype/slice.rs | 21 +++--- src/fetch/mod.rs | 65 +++++++++--------- src/filter/change.rs | 1 + src/filter/constant.rs | 7 ++ src/filter/mod.rs | 1 + src/filter/set.rs | 147 +++++++++++++++++++++++++++-------------- src/lib.rs | 5 +- 9 files changed, 203 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 22b8d227..981e8c91 100644 --- a/README.md +++ b/README.md @@ -159,10 +159,9 @@ let dt = 0.1; *pos += *vel * dt; ``` -On a further note, since the components have to be declared beforehand (not -always true, more on that later), it limits the amount of types which can be +On a further note, since the components have to be declared beforehand, it limits the amount of types which can be inserted as components. This fixes subtle bugs which come by having the type -dictate the component, such as inserting an `Arc` instead of just `Type`, +dictate the component, such as using an `Arc` instead of just `Type`, which leads to subsequent systems not finding the `Type` on the entity. Using statically declared components makes the rust type system disallow diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 78486363..9c2fb3d1 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use proc_macro2::{Span, TokenStream}; use proc_macro_crate::FoundCrate; -use quote::quote; +use quote::{format_ident, quote}; use syn::{Attribute, DataStruct, DeriveInput, Error, Ident, MetaList, Result, Type, Visibility}; /// ```rust,ignore @@ -77,15 +77,23 @@ fn derive_data_struct( &field_types, ); - Ok(quote! { + // let union_derive = derive_union( + // &crate_name, + // &input.vis, + // name, + // &item_name, + // &prepared_name, + // &field_names, + // &field_types, + // ); + Ok(quote! { #item_derive #prepared_derive #[automatically_derived] impl<'w> #crate_name::Fetch<'w> for #name - where #(#field_types: #crate_name::Fetch<'w>,)* { const MUTABLE: bool = #(<#field_types as #crate_name::Fetch<'w>>::MUTABLE)||*; @@ -94,7 +102,7 @@ fn derive_data_struct( fn prepare( &'w self, data: #crate_name::fetch::FetchPrepareData<'w> ) -> Option { Some(Self::Prepared { - #(#field_names: self.#field_names.prepare(data)?,)* + #(#field_names: #crate_name::Fetch::prepare(&self.#field_names, data)?,)* }) } @@ -134,17 +142,43 @@ fn derive_data_struct( } } -/// Derive the yielded Item type for a Fetch -fn derive_item_struct<'a>( +/// Implements the filtering of the struct fields using a set union +fn derive_union( + crate_name: &Ident, + vis: &Visibility, + name: &Ident, + item_name: &Ident, + prepared_name: &Ident, + field_names: &[&Ident], + field_types: &[&Type], +) -> TokenStream { + let union_msg = format!("The union fetch for {name}"); + let unioned = format_ident!("{name}Union"); + + quote! { + #[doc = #union_msg] + #vis struct #unioned(T); + + #[automatically_derived] + impl<'q, T> #crate_name::fetch::UnionFilter<'q> for #unioned where T: #crate_name::fetch::PreparedFetch<'q> { + unsafe fn filter_union(&mut self, slots: Slice) -> Slice { + #crate_name::fetch::UnionFilter::filter_slots(&mut #crate_name::filter::Union(#(&mut self.#field_names,)*), slots) + } + } + } +} + +/// Derive the returned Item type for a Fetch +fn derive_item_struct( crate_name: &Ident, attrs: &Attrs, vis: &Visibility, name: &Ident, item_name: &Ident, - field_names: &[&'a Ident], - field_types: &[&'a Type], + field_names: &[&Ident], + field_types: &[&Type], ) -> TokenStream { - let msg = format!("The item yielded by {name}"); + let msg = format!("The item returned by {name}"); let extras = match &attrs.extras { Some(extras) => { @@ -168,14 +202,14 @@ fn derive_item_struct<'a>( } } -fn derive_prepared_struct<'a>( +fn derive_prepared_struct( crate_name: &Ident, vis: &Visibility, name: &Ident, item_name: &Ident, prepared_name: &Ident, - field_names: &[&'a Ident], - field_types: &[&'a Type], + field_names: &[&Ident], + field_types: &[&Type], ) -> TokenStream { let msg = format!("The prepared fetch for {name}"); @@ -203,7 +237,7 @@ fn derive_prepared_struct<'a>( #[inline] fn set_visited(&mut self, slots: #crate_name::archetype::Slice) { - #(self.#field_names.set_visited(slots);)* + #(#crate_name::fetch::PreparedFetch::set_visited(&mut self.#field_names, slots);)* } } } diff --git a/src/archetype/slice.rs b/src/archetype/slice.rs index 9c8651e2..3b2b8f11 100644 --- a/src/archetype/slice.rs +++ b/src/archetype/slice.rs @@ -13,13 +13,13 @@ pub struct Slice { impl Slice { /// Creates a new slice of entity slots. - #[inline] - pub fn new(start: Slot, end: Slot) -> Self { + #[inline(always)] + pub const fn new(start: Slot, end: Slot) -> Self { Self { start, end } } #[inline] - pub(crate) fn single(slot: Slot) -> Slice { + pub(crate) const fn single(slot: Slot) -> Slice { Self::new(slot, slot + 1) } @@ -53,11 +53,15 @@ impl Slice { #[inline(always)] /// Returns the intersection of self and other - pub fn intersect(&self, other: &Self) -> Self { - let start = self.start.max(other.start); + pub fn intersect(&self, other: &Self) -> Option { let end = self.end.min(other.end); + let start = self.start.max(other.start).min(end); - Self::new(start, end) + if start == end { + None + } else { + Some(Self::new(start, end)) + } } /// Returns the union of two slices if contiguous. @@ -165,8 +169,9 @@ mod tests { let i = a.intersect(&b); let i2 = b.intersect(&a); - assert_eq!(i, Slice::new(10, 38)); - assert_eq!(i2, Slice::new(10, 38)); + assert_eq!(i, Some(Slice::new(10, 38))); + assert_eq!(i2, Some(Slice::new(10, 38))); + assert_eq!(Slice::new(10, 20).intersect(&Slice::new(0, 2)), None); let u = a.union(&b); diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 50958295..1d546fa5 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -30,6 +30,7 @@ pub use component_mut::*; pub use entity_ref::*; pub use ext::FetchExt; pub use maybe_mut::{MaybeMut, MutGuard}; +pub use modified::ModifiedFetch; pub use opt::*; pub use read_only::*; pub use relations::{relations_like, Relations, RelationsIter}; @@ -147,12 +148,21 @@ pub trait PreparedFetch<'q> { slots } - /// Do something for a a slice of entity slots which have been visited, such + /// Do something for a slice of entity slots which have been visited, such /// as updating change tracking for mutable queries. #[inline] fn set_visited(&mut self, _slots: Slice) {} } +/// Allows filtering the constituent parts of a fetch using a set union +pub trait UnionFilter<'q> { + // Filter the slots using a union operation of the constituent part + /// + /// # Safety + /// See: [`PreparedFetch::filter_slots`] + unsafe fn filter_union(&mut self, slots: Slice) -> Slice; +} + impl<'q, F> PreparedFetch<'q> for &'q mut F where F: PreparedFetch<'q>, @@ -176,6 +186,12 @@ impl<'q> FetchItem<'q> for () { type Item = (); } +impl<'q> UnionFilter<'q> for () { + unsafe fn filter_union(&mut self, slots: Slice) -> Slice { + slots + } +} + impl<'w> Fetch<'w> for () { const MUTABLE: bool = false; @@ -328,45 +344,28 @@ macro_rules! tuple_impl { #[inline] unsafe fn filter_slots(&mut self, mut slots: Slice) -> Slice { - // let mut start = slots.start; - - // while !slots.is_empty() { - // let v = slots; - - // $( let v = self.$idx.filter_slots(v);)* - - // if !v.is_empty() || v.start == slots.end { - // return v; - // } - - // slots.start = v.start; - // } - // slots $( slots = self.$idx.filter_slots(slots); )* slots - // ( $( - // { - // let v = self.$idx.filter_slots(slots); - // start = start.max(v.start); - // v - // }, - // )*); - - // let mut u = slots; - - // // Clamp to end bound - // start = start.min(slots.end); - // slots.start = start; + } + } - // $( - // u = u.intersect(&self.$idx.filter_slots(slots)); - // )* + impl<'q, $($ty, )*> UnionFilter<'q> for ($($ty,)*) + where $($ty: PreparedFetch<'q>,)* + { - // u + #[inline] + unsafe fn filter_union(&mut self, slots: Slice) -> Slice { + [ + // Don't leak union into this + $( self.$idx.filter_slots(slots)),* + ] + .into_iter() + .min() + .unwrap_or_default() } } @@ -393,7 +392,7 @@ macro_rules! tuple_impl { #[inline] fn access(&self, data: FetchAccessData, dst: &mut Vec) { - $( (self.$idx).access(data, dst);)* + $( (self.$idx).access(data, dst);)* } #[inline] diff --git a/src/filter/change.rs b/src/filter/change.rs index c99fb672..5d222a43 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -181,6 +181,7 @@ where }; cur.intersect(&slots) + .unwrap_or(Slice::new(slots.end, slots.end)) } fn set_visited(&mut self, slots: Slice) { diff --git a/src/filter/constant.rs b/src/filter/constant.rs index 7cb7dfc2..689edb4d 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -41,6 +41,12 @@ impl<'q> PreparedFetch<'q> for Nothing { type Item = (); unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} + + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + Slice::new(slots.end, slots.end) + } + + fn set_visited(&mut self, _slots: Slice) {} } /// Yields all entities @@ -111,6 +117,7 @@ impl<'q> PreparedFetch<'q> for Slice { #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { self.intersect(&slots) + .unwrap_or(Slice::new(slots.end, slots.end)) } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 20d7b429..86b4a93f 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -200,6 +200,7 @@ where if self.slots.is_empty() { return None; } + while !self.slots.is_empty() { // Safety // The yielded slots are split off of `self.slots` diff --git a/src/filter/set.rs b/src/filter/set.rs index 3006270b..690cd695 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -1,6 +1,6 @@ use crate::{ archetype::{Archetype, Slice, Slot}, - fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch}, + fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, UnionFilter}, system::Access, Fetch, FetchItem, }; @@ -182,66 +182,69 @@ impl ops::Not for Not { /// changed. pub struct Union(pub T); -macro_rules! tuple_impl { - ($($idx: tt => $ty: ident),*) => { - // Union - impl<'w, $($ty: Fetch<'w>,)*> Fetch<'w> for Union<($($ty,)*)> { - const MUTABLE: bool = $($ty::MUTABLE )||*; - - type Prepared = Union<($($ty::Prepared,)*)>; - - fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { - let inner = &self.0; - Some(Union(($(inner.$idx.prepare(data)?,)*))) - } +impl<'q, T> FetchItem<'q> for Union +where + T: FetchItem<'q>, +{ + type Item = T::Item; +} - fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { - let inner = &self.0; - $(inner.$idx.filter_arch(arch))&&* - } +impl<'w, T> Fetch<'w> for Union +where + T: Fetch<'w>, + T::Prepared: for<'q> UnionFilter<'q>, +{ + const MUTABLE: bool = T::MUTABLE; - fn access(&self, data: super::FetchAccessData, dst: &mut alloc::vec::Vec) { - let inner = &self.0; - $(inner.$idx.access(data, dst);)* - } + type Prepared = Union; - fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let inner = &self.0; - let mut s = f.debug_tuple("Union"); - $(s.field(&FmtQuery(&inner.$idx));)* + fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { + Some(Union(self.0.prepare(data)?)) + } - s.finish() - } - } + fn filter_arch(&self, arch: &Archetype) -> bool { + self.0.filter_arch(arch) + } + fn access(&self, data: FetchAccessData, dst: &mut Vec) { + self.0.access(data, dst) + } - impl<'w, $($ty: PreparedFetch<'w>,)* > PreparedFetch<'w> for Union<($($ty,)*)> { - type Item = ($($ty::Item,)*); + fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_tuple("Union").field(&FmtQuery(&self.0)).finish() + } +} - unsafe fn fetch(&'w mut self, slot: usize) -> Self::Item { - let inner = &mut self.0; - ($(inner.$idx.fetch(slot), )*) - } +impl<'q, T> UnionFilter<'q> for Union +where + T: UnionFilter<'q>, +{ + unsafe fn filter_union(&mut self, slots: Slice) -> Slice { + self.0.filter_union(slots) + } +} - unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { - let inner = &mut self.0; +impl<'q, T> PreparedFetch<'q> for Union +where + T: PreparedFetch<'q> + UnionFilter<'q>, +{ + type Item = T::Item; - [$(inner.$idx.filter_slots(slots)),*] - .into_iter() - .min() - .unwrap_or_default() - } + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + self.0.fetch(slot) + } - fn set_visited(&mut self, slots: crate::archetype::Slice) { - let inner = &mut self.0; - $(inner.$idx.set_visited(slots);)* - } - } + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + self.filter_union(slots) + } - impl<'q, $($ty: FetchItem<'q>,)*> FetchItem<'q> for Union<($($ty,)*)> { - type Item = ($($ty::Item,)*); - } + fn set_visited(&mut self, slots: Slice) { + self.0.set_visited(slots) + } +} +macro_rules! tuple_impl { + ($($idx: tt => $ty: ident),*) => { // Or impl<'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { type Item = (); @@ -303,6 +306,23 @@ macro_rules! tuple_impl { } } + + + impl<'q, $($ty, )*> UnionFilter<'q> for Or<($(Option<$ty>,)*)> + where $($ty: PreparedFetch<'q>,)* + { + unsafe fn filter_union(&mut self, slots: Slice) -> Slice { + let inner = &mut self.0; + + [ + $( inner.$idx.filter_slots(slots)),* + ] + .into_iter() + .min() + .unwrap_or_default() + + } + } }; @@ -315,3 +335,32 @@ tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D } tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E } tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F } tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H } + +#[cfg(test)] +mod tests { + use itertools::Itertools; + + use crate::{ + filter::{All, FilterIter, Nothing}, + World, + }; + + use super::*; + + #[test] + fn union() { + let fetch = Union(( + Slice::new(0, 2), + Nothing, + Slice::new(7, 16), + Slice::new(3, 10), + )); + + let fetch = FilterIter::new(Slice::new(0, 100), fetch); + + assert_eq!( + fetch.collect_vec(), + [Slice::new(0, 2), Slice::new(3, 10), Slice::new(10, 16)] + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 47b746ae..14890e43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,10 +169,9 @@ //! # } //! ``` //! -//! On a further note, since the components have to be declared beforehand (not -//! always true, more on that later), it limits the amount of types which can be +//! On a further note, since the components have to be declared beforehand, it limits the amount of types which can be //! inserted as components. This fixes subtle bugs which come by having the type -//! dictate the component, such as inserting an `Arc` instead of just `Type`, +//! dictate the component, such as using an `Arc` instead of just `Type`, //! which leads to subsequent systems not finding the `Type` on the entity. //! //! Using statically declared components makes the rust type system disallow From 41a5347c38818d5c232708e84bb496744463a257 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 1 Jul 2023 18:13:26 +0200 Subject: [PATCH 08/52] feat: make derive support generics --- .nvim-settings.json | 9 + flax-derive/src/lib.rs | 489 ++++++++++++++++++++++++++++++---------- src/fetch/modified.rs | 84 ++++++- tests/derive_generic.rs | 58 +++++ 4 files changed, 515 insertions(+), 125 deletions(-) create mode 100644 .nvim-settings.json create mode 100644 tests/derive_generic.rs diff --git a/.nvim-settings.json b/.nvim-settings.json new file mode 100644 index 00000000..695cbd31 --- /dev/null +++ b/.nvim-settings.json @@ -0,0 +1,9 @@ +{ + "lsp": { + "rust-analyzer": { + "cargo": { + "features": "all" + } + } + } +} diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 9c2fb3d1..668383de 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -2,7 +2,11 @@ use itertools::Itertools; use proc_macro2::{Span, TokenStream}; use proc_macro_crate::FoundCrate; use quote::{format_ident, quote}; -use syn::{Attribute, DataStruct, DeriveInput, Error, Ident, MetaList, Result, Type, Visibility}; +use syn::{ + token::{Gt, Lt}, + Attribute, DataStruct, DeriveInput, Error, GenericParam, Generics, Ident, ImplGenerics, + Lifetime, LifetimeParam, MetaList, Result, Type, TypeGenerics, TypeParam, Visibility, +}; /// ```rust,ignore /// use glam::*; @@ -42,93 +46,30 @@ fn derive_data_struct( data: &DataStruct, ) -> Result { let name = &input.ident; - let item_name = Ident::new(&format!("{}Item", name), Span::call_site()); - let prepared_name = Ident::new(&format!("Prepared{}", name), Span::call_site()); let attrs = Attrs::get(&input.attrs)?; match data.fields { syn::Fields::Named(ref fields) => { let fields = &fields.named; - let field_names = fields - .iter() - .map(|v| v.ident.as_ref().unwrap()) - .collect_vec(); - - let field_types = fields.iter().map(|v| &v.ty).collect_vec(); - - let item_derive = derive_item_struct( - &crate_name, - &attrs, - &input.vis, - name, - &item_name, - &field_names, - &field_types, - ); - - let prepared_derive = derive_prepared_struct( - &crate_name, - &input.vis, - name, - &item_name, - &prepared_name, - &field_names, - &field_types, - ); - - // let union_derive = derive_union( - // &crate_name, - // &input.vis, - // name, - // &item_name, - // &prepared_name, - // &field_names, - // &field_types, - // ); + let params = Params::new(&crate_name, &input.vis, input, &attrs); - Ok(quote! { - #item_derive + let prepared_derive = derive_prepared_struct(¶ms); - #prepared_derive + let union_derive = derive_union(¶ms); - #[automatically_derived] - impl<'w> #crate_name::Fetch<'w> for #name - { - const MUTABLE: bool = #(<#field_types as #crate_name::Fetch<'w>>::MUTABLE)||*; - - type Prepared = #prepared_name<'w>; - #[inline] - fn prepare( &'w self, data: #crate_name::fetch::FetchPrepareData<'w> - ) -> Option { - Some(Self::Prepared { - #(#field_names: #crate_name::Fetch::prepare(&self.#field_names, data)?,)* - }) - } + let transform_modified = derive_modified(¶ms); - #[inline] - fn filter_arch(&self, arch: &#crate_name::archetype::Archetype) -> bool { - #(self.#field_names.filter_arch(arch))&&* - } + let fetch_derive = derive_fetch_struct(¶ms); - fn describe(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - let mut s = f.debug_struct(stringify!(#name)); - - #( - s.field(stringify!(#field_names), &#crate_name::fetch::FmtQuery(&self.#field_names)); - )* + Ok(quote! { + #fetch_derive - s.finish() - } + #prepared_derive - fn access(&self, data: #crate_name::fetch::FetchAccessData, dst: &mut Vec<#crate_name::system::Access>) { - #(self.#field_names.access(data, dst));* - } + #union_derive - fn searcher(&self, searcher: &mut #crate_name::query::ArchetypeSearcher) { - #(self.#field_names.searcher(searcher);)* - } - } + // #transform_modified }) } syn::Fields::Unnamed(_) => Err(Error::new( @@ -142,43 +83,232 @@ fn derive_data_struct( } } -/// Implements the filtering of the struct fields using a set union -fn derive_union( - crate_name: &Ident, - vis: &Visibility, - name: &Ident, - item_name: &Ident, - prepared_name: &Ident, - field_names: &[&Ident], - field_types: &[&Type], -) -> TokenStream { - let union_msg = format!("The union fetch for {name}"); - let unioned = format_ident!("{name}Union"); +fn derive_fetch_struct(params: &Params) -> TokenStream { + let Params { + crate_name, + vis, + fetch_name, + item_name, + prepared_name, + generics, + q_generics, + field_names, + field_types, + w_lf, + q_lf, + attrs, + .. + } = params; + + let item_ty = params.item_ty(); + let item_impl = params.item_impl(); + let item_msg = format!("The item returned by {fetch_name}"); + + let prep_ty = params.prepared_ty(); + + let extras = match &attrs.extras { + Some(extras) => { + let nested = &extras.tokens; + quote! { #[derive(#nested)]} + } + None => quote! {}, + }; + + let fetch_impl = params.fetch_impl(); + let fetch_ty = params.fetch_ty(); + + let msg = format!("The item returned by {fetch_name}"); + + let extras = match &attrs.extras { + Some(extras) => { + let nested = &extras.tokens; + quote! { #[derive(#nested)]} + } + None => quote! {}, + }; quote! { - #[doc = #union_msg] - #vis struct #unioned(T); + #[doc = #item_msg] + #extras + #vis struct #item_name #q_generics { + #(#field_names: <#field_types as #crate_name::fetch::FetchItem<#q_lf>>::Item,)* + } + + // #[automatically_derived] + impl #item_impl #crate_name::fetch::FetchItem<#q_lf> for #fetch_name #fetch_ty { + type Item = #item_name #item_ty; + } #[automatically_derived] - impl<'q, T> #crate_name::fetch::UnionFilter<'q> for #unioned where T: #crate_name::fetch::PreparedFetch<'q> { - unsafe fn filter_union(&mut self, slots: Slice) -> Slice { - #crate_name::fetch::UnionFilter::filter_slots(&mut #crate_name::filter::Union(#(&mut self.#field_names,)*), slots) + impl #fetch_impl #crate_name::Fetch<#w_lf> for #fetch_name #fetch_ty + where #(#field_types: #crate_name::Fetch<#w_lf>,)* + { + const MUTABLE: bool = #(<#field_types as #crate_name::Fetch <#w_lf>>::MUTABLE)||*; + + type Prepared = #prepared_name #prep_ty; + + #[inline] + fn prepare( &'w self, data: #crate_name::fetch::FetchPrepareData<'w> + ) -> Option { + Some(Self::Prepared { + #(#field_names: #crate_name::Fetch::prepare(&self.#field_names, data)?,)* + }) + } + + #[inline] + fn filter_arch(&self, arch: &#crate_name::archetype::Archetype) -> bool { + #(self.#field_names.filter_arch(arch))&&* + } + + fn describe(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + let mut s = f.debug_struct(stringify!(#fetch_name)); + + #( + s.field(stringify!(#field_names), &#crate_name::fetch::FmtQuery(&self.#field_names)); + )* + + s.finish() + } + + fn access(&self, data: #crate_name::fetch::FetchAccessData, dst: &mut Vec<#crate_name::system::Access>) { + #(self.#field_names.access(data, dst));* + } + + fn searcher(&self, searcher: &mut #crate_name::query::ArchetypeSearcher) { + #(self.#field_names.searcher(searcher);)* } } } } +fn prepend_generics(prepend: &[GenericParam], generics: &Generics) -> Generics { + let mut generics = generics.clone(); + generics.params = prepend + .into_iter() + .cloned() + .chain(generics.params) + .collect(); + + generics +} + +/// Implements the filtering of the struct fields using a set union +fn derive_union(params: &Params) -> TokenStream { + let ty_generics = params.fetch_ty(); + + let Params { + crate_name, + generics, + w_generics, + q_generics, + fetch_name, + field_types, + field_names, + .. + } = params; + + let (_, fetch_ty, _) = generics.split_for_impl(); + let (impl_generics, _, _) = q_generics.split_for_impl(); + + quote! { + // #[automatically_derived] + // impl #impl_generics #crate_name::fetch::UnionFilter<'q> for #fetch_name #fetch_ty where #(#field_types: for<'x> #crate_name::fetch::PreparedFetch<'x>,)* { + // unsafe fn filter_union(&mut self, slots: #crate_name::archetype::Slice) -> #crate_name::archetype::Slice { + // #crate_name::fetch::PreparedFetch::filter_slots(&mut #crate_name::filter::Union((#(&mut self.#field_names,)*)), slots) + // } + // } + } +} + +/// Implements the filtering of the struct fields using a set union +fn derive_modified(params: &Params) -> TokenStream { + let Params { + crate_name, + vis, + fetch_name, + item_name, + prepared_name, + generics, + field_names, + field_types, + w_lf, + q_lf, + attrs, + .. + } = params; + + // Replace all the fields with generics to allow transforming into different types + let ty_generics = ('a'..='z') + .map(|c| format_ident!("{}", c)) + .map(|v| GenericParam::Type(TypeParam::from(v))) + .take(params.field_types.len()) + .collect_vec(); + + let transformed_name = format_ident!("{}Transformed", params.fetch_name); + let transformed_struct = quote! { + #vis struct #transformed_name<#(#ty_generics),*>{ + #(#field_names: #ty_generics,)* + } + }; + + let input = + syn::parse2::(transformed_struct).expect("Generated struct is always valid"); + + let transformed_params = Params::new(crate_name, vis, &input, attrs); + + let prepared = derive_prepared_struct(&transformed_params); + + // Replace all the fields with generics to allow transforming into different types + let generics_params = ('a'..='z') + .map(|c| format_ident!("{}", c)) + .map(|v| GenericParam::Type(TypeParam::from(v))) + .take(params.field_types.len()) + .collect(); + + let generics = Generics { + lt_token: Some(Lt(Span::call_site())), + params: generics_params, + gt_token: Some(Gt(Span::call_site())), + where_clause: None, + }; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let fetch = derive_fetch_struct(&transformed_params); + + quote! { + // #vis struct #transformed #ty_generics { + // #(#field_names: #generics,)* + // } + + // #fetch + + // #prepared + + // #[automatically_derived] + // impl #crate_name::fetch::ModifiedFetch for #name where #(#field_types: #crate_name::fetch::ModifiedFetch + for<'q> #crate_name::fetch::PreparedFetch<'q>,)* { + // type Modified = #crate_name::filter::Union<#transformed<#(<#field_types as #crate_name::fetch::ModifiedFetch>::Modified,)*>>; + // } + } +} + /// Derive the returned Item type for a Fetch -fn derive_item_struct( - crate_name: &Ident, - attrs: &Attrs, - vis: &Visibility, - name: &Ident, - item_name: &Ident, - field_names: &[&Ident], - field_types: &[&Type], -) -> TokenStream { - let msg = format!("The item returned by {name}"); +fn derive_item_struct(params: &Params) -> TokenStream { + let Params { + crate_name, + vis, + fetch_name, + item_name, + prepared_name, + generics, + field_names, + field_types, + w_lf, + q_lf, + attrs, + .. + } = params; + + let msg = format!("The item returned by {fetch_name}"); let extras = match &attrs.extras { Some(extras) => { @@ -188,40 +318,51 @@ fn derive_item_struct( None => quote! {}, }; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let item_ty = params.item_ty(); + quote! { #[doc = #msg] #extras - #vis struct #item_name<'q> { - #(#field_names: <#field_types as #crate_name::fetch::FetchItem<'q>>::Item,)* - } - - #[automatically_derived] - impl<'q> #crate_name::fetch::FetchItem<'q> for #name { - type Item = #item_name<'q>; + #vis struct #item_name q_generics { + #(#field_names: <#field_types as #crate_name::fetch::FetchItem<#q_lf>>::Item,)* } } } -fn derive_prepared_struct( - crate_name: &Ident, - vis: &Visibility, - name: &Ident, - item_name: &Ident, - prepared_name: &Ident, - field_names: &[&Ident], - field_types: &[&Type], -) -> TokenStream { - let msg = format!("The prepared fetch for {name}"); +fn derive_prepared_struct(params: &Params) -> TokenStream { + let Params { + crate_name, + vis, + fetch_name, + item_name, + prepared_name, + generics, + field_names, + field_types, + w_generics, + w_lf, + q_lf, + .. + } = params; + + let msg = format!("The prepared fetch for {fetch_name}"); + + let prep_impl = params.prepared_impl(); + let fetch_ty = params.fetch_ty(); + let prep_ty = params.prepared_ty(); + let item_ty = params.item_ty(); quote! { #[doc = #msg] - #vis struct #prepared_name<'w> { - #(#field_names: <#field_types as #crate_name::Fetch<'w>>::Prepared,)* + #vis struct #prepared_name #w_generics { + #(#field_names: <#field_types as #crate_name::Fetch <#w_lf>>::Prepared,)* } #[automatically_derived] - impl<'w, 'q> #crate_name::fetch::PreparedFetch<'q> for #prepared_name<'w> { - type Item = #item_name<'q>; + impl #prep_impl #crate_name::fetch::PreparedFetch<#q_lf> for #prepared_name #prep_ty { + type Item = #item_name #item_ty; #[inline] unsafe fn fetch(&'q mut self, slot: #crate_name::archetype::Slot) -> Self::Item { @@ -243,6 +384,7 @@ fn derive_prepared_struct( } } +#[derive(Default)] struct Attrs { extras: Option, } @@ -269,5 +411,104 @@ impl Attrs { } } -#[cfg(test)] -mod test; +#[derive(Clone)] +struct Params<'a> { + crate_name: &'a Ident, + vis: &'a Visibility, + + fetch_name: Ident, + item_name: Ident, + prepared_name: Ident, + + generics: &'a Generics, + w_generics: Generics, + q_generics: Generics, + wq_generics: Generics, + + field_names: Vec<&'a Ident>, + field_types: Vec<&'a Type>, + + w_lf: LifetimeParam, + q_lf: LifetimeParam, + attrs: &'a Attrs, +} + +impl<'a> Params<'a> { + fn new( + crate_name: &'a Ident, + vis: &'a Visibility, + input: &'a DeriveInput, + attrs: &'a Attrs, + ) -> Self { + let fields = match &input.data { + syn::Data::Struct(data) => match &data.fields { + syn::Fields::Named(fields) => fields, + _ => unreachable!(), + }, + + _ => unreachable!(), + }; + + let field_names = fields + .named + .iter() + .map(|v| v.ident.as_ref().unwrap()) + .collect_vec(); + + let field_types = fields.named.iter().map(|v| &v.ty).collect_vec(); + + let fetch_name = input.ident.clone(); + + let w_lf = LifetimeParam::new(Lifetime::new("'w", Span::call_site())); + let q_lf = LifetimeParam::new(Lifetime::new("'q", Span::call_site())); + + Self { + crate_name, + vis, + generics: &input.generics, + field_names, + field_types, + attrs, + item_name: format_ident!("{fetch_name}Item"), + prepared_name: format_ident!("Prepared{fetch_name}"), + fetch_name, + w_generics: prepend_generics(&[GenericParam::Lifetime(w_lf.clone())], &input.generics), + q_generics: prepend_generics(&[GenericParam::Lifetime(q_lf.clone())], &input.generics), + + wq_generics: prepend_generics( + &[ + GenericParam::Lifetime(w_lf.clone()), + GenericParam::Lifetime(q_lf.clone()), + ], + &input.generics, + ), + + w_lf, + q_lf, + } + } + + fn item_impl(&self) -> ImplGenerics { + self.q_generics.split_for_impl().0 + } + + fn prepared_impl(&self) -> ImplGenerics { + self.wq_generics.split_for_impl().0 + } + + fn fetch_impl(&self) -> ImplGenerics { + self.wq_generics.split_for_impl().0 + } + + fn fetch_ty(&self) -> TypeGenerics { + self.generics.split_for_impl().1 + } + + fn item_ty(&self) -> TypeGenerics { + self.q_generics.split_for_impl().1 + } + + fn prepared_ty(&self) -> TypeGenerics { + self.w_generics.split_for_impl().1 + } +} diff --git a/src/fetch/modified.rs b/src/fetch/modified.rs index 5e3187d8..613abe1e 100644 --- a/src/fetch/modified.rs +++ b/src/fetch/modified.rs @@ -39,7 +39,9 @@ mod tests { use alloc::string::{String, ToString}; use itertools::Itertools; - use crate::{component, entity_ids, CommandBuffer, Entity, FetchExt, Query, World}; + use crate::{ + component, entity_ids, CommandBuffer, Component, Entity, Fetch, FetchExt, Query, World, + }; #[test] fn query_modified() { @@ -114,4 +116,84 @@ mod tests { [(id3, (&-1, &":P".to_string()))] ); } + + #[test] + fn query_modified_struct() { + component! { + a: i32, + b: String, + other: (), + } + + #[derive(Fetch)] + struct MyFetch { + a: Component, + b: Component, + } + + let mut world = World::new(); + + let id1 = Entity::builder() + .set(a(), 0) + .set(b(), "Hello".into()) + .spawn(&mut world); + + let id2 = Entity::builder() + .set(a(), 1) + .set(b(), "World".into()) + .spawn(&mut world); + + let id3 = Entity::builder() + // .set(a(), 0) + .set(b(), "There".into()) + .spawn(&mut world); + + // Force to a different archetype + let id4 = Entity::builder() + .set(a(), 2) + .set(b(), "!".into()) + .tag(other()) + .spawn(&mut world); + + let mut query = Query::new((entity_ids(), (a(), b()).modified())); + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [ + (id1, (&0, &"Hello".to_string())), + (id2, (&1, &"World".to_string())), + (id4, (&2, &"!".to_string())) + ] + ); + + assert_eq!(query.borrow(&world).iter().collect_vec(), []); + + // Get mut *without* a mut deref is not a change + assert_eq!(*world.get_mut(id2, a()).unwrap(), 1); + + assert_eq!(query.borrow(&world).iter().collect_vec(), []); + + *world.get_mut(id2, a()).unwrap() = 5; + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [(id2, (&5, &"World".to_string()))] + ); + + // Adding the required component to id3 will cause it to be picked up by the query + let mut cmd = CommandBuffer::new(); + cmd.set(id3, a(), -1).apply(&mut world).unwrap(); + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [(id3, (&-1, &"There".to_string()))] + ); + + cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap(); + + assert_eq!( + query.borrow(&world).iter().collect_vec(), + [(id3, (&-1, &":P".to_string()))] + ); + } } diff --git a/tests/derive_generic.rs b/tests/derive_generic.rs new file mode 100644 index 00000000..a27908b8 --- /dev/null +++ b/tests/derive_generic.rs @@ -0,0 +1,58 @@ +#[test] +#[cfg(feature = "derive")] +fn derive_fetch_generic() { + flax::component! { + position: Vec3 => [flax::Debuggable], + rotation: Quat => [flax::Debuggable], + scale: Vec3 => [flax::Debuggable], + } + + use glam::*; + + use flax::{Fetch, *}; + + #[derive(Fetch)] + #[fetch(Debug, PartialEq)] + struct TransformQuery { + pos: Component, + rot: Opt>, + scale: Opt>, + } + + let mut world = World::new(); + + let id1 = Entity::builder() + .set(position(), vec3(3.4, 2.4, 2.1)) + .spawn(&mut world); + + let id2 = Entity::builder() + .set(position(), vec3(7.4, 9.2, 3.4)) + .set(rotation(), Quat::from_axis_angle(Vec3::Z, 1.0)) + .spawn(&mut world); + + let mut query = Query::new(TransformQuery { + pos: position(), + rot: rotation().opt(), + scale: scale().opt(), + }); + + let mut query = query.borrow(&world); + + assert_eq!( + query.get(id1), + Ok(TransformQueryItem { + pos: &vec3(3.4, 2.4, 2.1), + rot: None, + scale: None + }) + ); + + assert_eq!( + query.get(id2), + Ok(TransformQueryItem { + pos: &vec3(7.4, 9.2, 3.4), + rot: Some(&Quat::from_axis_angle(Vec3::Z, 1.0)), + scale: None + }) + ); +} From a01b58e05c5e3f510eca0c0d9929318064486e49 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 1 Jul 2023 18:18:54 +0200 Subject: [PATCH 09/52] fix: warnings --- flax-derive/src/lib.rs | 124 +++++++++-------------------------------- 1 file changed, 26 insertions(+), 98 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 668383de..f7459df2 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -45,13 +45,10 @@ fn derive_data_struct( input: &DeriveInput, data: &DataStruct, ) -> Result { - let name = &input.ident; let attrs = Attrs::get(&input.attrs)?; match data.fields { - syn::Fields::Named(ref fields) => { - let fields = &fields.named; - + syn::Fields::Named(_) => { let params = Params::new(&crate_name, &input.vis, input, &attrs); let prepared_derive = derive_prepared_struct(¶ms); @@ -90,7 +87,6 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { fetch_name, item_name, prepared_name, - generics, q_generics, field_names, field_types, @@ -100,11 +96,11 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { .. } = params; - let item_ty = params.item_ty(); - let item_impl = params.item_impl(); + let item_ty = params.q_ty(); + let item_impl = params.q_impl(); let item_msg = format!("The item returned by {fetch_name}"); - let prep_ty = params.prepared_ty(); + let prep_ty = params.w_ty(); let extras = match &attrs.extras { Some(extras) => { @@ -114,18 +110,8 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { None => quote! {}, }; - let fetch_impl = params.fetch_impl(); - let fetch_ty = params.fetch_ty(); - - let msg = format!("The item returned by {fetch_name}"); - - let extras = match &attrs.extras { - Some(extras) => { - let nested = &extras.tokens; - quote! { #[derive(#nested)]} - } - None => quote! {}, - }; + let fetch_impl = params.w_impl(); + let fetch_ty = params.base_ty(); quote! { #[doc = #item_msg] @@ -183,40 +169,32 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { fn prepend_generics(prepend: &[GenericParam], generics: &Generics) -> Generics { let mut generics = generics.clone(); - generics.params = prepend - .into_iter() - .cloned() - .chain(generics.params) - .collect(); + generics.params = prepend.iter().cloned().chain(generics.params).collect(); generics } /// Implements the filtering of the struct fields using a set union fn derive_union(params: &Params) -> TokenStream { - let ty_generics = params.fetch_ty(); - let Params { crate_name, - generics, - w_generics, - q_generics, fetch_name, field_types, field_names, .. } = params; - let (_, fetch_ty, _) = generics.split_for_impl(); - let (impl_generics, _, _) = q_generics.split_for_impl(); + let impl_generics = params.q_impl(); + + let fetch_ty = params.base_ty(); quote! { - // #[automatically_derived] - // impl #impl_generics #crate_name::fetch::UnionFilter<'q> for #fetch_name #fetch_ty where #(#field_types: for<'x> #crate_name::fetch::PreparedFetch<'x>,)* { - // unsafe fn filter_union(&mut self, slots: #crate_name::archetype::Slice) -> #crate_name::archetype::Slice { - // #crate_name::fetch::PreparedFetch::filter_slots(&mut #crate_name::filter::Union((#(&mut self.#field_names,)*)), slots) - // } - // } + #[automatically_derived] + impl #impl_generics #crate_name::fetch::UnionFilter<'q> for #fetch_name #fetch_ty where #(#field_types: for<'x> #crate_name::fetch::PreparedFetch<'x>,)* { + unsafe fn filter_union(&mut self, slots: #crate_name::archetype::Slice) -> #crate_name::archetype::Slice { + #crate_name::fetch::PreparedFetch::filter_slots(&mut #crate_name::filter::Union((#(&mut self.#field_names,)*)), slots) + } + } } } @@ -225,14 +203,7 @@ fn derive_modified(params: &Params) -> TokenStream { let Params { crate_name, vis, - fetch_name, - item_name, - prepared_name, - generics, field_names, - field_types, - w_lf, - q_lf, attrs, .. } = params; @@ -271,7 +242,6 @@ fn derive_modified(params: &Params) -> TokenStream { gt_token: Some(Gt(Span::call_site())), where_clause: None, }; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let fetch = derive_fetch_struct(&transformed_params); @@ -291,46 +261,6 @@ fn derive_modified(params: &Params) -> TokenStream { } } -/// Derive the returned Item type for a Fetch -fn derive_item_struct(params: &Params) -> TokenStream { - let Params { - crate_name, - vis, - fetch_name, - item_name, - prepared_name, - generics, - field_names, - field_types, - w_lf, - q_lf, - attrs, - .. - } = params; - - let msg = format!("The item returned by {fetch_name}"); - - let extras = match &attrs.extras { - Some(extras) => { - let nested = &extras.tokens; - quote! { #[derive(#nested)]} - } - None => quote! {}, - }; - - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - let item_ty = params.item_ty(); - - quote! { - #[doc = #msg] - #extras - #vis struct #item_name q_generics { - #(#field_names: <#field_types as #crate_name::fetch::FetchItem<#q_lf>>::Item,)* - } - } -} - fn derive_prepared_struct(params: &Params) -> TokenStream { let Params { crate_name, @@ -338,7 +268,6 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { fetch_name, item_name, prepared_name, - generics, field_names, field_types, w_generics, @@ -349,10 +278,9 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { let msg = format!("The prepared fetch for {fetch_name}"); - let prep_impl = params.prepared_impl(); - let fetch_ty = params.fetch_ty(); - let prep_ty = params.prepared_ty(); - let item_ty = params.item_ty(); + let prep_impl = params.wq_impl(); + let prep_ty = params.w_ty(); + let item_ty = params.q_ty(); quote! { #[doc = #msg] @@ -488,27 +416,27 @@ impl<'a> Params<'a> { } } - fn item_impl(&self) -> ImplGenerics { + fn q_impl(&self) -> ImplGenerics { self.q_generics.split_for_impl().0 } - fn prepared_impl(&self) -> ImplGenerics { + fn wq_impl(&self) -> ImplGenerics { self.wq_generics.split_for_impl().0 } - fn fetch_impl(&self) -> ImplGenerics { - self.wq_generics.split_for_impl().0 + fn w_impl(&self) -> ImplGenerics { + self.w_generics.split_for_impl().0 } - fn fetch_ty(&self) -> TypeGenerics { + fn base_ty(&self) -> TypeGenerics { self.generics.split_for_impl().1 } - fn item_ty(&self) -> TypeGenerics { + fn q_ty(&self) -> TypeGenerics { self.q_generics.split_for_impl().1 } - fn prepared_ty(&self) -> TypeGenerics { + fn w_ty(&self) -> TypeGenerics { self.w_generics.split_for_impl().1 } } From 82fd6a83716d04d33cd91de41eaa74d475e7cd2a Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 1 Jul 2023 18:41:39 +0200 Subject: [PATCH 10/52] feat: derive modified transform --- flax-derive/src/lib.rs | 52 ++++++++++++----------------- tests/derive_generic.rs | 74 ++++++++++++++++++++--------------------- 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index f7459df2..9920cd68 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -53,12 +53,12 @@ fn derive_data_struct( let prepared_derive = derive_prepared_struct(¶ms); + let fetch_derive = derive_fetch_struct(¶ms); + let union_derive = derive_union(¶ms); let transform_modified = derive_modified(¶ms); - let fetch_derive = derive_fetch_struct(¶ms); - Ok(quote! { #fetch_derive @@ -66,7 +66,7 @@ fn derive_data_struct( #union_derive - // #transform_modified + #transform_modified }) } syn::Fields::Unnamed(_) => Err(Error::new( @@ -127,7 +127,7 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { #[automatically_derived] impl #fetch_impl #crate_name::Fetch<#w_lf> for #fetch_name #fetch_ty - where #(#field_types: #crate_name::Fetch<#w_lf>,)* + where #(#field_types: 'static,)* { const MUTABLE: bool = #(<#field_types as #crate_name::Fetch <#w_lf>>::MUTABLE)||*; @@ -203,13 +203,16 @@ fn derive_modified(params: &Params) -> TokenStream { let Params { crate_name, vis, + fetch_name, field_names, + field_types, attrs, + w_lf, .. } = params; // Replace all the fields with generics to allow transforming into different types - let ty_generics = ('a'..='z') + let ty_generics = ('A'..='Z') .map(|c| format_ident!("{}", c)) .map(|v| GenericParam::Type(TypeParam::from(v))) .take(params.field_types.len()) @@ -217,7 +220,7 @@ fn derive_modified(params: &Params) -> TokenStream { let transformed_name = format_ident!("{}Transformed", params.fetch_name); let transformed_struct = quote! { - #vis struct #transformed_name<#(#ty_generics),*>{ + #vis struct #transformed_name<#(#ty_generics: for<'x> #crate_name::fetch::Fetch<'x>),*>{ #(#field_names: #ty_generics,)* } }; @@ -225,38 +228,23 @@ fn derive_modified(params: &Params) -> TokenStream { let input = syn::parse2::(transformed_struct).expect("Generated struct is always valid"); - let transformed_params = Params::new(crate_name, vis, &input, attrs); - - let prepared = derive_prepared_struct(&transformed_params); - - // Replace all the fields with generics to allow transforming into different types - let generics_params = ('a'..='z') - .map(|c| format_ident!("{}", c)) - .map(|v| GenericParam::Type(TypeParam::from(v))) - .take(params.field_types.len()) - .collect(); - - let generics = Generics { - lt_token: Some(Lt(Span::call_site())), - params: generics_params, - gt_token: Some(Gt(Span::call_site())), - where_clause: None, - }; + let attrs = Attrs::default(); + let transformed_params = Params::new(crate_name, vis, &input, &attrs); let fetch = derive_fetch_struct(&transformed_params); + let prepared = derive_prepared_struct(&transformed_params); + quote! { - // #vis struct #transformed #ty_generics { - // #(#field_names: #generics,)* - // } + #input - // #fetch + #fetch - // #prepared + #prepared // #[automatically_derived] - // impl #crate_name::fetch::ModifiedFetch for #name where #(#field_types: #crate_name::fetch::ModifiedFetch + for<'q> #crate_name::fetch::PreparedFetch<'q>,)* { - // type Modified = #crate_name::filter::Union<#transformed<#(<#field_types as #crate_name::fetch::ModifiedFetch>::Modified,)*>>; + // impl #crate_name::fetch::ModifiedFetch for #fetch_name where #(#field_types: #crate_name::fetch::ModifiedFetch + for<'q> #crate_name::fetch::PreparedFetch<'q>,)* { + // type Modified = #crate_name::filter::Union<#transformed_name<#(<#field_types as #crate_name::fetch::ModifiedFetch>::Modified,)*>>; // } } } @@ -289,7 +277,9 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[automatically_derived] - impl #prep_impl #crate_name::fetch::PreparedFetch<#q_lf> for #prepared_name #prep_ty { + impl #prep_impl #crate_name::fetch::PreparedFetch<#q_lf> for #prepared_name #prep_ty + where #(#field_types: 'static,)* + { type Item = #item_name #item_ty; #[inline] diff --git a/tests/derive_generic.rs b/tests/derive_generic.rs index a27908b8..bbfd498f 100644 --- a/tests/derive_generic.rs +++ b/tests/derive_generic.rs @@ -12,47 +12,47 @@ fn derive_fetch_generic() { use flax::{Fetch, *}; #[derive(Fetch)] - #[fetch(Debug, PartialEq)] + // #[fetch(Debug, PartialEq)] struct TransformQuery { pos: Component, rot: Opt>, scale: Opt>, } - let mut world = World::new(); - - let id1 = Entity::builder() - .set(position(), vec3(3.4, 2.4, 2.1)) - .spawn(&mut world); - - let id2 = Entity::builder() - .set(position(), vec3(7.4, 9.2, 3.4)) - .set(rotation(), Quat::from_axis_angle(Vec3::Z, 1.0)) - .spawn(&mut world); - - let mut query = Query::new(TransformQuery { - pos: position(), - rot: rotation().opt(), - scale: scale().opt(), - }); - - let mut query = query.borrow(&world); - - assert_eq!( - query.get(id1), - Ok(TransformQueryItem { - pos: &vec3(3.4, 2.4, 2.1), - rot: None, - scale: None - }) - ); - - assert_eq!( - query.get(id2), - Ok(TransformQueryItem { - pos: &vec3(7.4, 9.2, 3.4), - rot: Some(&Quat::from_axis_angle(Vec3::Z, 1.0)), - scale: None - }) - ); + // let mut world = World::new(); + + // let id1 = Entity::builder() + // .set(position(), vec3(3.4, 2.4, 2.1)) + // .spawn(&mut world); + + // let id2 = Entity::builder() + // .set(position(), vec3(7.4, 9.2, 3.4)) + // .set(rotation(), Quat::from_axis_angle(Vec3::Z, 1.0)) + // .spawn(&mut world); + + // let mut query = Query::new(TransformQuery { + // pos: position(), + // rot: rotation().opt(), + // scale: scale().opt(), + // }); + + // let mut query = query.borrow(&world); + + // assert_eq!( + // query.get(id1), + // Ok(TransformQueryItem { + // pos: &vec3(3.4, 2.4, 2.1), + // rot: None, + // scale: None + // }) + // ); + + // assert_eq!( + // query.get(id2), + // Ok(TransformQueryItem { + // pos: &vec3(7.4, 9.2, 3.4), + // rot: Some(&Quat::from_axis_angle(Vec3::Z, 1.0)), + // scale: None + // }) + // ); } From 1daf43d607b6da123ba42777ed7378148f290f42 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 1 Jul 2023 18:43:18 +0200 Subject: [PATCH 11/52] fix: warnings --- flax-derive/src/lib.rs | 6 +----- src/fetch/modified.rs | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 9920cd68..ead5cd59 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -3,7 +3,6 @@ use proc_macro2::{Span, TokenStream}; use proc_macro_crate::FoundCrate; use quote::{format_ident, quote}; use syn::{ - token::{Gt, Lt}, Attribute, DataStruct, DeriveInput, Error, GenericParam, Generics, Ident, ImplGenerics, Lifetime, LifetimeParam, MetaList, Result, Type, TypeGenerics, TypeParam, Visibility, }; @@ -205,9 +204,6 @@ fn derive_modified(params: &Params) -> TokenStream { vis, fetch_name, field_names, - field_types, - attrs, - w_lf, .. } = params; @@ -218,7 +214,7 @@ fn derive_modified(params: &Params) -> TokenStream { .take(params.field_types.len()) .collect_vec(); - let transformed_name = format_ident!("{}Transformed", params.fetch_name); + let transformed_name = format_ident!("{fetch_name}Transformed"); let transformed_struct = quote! { #vis struct #transformed_name<#(#ty_generics: for<'x> #crate_name::fetch::Fetch<'x>),*>{ #(#field_names: #ty_generics,)* diff --git a/src/fetch/modified.rs b/src/fetch/modified.rs index 613abe1e..bee85562 100644 --- a/src/fetch/modified.rs +++ b/src/fetch/modified.rs @@ -118,6 +118,7 @@ mod tests { } #[test] + #[cfg(feature = "derive")] fn query_modified_struct() { component! { a: i32, From 1ab5d8439e2b22b60b4697c5d5e95c04179e0ee7 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 2 Jul 2023 18:18:21 +0200 Subject: [PATCH 12/52] feat: generic fetch transforms --- flax-derive/src/lib.rs | 138 +++++++++++++++++++----- src/fetch/ext.rs | 11 +- src/fetch/mod.rs | 4 +- src/fetch/{modified.rs => transform.rs} | 102 +++++++++++------- src/filter/change.rs | 30 +++--- src/filter/mod.rs | 10 +- src/filter/set.rs | 3 + src/query/mod.rs | 5 +- tests/derive.rs | 2 +- 9 files changed, 211 insertions(+), 94 deletions(-) rename src/fetch/{modified.rs => transform.rs} (58%) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index ead5cd59..fe71b17b 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -1,10 +1,13 @@ +use std::collections::BTreeSet; + use itertools::Itertools; use proc_macro2::{Span, TokenStream}; use proc_macro_crate::FoundCrate; use quote::{format_ident, quote}; use syn::{ - Attribute, DataStruct, DeriveInput, Error, GenericParam, Generics, Ident, ImplGenerics, - Lifetime, LifetimeParam, MetaList, Result, Type, TypeGenerics, TypeParam, Visibility, + bracketed, parse::Parse, punctuated::Punctuated, spanned::Spanned, Attribute, DataStruct, + DeriveInput, Error, GenericParam, Generics, Ident, ImplGenerics, Lifetime, LifetimeParam, + Result, Token, Type, TypeGenerics, TypeParam, Visibility, }; /// ```rust,ignore @@ -101,10 +104,9 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { let prep_ty = params.w_ty(); - let extras = match &attrs.extras { + let extras = match &attrs.item_derives { Some(extras) => { - let nested = &extras.tokens; - quote! { #[derive(#nested)]} + quote! { #[derive(#extras)]} } None => quote! {}, }; @@ -180,16 +182,18 @@ fn derive_union(params: &Params) -> TokenStream { fetch_name, field_types, field_names, + prepared_name, + q_lf, .. } = params; - let impl_generics = params.q_impl(); + let impl_generics = params.wq_impl(); - let fetch_ty = params.base_ty(); + let prep_ty = params.w_ty(); quote! { #[automatically_derived] - impl #impl_generics #crate_name::fetch::UnionFilter<'q> for #fetch_name #fetch_ty where #(#field_types: for<'x> #crate_name::fetch::PreparedFetch<'x>,)* { + impl #impl_generics #crate_name::fetch::UnionFilter<#q_lf> for #prepared_name #prep_ty where #prepared_name #prep_ty: #crate_name::fetch::PreparedFetch<'q> { unsafe fn filter_union(&mut self, slots: #crate_name::archetype::Slice) -> #crate_name::archetype::Slice { #crate_name::fetch::PreparedFetch::filter_slots(&mut #crate_name::filter::Union((#(&mut self.#field_names,)*)), slots) } @@ -204,6 +208,8 @@ fn derive_modified(params: &Params) -> TokenStream { vis, fetch_name, field_names, + field_types, + attrs, .. } = params; @@ -224,12 +230,34 @@ fn derive_modified(params: &Params) -> TokenStream { let input = syn::parse2::(transformed_struct).expect("Generated struct is always valid"); - let attrs = Attrs::default(); - let transformed_params = Params::new(crate_name, vis, &input, &attrs); + let transformed_attrs = Attrs::default(); + let transformed_params = Params::new(crate_name, vis, &input, &transformed_attrs); let fetch = derive_fetch_struct(&transformed_params); let prepared = derive_prepared_struct(&transformed_params); + let union = derive_union(&transformed_params); + + let transform_modified = if attrs.transforms.contains(&TransformIdent::Modified) { + let trait_name = + quote! { #crate_name::fetch::TransformFetch<#crate_name::fetch::Modified> }; + + quote! { + + #[automatically_derived] + impl #trait_name for #fetch_name + { + type Output = #crate_name::filter::Union<#transformed_name<#(<#field_types as #trait_name>::Output,)*>>; + fn transform_fetch(self) -> Self::Output { + #crate_name::filter::Union(#transformed_name { + #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names),)* + }) + } + } + } + } else { + quote! {} + }; quote! { #input @@ -238,10 +266,9 @@ fn derive_modified(params: &Params) -> TokenStream { #prepared - // #[automatically_derived] - // impl #crate_name::fetch::ModifiedFetch for #fetch_name where #(#field_types: #crate_name::fetch::ModifiedFetch + for<'q> #crate_name::fetch::PreparedFetch<'q>,)* { - // type Modified = #crate_name::filter::Union<#transformed_name<#(<#field_types as #crate_name::fetch::ModifiedFetch>::Modified,)*>>; - // } + #union + + #transform_modified } } @@ -300,25 +327,65 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { #[derive(Default)] struct Attrs { - extras: Option, + item_derives: Option>, + transforms: BTreeSet, } impl Attrs { fn get(input: &[Attribute]) -> Result { - let mut res = Self { extras: None }; + let mut res = Self::default(); for attr in input { - if attr.path().is_ident("fetch") { - match &attr.meta { - syn::Meta::List(list) => res.extras = Some(list.clone()), - _ => { - return Err(Error::new( - Span::call_site(), - "Expected a MetaList for `fetch`", - )) - } - }; + if !attr.path().is_ident("fetch") { + continue; } + + match &attr.meta { + syn::Meta::List(list) => { + // Parse list + + list.parse_nested_meta(|meta| { + // item = [Debug, PartialEq] + if meta.path.is_ident("item") { + let value = meta.value()?; + let content; + bracketed!(content in value); + let content = + >::parse_terminated(&content)?; + + // let derives = syn::parse2::(value.to_token_stream()) + // .map_err(|_| { + // Error::new( + // value.span(), + // "Expected a MetaList for item derives", + // ) + // })?; + + res.item_derives = Some(content); + Ok(()) + } else if meta.path.is_ident("transforms") { + let value = meta.value()?; + let content; + bracketed!(content in value); + let content = + >::parse_terminated( + &content, + )?; + + res.transforms.extend(content); + Ok(()) + } else { + Err(Error::new(meta.path.span(), "Unknown fetch attribute")) + } + })?; + } + _ => { + return Err(Error::new( + Span::call_site(), + "Expected a MetaList for `fetch`", + )) + } + }; } Ok(res) @@ -426,3 +493,22 @@ impl<'a> Params<'a> { self.w_generics.split_for_impl().1 } } + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +enum TransformIdent { + Modified, +} + +impl Parse for TransformIdent { + fn parse(input: syn::parse::ParseStream) -> Result { + let ident = input.parse::()?; + if ident == "Modified" { + Ok(Self::Modified) + } else { + Err(Error::new( + ident.span(), + format!("Unknown transform {ident}"), + )) + } + } +} diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index 862932d0..27a604e7 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -7,10 +7,9 @@ use super::{ as_deref::AsDeref, cloned::Cloned, copied::Copied, - modified::ModifiedFetch, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, - Satisfied, Source, + Modified, Satisfied, Source, TransformFetch, }; /// Extension trait for [crate::Fetch] @@ -143,12 +142,12 @@ pub trait FetchExt: Sized { /// /// This means will yield *any* of `a` *or* `b` are modified. /// - /// Works for in combination with `opt`, `copy` etc constituents. - fn modified(self) -> Self::Modified + /// Works with `opt`, `copy`, etc constituents. + fn modified(self) -> >::Output where - Self: ModifiedFetch, + Self: TransformFetch, { - self.transform_modified() + self.transform_fetch() } } diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 1d546fa5..641b5939 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -6,12 +6,12 @@ mod copied; mod entity_ref; mod ext; mod maybe_mut; -mod modified; mod opt; mod read_only; mod relations; mod satisfied; mod source; +mod transform; use crate::{ archetype::{Archetype, Slice, Slot}, @@ -30,12 +30,12 @@ pub use component_mut::*; pub use entity_ref::*; pub use ext::FetchExt; pub use maybe_mut::{MaybeMut, MutGuard}; -pub use modified::ModifiedFetch; pub use opt::*; pub use read_only::*; pub use relations::{relations_like, Relations, RelationsIter}; pub use satisfied::Satisfied; pub use source::Source; +pub use transform::{Modified, TransformFetch}; #[doc(hidden)] pub struct FmtQuery<'r, Q>(pub &'r Q); diff --git a/src/fetch/modified.rs b/src/fetch/transform.rs similarity index 58% rename from src/fetch/modified.rs rename to src/fetch/transform.rs index bee85562..406fd0b6 100644 --- a/src/fetch/modified.rs +++ b/src/fetch/transform.rs @@ -1,25 +1,34 @@ -use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch, FetchItem}; - -/// Transforms any supported fetch or collection of fetch into a fetch which filters modified -/// items. -pub trait ModifiedFetch: for<'w> Fetch<'w> { - type Modified: for<'x> Fetch<'x> + for<'y> FetchItem<'y, Item = >::Item>; - fn transform_modified(self) -> Self::Modified; +use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch}; + +/// Allows transforming a fetch into another. +/// +/// For example transforming a tuple or struct fetch into a modified filtering fetch. +/// The generic signifies a marker to use for transforming +pub trait TransformFetch: for<'w> Fetch<'w> { + /// The transformed type. + /// + /// May of may not have the same `Item` + type Output; + /// Transform the fetch using the provided method + fn transform_fetch(self) -> Self::Output; } -impl ModifiedFetch for Component { - type Modified = ChangeFilter; - fn transform_modified(self) -> Self::Modified { +impl TransformFetch for Component { + type Output = ChangeFilter; + fn transform_fetch(self) -> Self::Output { self.modified() } } +/// Marker for a fetch which has been transformed to filter modified items. +pub struct Modified; + macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { - impl<$($ty: ModifiedFetch,)*> ModifiedFetch for ($($ty,)*) { - type Modified = Union<($($ty::Modified,)*)>; - fn transform_modified(self) -> Self::Modified { - Union(($(self.$idx.transform_modified(),)*)) + impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { + type Output = Union<($($ty::Output,)*)>; + fn transform_fetch(self) -> Self::Output { + Union(($(self.$idx.transform_fetch(),)*)) } } }; @@ -40,7 +49,8 @@ mod tests { use itertools::Itertools; use crate::{ - component, entity_ids, CommandBuffer, Component, Entity, Fetch, FetchExt, Query, World, + component, entity_ids, filter::ChangeFilter, filter::Union, CommandBuffer, Component, + Entity, Fetch, FetchExt, Query, QueryBorrow, World, }; #[test] @@ -127,6 +137,7 @@ mod tests { } #[derive(Fetch)] + #[fetch(item = [Debug], transforms = [Modified])] struct MyFetch { a: Component, b: Component, @@ -156,45 +167,54 @@ mod tests { .tag(other()) .spawn(&mut world); - let mut query = Query::new((entity_ids(), (a(), b()).modified())); + let query = MyFetch { a: a(), b: b() }.modified(); + let mut query = Query::new((entity_ids(), query)); + + let mut collect = move |world| { + query + .borrow(world) + .iter() + .map(|(id, v)| (id, (*v.a, v.b.clone()))) + .collect_vec() + }; assert_eq!( - query.borrow(&world).iter().collect_vec(), + collect(&world), [ - (id1, (&0, &"Hello".to_string())), - (id2, (&1, &"World".to_string())), - (id4, (&2, &"!".to_string())) + (id1, (0, "Hello".to_string())), + (id2, (1, "World".to_string())), + (id4, (2, "!".to_string())) ] ); - assert_eq!(query.borrow(&world).iter().collect_vec(), []); + // assert_eq!(query.borrow(&world).iter().collect_vec(), []); - // Get mut *without* a mut deref is not a change - assert_eq!(*world.get_mut(id2, a()).unwrap(), 1); + // // Get mut *without* a mut deref is not a change + // assert_eq!(*world.get_mut(id2, a()).unwrap(), 1); - assert_eq!(query.borrow(&world).iter().collect_vec(), []); + // assert_eq!(query.borrow(&world).iter().collect_vec(), []); - *world.get_mut(id2, a()).unwrap() = 5; + // *world.get_mut(id2, a()).unwrap() = 5; - assert_eq!( - query.borrow(&world).iter().collect_vec(), - [(id2, (&5, &"World".to_string()))] - ); + // assert_eq!( + // query.borrow(&world).iter().collect_vec(), + // [(id2, (&5, &"World".to_string()))] + // ); - // Adding the required component to id3 will cause it to be picked up by the query - let mut cmd = CommandBuffer::new(); - cmd.set(id3, a(), -1).apply(&mut world).unwrap(); + // // Adding the required component to id3 will cause it to be picked up by the query + // let mut cmd = CommandBuffer::new(); + // cmd.set(id3, a(), -1).apply(&mut world).unwrap(); - assert_eq!( - query.borrow(&world).iter().collect_vec(), - [(id3, (&-1, &"There".to_string()))] - ); + // assert_eq!( + // query.borrow(&world).iter().collect_vec(), + // [(id3, (&-1, &"There".to_string()))] + // ); - cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap(); + // cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap(); - assert_eq!( - query.borrow(&world).iter().collect_vec(), - [(id3, (&-1, &":P".to_string()))] - ); + // assert_eq!( + // query.borrow(&world).iter().collect_vec(), + // [(id3, (&-1, &":P".to_string()))] + // ); } } diff --git a/src/filter/change.rs b/src/filter/change.rs index 5d222a43..174f7bb2 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -46,7 +46,7 @@ where type Item = &'q T; } -impl<'q, Q: ReadOnlyFetch<'q>, A> ReadOnlyFetch<'q> for PreparedKindFilter +impl<'q, Q: ReadOnlyFetch<'q>, A> ReadOnlyFetch<'q> for PreparedChangeFilter where Q: PreparedFetch<'q>, A: Deref, @@ -62,7 +62,7 @@ where { const MUTABLE: bool = false; - type Prepared = PreparedKindFilter, AtomicRef<'w, [Change]>>; + type Prepared = PreparedChangeFilter, AtomicRef<'w, [Change]>>; fn prepare(&'w self, data: crate::fetch::FetchPrepareData<'w>) -> Option { let changes = data.arch.changes(self.component.key())?; @@ -75,7 +75,7 @@ where let changes = AtomicRef::map(changes, |changes| changes.get(self.kind).as_slice()); let fetch = self.component.prepare(data)?; - Some(PreparedKindFilter::new(fetch, changes, data.old_tick)) + Some(PreparedChangeFilter::new(fetch, changes, data.old_tick)) } fn filter_arch(&self, arch: &Archetype) -> bool { @@ -105,9 +105,8 @@ where } } -#[derive(Debug)] #[doc(hidden)] -pub struct PreparedKindFilter { +pub struct PreparedChangeFilter { fetch: Q, changes: A, cur: Option, @@ -115,7 +114,14 @@ pub struct PreparedKindFilter { old_tick: u32, } -impl PreparedKindFilter +impl core::fmt::Debug for PreparedChangeFilter { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PreparedChangeFilter") + .finish_non_exhaustive() + } +} + +impl PreparedChangeFilter where A: Deref, { @@ -161,7 +167,7 @@ where } } -impl<'q, Q, A> PreparedFetch<'q> for PreparedKindFilter +impl<'q, Q, A> PreparedFetch<'q> for PreparedChangeFilter where Q: PreparedFetch<'q>, A: Deref, @@ -219,7 +225,7 @@ impl<'q, T: ComponentValue> FetchItem<'q> for RemovedFilter { impl<'a, T: ComponentValue> Fetch<'a> for RemovedFilter { const MUTABLE: bool = false; - type Prepared = PreparedKindFilter<(), &'a [Change]>; + type Prepared = PreparedChangeFilter<(), &'a [Change]>; fn prepare(&self, data: FetchPrepareData<'a>) -> Option { let changes = data @@ -227,7 +233,7 @@ impl<'a, T: ComponentValue> Fetch<'a> for RemovedFilter { .removals(self.component.key()) .unwrap_or(&EMPTY_CHANGELIST); - Some(PreparedKindFilter::new((), changes, data.old_tick)) + Some(PreparedChangeFilter::new((), changes, data.old_tick)) } fn filter_arch(&self, _: &Archetype) -> bool { @@ -266,7 +272,7 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let mut filter = PreparedKindFilter::new((), &changes[..], 2); + let mut filter = PreparedChangeFilter::new((), &changes[..], 2); unsafe { assert_eq!(filter.filter_slots(Slice::new(0, 10)), Slice::new(10, 10)); @@ -294,7 +300,7 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let filter = PreparedKindFilter::new((), &changes[..], 2); + let filter = PreparedChangeFilter::new((), &changes[..], 2); let slices = FilterIter::new(Slice::new(0, 500), filter).collect_vec(); @@ -318,7 +324,7 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let filter = PreparedKindFilter::new((), &changes[..], 2); + let filter = PreparedChangeFilter::new((), &changes[..], 2); let slices = FilterIter::new(Slice::new(25, 150), filter) .take(100) diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 86b4a93f..9699ac36 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -610,7 +610,7 @@ mod tests { changes.set(Change::new(Slice::new(784, 800), 7)); changes.set(Change::new(Slice::new(945, 1139), 8)); - let filter = PreparedKindFilter::new((), changes.as_slice(), 2); + let filter = PreparedChangeFilter::new((), changes.as_slice(), 2); // The whole "archetype" let slots = Slice::new(0, 1238); @@ -644,8 +644,8 @@ mod tests { let slots = Slice::new(0, 1000); // Or - let a = PreparedKindFilter::new((), changes_1.as_slice(), 1); - let b = PreparedKindFilter::new((), changes_2.as_slice(), 2); + let a = PreparedChangeFilter::new((), changes_1.as_slice(), 1); + let b = PreparedChangeFilter::new((), changes_2.as_slice(), 2); let filter = Or((Some(a), Some(b))); @@ -661,8 +661,8 @@ mod tests { // And - let a = PreparedKindFilter::new((), changes_1.as_slice(), 1); - let b = PreparedKindFilter::new((), changes_2.as_slice(), 2); + let a = PreparedChangeFilter::new((), changes_1.as_slice(), 1); + let b = PreparedChangeFilter::new((), changes_2.as_slice(), 2); let filter = And(a, b); diff --git a/src/filter/set.rs b/src/filter/set.rs index 690cd695..bb26d950 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -180,6 +180,9 @@ impl ops::Not for Not { /// This is most useful for change queries, where you care about about *any* change, but still /// require the entity to have all the components, and have them returned despite not all having /// changed. +/// +/// For this to implement `Fetch`, `T::Prepared` must implement `UnionFilter`. +#[derive(Debug, Clone)] pub struct Union(pub T); impl<'q, T> FetchItem<'q> for Union diff --git a/src/query/mod.rs b/src/query/mod.rs index 67db51b5..6522f84f 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -120,7 +120,10 @@ impl Query { /// [`Query::with_components`] /// /// A fetch may also contain filters - pub fn new(fetch: Q) -> Self { + pub fn new(fetch: Q) -> Self + where + Q: for<'x> Fetch<'x>, + { Self { fetch: Filtered::new(fetch, All, false), change_tick: 0, diff --git a/tests/derive.rs b/tests/derive.rs index 1be34abe..9e4b0fa4 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -12,7 +12,7 @@ fn derive_fetch() { use flax::{Fetch, *}; #[derive(Fetch)] - #[fetch(Debug, PartialEq)] + #[fetch(item = [Debug, PartialEq])] struct TransformQuery { pos: Component, rot: Opt>, From 53ea861a0f0e7a8def1ffe247ac104489d69f47a Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 2 Jul 2023 19:32:43 +0200 Subject: [PATCH 13/52] chore: attempt to use GAT See: --- asteroids/src/main.rs | 2 +- flax-derive/src/lib.rs | 8 ++-- src/fetch/as_deref.rs | 22 +++++----- src/fetch/cloned.rs | 24 +++++------ src/fetch/component.rs | 14 +++--- src/fetch/component_mut.rs | 10 ++--- src/fetch/copied.rs | 24 +++++------ src/fetch/entity_ref.rs | 10 ++--- src/fetch/ext.rs | 5 ++- src/fetch/maybe_mut.rs | 14 +++--- src/fetch/mod.rs | 87 ++++++++++++++++++++------------------ src/fetch/opt.rs | 34 +++++++-------- src/fetch/read_only.rs | 10 ++--- src/fetch/relations.rs | 14 +++--- src/fetch/satisfied.rs | 10 ++--- src/fetch/source.rs | 23 +++++----- src/fetch/transform.rs | 13 +++--- src/filter/change.rs | 23 +++++----- src/filter/cmp.rs | 30 +++++++------ src/filter/constant.rs | 40 +++++++++--------- src/filter/mod.rs | 68 ++++++++++++++--------------- src/filter/set.rs | 60 +++++++++++++------------- src/query/borrow.rs | 10 ++--- src/query/dfs.rs | 8 ++-- src/query/entity.rs | 2 +- src/query/iter.rs | 20 ++++----- src/query/mod.rs | 2 +- src/query/planar.rs | 12 +++--- src/query/topo.rs | 4 +- src/query/walk.rs | 2 +- src/system/mod.rs | 8 ++-- 31 files changed, 311 insertions(+), 302 deletions(-) diff --git a/asteroids/src/main.rs b/asteroids/src/main.rs index 594661ca..012ee73a 100644 --- a/asteroids/src/main.rs +++ b/asteroids/src/main.rs @@ -481,7 +481,7 @@ const PLUME_COOLDOWN: f32 = 0.02; /// and refactoring. #[derive(Fetch)] // Ensures the fetch item is debuggable -#[fetch(Debug)] +#[fetch(item = [Debug])] struct PlayerQuery { id: EntityIds, player: Component<()>, diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index fe71b17b..1390bf42 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -248,9 +248,9 @@ fn derive_modified(params: &Params) -> TokenStream { impl #trait_name for #fetch_name { type Output = #crate_name::filter::Union<#transformed_name<#(<#field_types as #trait_name>::Output,)*>>; - fn transform_fetch(self) -> Self::Output { + fn transform_fetch(self, method: #crate_name::fetch::Modified) -> Self::Output { #crate_name::filter::Union(#transformed_name { - #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names),)* + #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names, method),)* }) } } @@ -300,10 +300,10 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[automatically_derived] - impl #prep_impl #crate_name::fetch::PreparedFetch<#q_lf> for #prepared_name #prep_ty + impl #prep_impl #crate_name::fetch::PreparedFetch for #prepared_name #prep_ty where #(#field_types: 'static,)* { - type Item = #item_name #item_ty; + type Item<#q_lf> = #item_name #item_ty; #[inline] unsafe fn fetch(&'q mut self, slot: #crate_name::archetype::Slot) -> Self::Item { diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index 8d9158a2..2901114b 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -6,18 +6,18 @@ use core::{fmt, ops::Deref}; /// Dereferences the fetch item pub struct AsDeref(pub(crate) F); -impl<'q, F, V> FetchItem<'q> for AsDeref +impl FetchItem for AsDeref where - F: FetchItem<'q, Item = &'q V>, + F: for<'q> FetchItem = &'q V>, V: 'static + Deref, { - type Item = &'q V::Target; + type Item<'q> = &'q V::Target; } impl<'w, F, V> Fetch<'w> for AsDeref where F: Fetch<'w>, - F: for<'q> FetchItem<'q, Item = &'q V>, + F: for<'q> FetchItem = &'q V>, V: 'static + Deref, { const MUTABLE: bool = F::MUTABLE; @@ -50,14 +50,14 @@ where } } -impl<'q, F, V> PreparedFetch<'q> for AsDeref +impl PreparedFetch for AsDeref where - F: PreparedFetch<'q, Item = &'q V>, + for<'q> F: PreparedFetch = &'q V> + 'q, V: 'static + Deref, { - type Item = &'q V::Target; + type Item<'q> = &'q V::Target where Self: 'q; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.0.fetch(slot) } @@ -70,12 +70,12 @@ where } } -impl<'q, F, V> ReadOnlyFetch<'q> for AsDeref +impl ReadOnlyFetch for AsDeref where - F: ReadOnlyFetch<'q, Item = &'q V>, + for<'q> F: ReadOnlyFetch = &'q V> + 'q, V: 'static + Deref, { - unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&self, slot: crate::archetype::Slot) -> Self::Item<'q> { self.0.fetch_shared(slot) } } diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index 0ea3d0a4..bd5571ea 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -20,9 +20,9 @@ use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; /// See [crate::Component::as_mut] pub struct Cloned(pub(crate) F); -impl<'q, F, V> FetchItem<'q> for Cloned +impl FetchItem for Cloned where - F: FetchItem<'q, Item = &'q V>, + F: for<'q> FetchItem = &'q V>, V: 'static, { type Item = V; @@ -31,7 +31,7 @@ where impl<'w, F, V> Fetch<'w> for Cloned where F: Fetch<'w>, - F: for<'q> FetchItem<'q, Item = &'q V>, + F: for<'q> FetchItem = &'q V>, V: 'static + Clone, { const MUTABLE: bool = F::MUTABLE; @@ -62,16 +62,16 @@ where } } -impl<'q, F, V> PreparedFetch<'q> for Cloned +impl PreparedFetch for Cloned where - F: PreparedFetch<'q>, - F::Item: Deref, + F: PreparedFetch, + for<'q> F::Item<'q>: Deref, V: 'static + Clone, { - type Item = V; + type Item<'q> = V where Self: 'q; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.0.fetch(slot).clone() } @@ -86,13 +86,13 @@ where } } -impl<'q, V, F> ReadOnlyFetch<'q> for Cloned +impl ReadOnlyFetch for Cloned where - F: ReadOnlyFetch<'q>, - F::Item: Deref, + F: ReadOnlyFetch, + for<'q> F::Item<'q>: Deref, V: 'static + Clone, { - unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: crate::archetype::Slot) -> Self::Item<'q> { self.0.fetch_shared(slot).clone() } } diff --git a/src/fetch/component.rs b/src/fetch/component.rs index 04bb4755..abd27faf 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -9,18 +9,18 @@ pub struct ReadComponent<'a, T> { borrow: AtomicRef<'a, [T]>, } -impl<'q, 'w, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { - type Item = &'q T; +impl<'w, T: 'static> PreparedFetch for ReadComponent<'w, T> { + type Item<'q> = &'q T; #[inline(always)] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { // Safety: bounds guaranteed by callee unsafe { self.borrow.get_unchecked(slot) } } } -impl<'w, 'p, T: ComponentValue> ReadOnlyFetch<'p> for ReadComponent<'w, T> { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { +impl<'w, T: ComponentValue> ReadOnlyFetch for ReadComponent<'w, T> { + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { self.borrow.get_unchecked(slot) } } @@ -65,6 +65,6 @@ where } } -impl<'q, T: ComponentValue> FetchItem<'q> for Component { - type Item = &'q T; +impl FetchItem for Component { + type Item<'q> = &'q T; } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 3aa3e750..20246280 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -89,15 +89,15 @@ where } } -impl<'q, T: ComponentValue> FetchItem<'q> for Mutable { - type Item = &'q mut T; +impl FetchItem for Mutable { + type Item<'q> = &'q mut T; } -impl<'q, 'w, T: 'q> PreparedFetch<'q> for WriteComponent<'w, T> { - type Item = &'q mut T; +impl<'w, T: 'static> PreparedFetch for WriteComponent<'w, T> { + type Item<'q> = &'q mut T; #[inline(always)] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { // Perform a reborrow // Cast from a immutable to a mutable borrow as all calls to this // function are guaranteed to be disjoint diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index 1b4df019..aa545277 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -20,18 +20,18 @@ use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; /// See [crate::Component::as_mut] pub struct Copied(pub(crate) F); -impl<'q, F, V> FetchItem<'q> for Copied +impl FetchItem for Copied where - F: FetchItem<'q, Item = &'q V>, + F: for<'q> FetchItem = &'q V>, V: 'static, { - type Item = V; + type Item<'q> = V; } impl<'w, F, V> Fetch<'w> for Copied where F: Fetch<'w>, - F: for<'q> FetchItem<'q, Item = &'q V>, + F: for<'q> FetchItem = &'q V>, V: 'static + Copy, { const MUTABLE: bool = F::MUTABLE; @@ -63,16 +63,16 @@ where } } -impl<'q, F, V> PreparedFetch<'q> for Copied +impl PreparedFetch for Copied where - F: PreparedFetch<'q>, - F::Item: Deref, + F: PreparedFetch, + for<'q> F::Item<'q>: Deref, V: 'static + Copy, { type Item = V; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { *self.0.fetch(slot) } @@ -87,13 +87,13 @@ where } } -impl<'p, F, V> ReadOnlyFetch<'p> for Copied +impl ReadOnlyFetch for Copied where - F: ReadOnlyFetch<'p>, - F::Item: Deref, + F: ReadOnlyFetch, + for<'q> F::Item<'q>: Deref, V: 'static + Copy, { - unsafe fn fetch_shared(&'p self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: crate::archetype::Slot) -> Self::Item<'q> { *self.0.fetch_shared(slot) } } diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index 6ea5e686..78d36a64 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -16,8 +16,8 @@ pub fn entity_refs() -> EntityRefs { EntityRefs } -impl<'q> FetchItem<'q> for EntityRefs { - type Item = EntityRef<'q>; +impl FetchItem for EntityRefs { + type Item<'q> = EntityRef<'q>; } impl<'w> Fetch<'w> for EntityRefs { @@ -59,11 +59,11 @@ pub struct PreparedEntityRef<'a> { arch: &'a Archetype, } -impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { - type Item = EntityRef<'q>; +impl<'w> PreparedFetch for PreparedEntityRef<'w> { + type Item<'q> = EntityRef<'q>; #[inline] - unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: crate::archetype::Slot) -> Self::Item<'q> { EntityRef { arch: self.arch, slot, diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index 27a604e7..054c5978 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -7,6 +7,7 @@ use super::{ as_deref::AsDeref, cloned::Cloned, copied::Copied, + map::Map, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, Modified, Satisfied, Source, TransformFetch, @@ -25,7 +26,7 @@ pub trait FetchExt: Sized { fn opt_or(self, default: V) -> OptOr where Self: for<'w> Fetch<'w>, - for<'q> Self: FetchItem<'q, Item = &'q V>, + for<'q> Self: FetchItem = &'q V>, { OptOr::new(self, default) } @@ -40,7 +41,7 @@ pub trait FetchExt: Sized { fn opt_or_default(self) -> OptOr where Self: for<'w> Fetch<'w>, - for<'q> Self: FetchItem<'q, Item = &'q V>, + for<'q> Self: FetchItem = &'q V>, V: Default, { self.opt_or(Default::default()) diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index ae1d54e7..05298814 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -19,8 +19,8 @@ use super::{FetchAccessData, PreparedFetch, ReadOnlyFetch}; /// to the loop body, rather than the iterator. pub struct MaybeMut(pub(crate) Component); -impl<'q, T: ComponentValue> FetchItem<'q> for MaybeMut { - type Item = MutGuard<'q, T>; +impl FetchItem for MaybeMut { + type Item<'q> = MutGuard<'q, T>; } impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut { @@ -87,11 +87,11 @@ pub struct PreparedMaybeMut<'w, T> { _marker: PhantomData, } -impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { - type Item = MutGuard<'q, T>; +impl<'w, T: ComponentValue> PreparedFetch for PreparedMaybeMut<'w, T> { + type Item<'q> = MutGuard<'q, T>; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { MutGuard { slot, cell: self.cell, @@ -102,9 +102,9 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { } } -impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { +impl<'w, T: ComponentValue> ReadOnlyFetch for PreparedMaybeMut<'w, T> { #[inline] - unsafe fn fetch_shared(&'q self, slot: usize) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: usize) -> Self::Item<'q> { MutGuard { slot, cell: self.cell, diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 641b5939..00338cd8 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -5,6 +5,7 @@ mod component_mut; mod copied; mod entity_ref; mod ext; +mod map; mod maybe_mut; mod opt; mod read_only; @@ -76,9 +77,9 @@ pub struct FetchPrepareData<'w> { } /// Trait which gives an associated `Item` fetch type -pub trait FetchItem<'q> { +pub trait FetchItem { /// The item yielded by the prepared fetch - type Item; + type Item<'q>; } /// A fetch describes a retrieval of data from the world and archetypes during a query. @@ -88,12 +89,12 @@ pub trait FetchItem<'q> { /// /// The PreparedFetch can in turn control the ranges of slots which are requested by the query, /// e.g; filtering changed components -pub trait Fetch<'w>: for<'q> FetchItem<'q> { +pub trait Fetch<'w>: FetchItem { /// true if the fetch mutates any component and thus needs a change event const MUTABLE: bool; /// The prepared version of the fetch - type Prepared: for<'x> PreparedFetch<'x, Item = >::Item> + 'w; + type Prepared: for<'x> PreparedFetch = ::Item<'x>> + 'w; /// Prepares the fetch for an archetype by acquiring borrows. /// @@ -126,9 +127,11 @@ pub trait Fetch<'w>: for<'q> FetchItem<'q> { } /// Borrowed state for a fetch -pub trait PreparedFetch<'q> { +pub trait PreparedFetch { /// Item returned by fetch - type Item: 'q; + type Item<'q>: 'q + where + Self: 'q; /// Fetch the item from entity at the slot in the prepared storage. /// # Safety @@ -136,7 +139,7 @@ pub trait PreparedFetch<'q> { /// prepared archetype. /// /// The callee is responsible for assuring disjoint calls. - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item; + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q>; #[inline] /// Filter the slots to visit @@ -155,7 +158,7 @@ pub trait PreparedFetch<'q> { } /// Allows filtering the constituent parts of a fetch using a set union -pub trait UnionFilter<'q> { +pub trait UnionFilter { // Filter the slots using a union operation of the constituent part /// /// # Safety @@ -163,13 +166,13 @@ pub trait UnionFilter<'q> { unsafe fn filter_union(&mut self, slots: Slice) -> Slice; } -impl<'q, F> PreparedFetch<'q> for &'q mut F +impl PreparedFetch for &mut F where - F: PreparedFetch<'q>, + F: PreparedFetch, { - type Item = F::Item; + type Item<'q> = F::Item<'q>where F: 'q; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { (*self).fetch(slot) } @@ -182,11 +185,11 @@ where } } -impl<'q> FetchItem<'q> for () { +impl FetchItem for () { type Item = (); } -impl<'q> UnionFilter<'q> for () { +impl UnionFilter for () { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { slots } @@ -213,24 +216,25 @@ impl<'w> Fetch<'w> for () { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'p> ReadOnlyFetch<'p> for () { - unsafe fn fetch_shared(&'p self, _: Slot) -> Self::Item {} +impl ReadOnlyFetch for () { + unsafe fn fetch_shared<'q>(&'q self, _: Slot) -> Self::Item<'q> {} } -impl<'q> PreparedFetch<'q> for () { - type Item = (); +impl PreparedFetch for () { + type Item<'q> = (); - unsafe fn fetch(&'q mut self, _: Slot) -> Self::Item {} + unsafe fn fetch<'q>(&'q mut self, _: Slot) -> Self::Item<'q> {} } -impl<'q, F> PreparedFetch<'q> for Option +impl PreparedFetch for Option where - F: PreparedFetch<'q>, + F: PreparedFetch, { - type Item = Option; + type Item<'q> = Option>where + Self: 'q; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.as_mut().map(|fetch| fetch.fetch(slot)) } @@ -259,7 +263,7 @@ pub struct ReadEntities<'a> { entities: &'a [Entity], } -impl<'q> FetchItem<'q> for EntityIds { +impl FetchItem for EntityIds { type Item = Entity; } @@ -286,18 +290,18 @@ impl<'w> Fetch<'w> for EntityIds { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { - type Item = Entity; +impl<'w> PreparedFetch for ReadEntities<'w> { + type Item<'q> = Entity; #[inline] - unsafe fn fetch(&mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.entities[slot] } } -impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { +impl<'w> ReadOnlyFetch for ReadEntities<'w> { #[inline] - unsafe fn fetch_shared(&self, slot: usize) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: usize) -> Self::Item<'q> { self.entities[slot] } } @@ -305,19 +309,19 @@ impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { // Implement for tuples macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { - impl<'q, $($ty, )*> FetchItem<'q> for ($($ty,)*) - where $($ty: FetchItem<'q>,)* + impl<$($ty, )*> FetchItem for ($($ty,)*) + where $($ty: FetchItem,)* { - type Item = ($($ty::Item,)*); + type Item<'q> = ($($ty::Item<'q>,)*); } - impl<'q, $($ty, )*> ReadOnlyFetch<'q> for ($($ty,)*) - where $($ty: ReadOnlyFetch<'q>,)* + impl<$($ty, )*> ReadOnlyFetch for ($($ty,)*) + where $($ty: ReadOnlyFetch,)* { #[inline(always)] - unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { ($( (self.$idx).fetch_shared(slot), )*) @@ -325,13 +329,14 @@ macro_rules! tuple_impl { } - impl<'q, $($ty, )*> PreparedFetch<'q> for ($($ty,)*) - where $($ty: PreparedFetch<'q>,)* + impl<$($ty, )*> PreparedFetch for ($($ty,)*) + where $($ty: PreparedFetch,)* { - type Item = ($($ty::Item,)*); + type Item<'q> = ($($ty::Item<'q>,)*) where Self: 'q; + #[inline] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { ($( (self.$idx).fetch(slot), )*) @@ -353,8 +358,8 @@ macro_rules! tuple_impl { } } - impl<'q, $($ty, )*> UnionFilter<'q> for ($($ty,)*) - where $($ty: PreparedFetch<'q>,)* + impl<$($ty, )*> UnionFilter for ($($ty,)*) + where $($ty: PreparedFetch,)* { #[inline] diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 862906f5..40acc9cb 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -16,8 +16,8 @@ use super::{FetchAccessData, FetchItem, ReadOnlyFetch}; #[derive(Debug, Clone)] pub struct Opt(pub(crate) F); -impl<'q, F: FetchItem<'q>> FetchItem<'q> for Opt { - type Item = Option; +impl FetchItem for Opt { + type Item<'q> = Option>; } impl<'w, F> Fetch<'w> for Opt @@ -49,23 +49,23 @@ where #[doc(hidden)] pub struct PreparedOpt(pub(crate) Option); -impl<'p, F> ReadOnlyFetch<'p> for PreparedOpt +impl<'p, F> ReadOnlyFetch for PreparedOpt where - F: ReadOnlyFetch<'p>, + F: ReadOnlyFetch, { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { self.0.as_ref().map(|fetch| fetch.fetch_shared(slot)) } } -impl<'q, F> PreparedFetch<'q> for PreparedOpt +impl PreparedFetch for PreparedOpt where - F: PreparedFetch<'q>, + F: PreparedFetch, { - type Item = Option; + type Item<'q> = Option> where Self: 'q; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&mut self, slot: usize) -> Self::Item<'q> { self.0.as_mut().map(|fetch| fetch.fetch(slot)) } @@ -101,8 +101,8 @@ impl OptOr { impl<'w, F, V> Fetch<'w> for OptOr where - F: Fetch<'w> + for<'q> FetchItem<'q, Item = &'q V>, - for<'q> F::Prepared: PreparedFetch<'q, Item = &'q V>, + F: Fetch<'w> + for<'q> FetchItem = &'q V>, + OptOr, &'w V>: PreparedFetch, V: ComponentValue, { const MUTABLE: bool = F::MUTABLE; @@ -131,18 +131,18 @@ where } } -impl<'q, F: FetchItem<'q, Item = &'q V>, V: ComponentValue> FetchItem<'q> for OptOr { - type Item = &'q V; +impl FetchItem = &'q V>, V: ComponentValue> FetchItem for OptOr { + type Item<'q> = &'q V; } -impl<'q, 'w, F, V> PreparedFetch<'q> for OptOr, &'w V> +impl<'w, F, V> PreparedFetch for OptOr, &'w V> where - F: PreparedFetch<'q, Item = &'q V>, + for<'q> F: PreparedFetch = &'q V> + 'q, V: 'static, { - type Item = &'q V; + type Item<'q> = &'q V where Self: 'q; - unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: crate::archetype::Slot) -> Self::Item<'q> { match self.fetch { Some(ref mut v) => v.fetch(slot), None => self.or, diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index b8d70cec..135b1c12 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -5,19 +5,19 @@ use super::PreparedFetch; /// A fetch which only yields items which can freely *alias*. /// /// This makes the `fetch` method *safer* to implement and can be called with a covariant lifetime. -pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { +pub trait ReadOnlyFetch: PreparedFetch { /// Fetch the shared item from the given slot /// /// # Safety /// Slot must be valid - unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q>; } -impl<'p, F> ReadOnlyFetch<'p> for Option +impl ReadOnlyFetch for Option where - F: ReadOnlyFetch<'p>, + F: ReadOnlyFetch, { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { self.as_ref().map(|fetch| fetch.fetch_shared(slot)) } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 4d950828..8fade529 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -72,8 +72,8 @@ where } } -impl<'q, T: ComponentValue> FetchItem<'q> for Relations { - type Item = RelationsIter<'q, T>; +impl FetchItem for Relations { + type Item<'q> = RelationsIter<'q, T>; } #[doc(hidden)] @@ -81,13 +81,13 @@ pub struct PreparedRelations<'a, T> { borrows: SmallVec<[(Entity, AtomicRef<'a, [T]>); 4]>, } -impl<'q, 'w, T> PreparedFetch<'q> for PreparedRelations<'w, T> +impl<'w, T> PreparedFetch for PreparedRelations<'w, T> where T: ComponentValue, { - type Item = RelationsIter<'q, T>; + type Item<'q> = RelationsIter<'q, T>; - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { RelationsIter { borrows: self.borrows.iter(), slot, @@ -101,8 +101,8 @@ pub struct RelationsIter<'a, T> { slot: Slot, } -impl<'a, T> Iterator for RelationsIter<'a, T> { - type Item = (Entity, &'a T); +impl<'q, T> Iterator for RelationsIter<'q, T> { + type Item = (Entity, &'q T); fn next(&mut self) -> Option { let (id, borrow) = self.borrows.next()?; diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index c99c6a76..1e367822 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -10,8 +10,8 @@ use super::{FmtQuery, PreparedFetch}; /// Yields true iff `F` would match the query pub struct Satisfied(pub(crate) F); -impl<'q, F: FetchItem<'q>> FetchItem<'q> for Satisfied { - type Item = bool; +impl FetchItem for Satisfied { + type Item<'q> = bool; } impl<'w, F: Fetch<'w>> Fetch<'w> for Satisfied { @@ -41,10 +41,10 @@ impl<'w, F: Fetch<'w>> Fetch<'w> for Satisfied { #[doc(hidden)] pub struct PreparedSatisfied(Option); -impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { - type Item = bool; +impl PreparedFetch for PreparedSatisfied { + type Item<'q> = bool; - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { if let Some(fetch) = &mut self.0 { !fetch.filter_slots(Slice::single(slot)).is_empty() } else { diff --git a/src/fetch/source.rs b/src/fetch/source.rs index a55e5b54..6fb2561e 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -79,18 +79,18 @@ impl Source { } } -impl<'q, Q, S> FetchItem<'q> for Source +impl FetchItem for Source where - Q: FetchItem<'q>, + Q: FetchItem, S: FetchSource, { - type Item = Q::Item; + type Item<'q> = Q::Item<'q>; } impl<'w, Q, S> Fetch<'w> for Source where Q: Fetch<'w>, - Q::Prepared: for<'x> ReadOnlyFetch<'x>, + PreparedSource: PreparedFetch, S: FetchSource, { const MUTABLE: bool = Q::MUTABLE; @@ -146,22 +146,23 @@ where } } -impl<'q, Q> ReadOnlyFetch<'q> for PreparedSource +impl ReadOnlyFetch for PreparedSource where - Q: ReadOnlyFetch<'q>, + Q: ReadOnlyFetch, { - unsafe fn fetch_shared(&'q self, _: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, _: crate::archetype::Slot) -> Self::Item<'q> { self.fetch.fetch_shared(self.slot) } } -impl<'q, Q> PreparedFetch<'q> for PreparedSource +impl PreparedFetch for PreparedSource where - Q: ReadOnlyFetch<'q>, + Q: ReadOnlyFetch, { - type Item = Q::Item; + type Item<'q> = Q::Item<'q> where Self: 'q; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + #[inline] + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.fetch_shared(slot) } diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index 406fd0b6..bdf9da29 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -1,4 +1,4 @@ -use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch}; +use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch, FetchItem}; /// Allows transforming a fetch into another. /// @@ -10,25 +10,26 @@ pub trait TransformFetch: for<'w> Fetch<'w> { /// May of may not have the same `Item` type Output; /// Transform the fetch using the provided method - fn transform_fetch(self) -> Self::Output; + fn transform_fetch(self, method: Method) -> Self::Output; } impl TransformFetch for Component { type Output = ChangeFilter; - fn transform_fetch(self) -> Self::Output { + fn transform_fetch(self, _: Modified) -> Self::Output { self.modified() } } /// Marker for a fetch which has been transformed to filter modified items. +#[derive(Debug, Clone, Copy)] pub struct Modified; macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { type Output = Union<($($ty::Output,)*)>; - fn transform_fetch(self) -> Self::Output { - Union(($(self.$idx.transform_fetch(),)*)) + fn transform_fetch(self, method: Modified) -> Self::Output { + Union(($(self.$idx.transform_fetch(method),)*)) } } }; @@ -168,7 +169,7 @@ mod tests { .spawn(&mut world); let query = MyFetch { a: a(), b: b() }.modified(); - let mut query = Query::new((entity_ids(), query)); + let mut query = Query::new((entity_ids(), query).map(|(id, v)| (id, v.a, v.b))); let mut collect = move |world| { query diff --git a/src/filter/change.rs b/src/filter/change.rs index 174f7bb2..fcc6802a 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -39,19 +39,19 @@ impl ChangeFilter { } } -impl<'q, T> FetchItem<'q> for ChangeFilter +impl FetchItem for ChangeFilter where T: ComponentValue, { - type Item = &'q T; + type Item<'q> = &'q T; } -impl<'q, Q: ReadOnlyFetch<'q>, A> ReadOnlyFetch<'q> for PreparedChangeFilter +impl ReadOnlyFetch for PreparedChangeFilter where - Q: PreparedFetch<'q>, + Q: PreparedFetch, A: Deref, { - unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { self.fetch.fetch_shared(slot) } } @@ -167,15 +167,14 @@ where } } -impl<'q, Q, A> PreparedFetch<'q> for PreparedChangeFilter +impl PreparedFetch for PreparedChangeFilter where - Q: PreparedFetch<'q>, + Q: PreparedFetch, A: Deref, { - type Item = Q::Item; - + type Item<'q> = Q::Item<'q> where Self: 'q; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.fetch.fetch(slot) } @@ -218,8 +217,8 @@ impl RemovedFilter { } } -impl<'q, T: ComponentValue> FetchItem<'q> for RemovedFilter { - type Item = (); +impl FetchItem for RemovedFilter { + type Item<'q> = (); } impl<'a, T: ComponentValue> Fetch<'a> for RemovedFilter { diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index 4f8ab5b6..e8d928a7 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -115,15 +115,17 @@ impl Cmp { } } -impl<'q, F: FetchItem<'q>, M> FetchItem<'q> for Cmp { - type Item = F::Item; +impl FetchItem for Cmp { + type Item<'q> = F::Item<'q>; } impl<'w, F, M> Fetch<'w> for Cmp where - F: Fetch<'w>, - F::Prepared: for<'x> ReadOnlyFetch<'x>, - M: for<'x> CmpMethod<>::Item> + 'w, + F: Fetch<'w> + 'w, + F::Prepared: for<'x> ReadOnlyFetch, + for<'x> PreparedCmp<'w, F::Prepared, M>: PreparedFetch, + // M: for<'x> CmpMethod<::Item<'x>>, + M: 'static, { const MUTABLE: bool = F::MUTABLE; @@ -159,25 +161,25 @@ pub struct PreparedCmp<'w, F, M> { method: &'w M, } -impl<'p, 'w, F, M> ReadOnlyFetch<'p> for PreparedCmp<'w, F, M> +impl<'w, F, M> ReadOnlyFetch for PreparedCmp<'w, F, M> where - F: for<'x> ReadOnlyFetch<'x>, - M: for<'x> CmpMethod<>::Item> + 'w, + F: for<'x> ReadOnlyFetch, + M: for<'x> CmpMethod<::Item<'x>> + 'w, { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { self.fetch.fetch_shared(slot) } } -impl<'q, 'w, F, M> PreparedFetch<'q> for PreparedCmp<'w, F, M> +impl<'w, F, M> PreparedFetch for PreparedCmp<'w, F, M> where - F: for<'x> ReadOnlyFetch<'x>, - M: for<'x> CmpMethod<>::Item> + 'w, + F: for<'x> ReadOnlyFetch, + M: for<'x> CmpMethod<::Item<'x>> + 'w, { - type Item = >::Item; + type Item<'q> = ::Item<'q> where Self: 'q; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.fetch.fetch(slot) } diff --git a/src/filter/constant.rs b/src/filter/constant.rs index 689edb4d..65b10cdd 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -11,8 +11,8 @@ use core::fmt::{self, Formatter}; /// A filter that yields, well, nothing pub struct Nothing; -impl<'q> FetchItem<'q> for Nothing { - type Item = (); +impl FetchItem for Nothing { + type Item<'q> = (); } impl<'a> Fetch<'a> for Nothing { @@ -37,10 +37,10 @@ impl<'a> Fetch<'a> for Nothing { fn access(&self, _data: FetchAccessData, _dst: &mut Vec) {} } -impl<'q> PreparedFetch<'q> for Nothing { - type Item = (); +impl PreparedFetch for Nothing { + type Item<'q> = (); - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} + unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.end, slots.end) @@ -53,8 +53,8 @@ impl<'q> PreparedFetch<'q> for Nothing { #[derive(Debug, Clone)] pub struct All; -impl<'q> FetchItem<'q> for All { - type Item = (); +impl FetchItem for All { + type Item<'q> = (); } impl<'w> Fetch<'w> for All { @@ -77,14 +77,14 @@ impl<'w> Fetch<'w> for All { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'q> PreparedFetch<'q> for All { - type Item = (); +impl PreparedFetch for All { + type Item<'q> = (); - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} + unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> {} } -impl<'q> FetchItem<'q> for Slice { - type Item = (); +impl FetchItem for Slice { + type Item<'q> = (); } impl<'w> Fetch<'w> for Slice { @@ -108,11 +108,11 @@ impl<'w> Fetch<'w> for Slice { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'q> PreparedFetch<'q> for Slice { - type Item = (); +impl PreparedFetch for Slice { + type Item<'q> = (); #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> {} #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -121,8 +121,8 @@ impl<'q> PreparedFetch<'q> for Slice { } } -impl<'q> FetchItem<'q> for bool { - type Item = bool; +impl FetchItem for bool { + type Item<'q> = bool; } impl<'w> Fetch<'w> for bool { @@ -148,11 +148,11 @@ impl<'w> Fetch<'w> for bool { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'q> PreparedFetch<'q> for bool { - type Item = bool; +impl PreparedFetch for bool { + type Item<'q> = bool; #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item { + unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> { *self } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 9699ac36..9c4e5af4 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -80,11 +80,11 @@ impl Filtered { } } -impl<'w, Q, F> FetchItem<'w> for Filtered +impl<'w, Q, F> FetchItem for Filtered where - Q: FetchItem<'w>, + Q: FetchItem, { - type Item = Q::Item; + type Item<'q> = Q::Item<'q>; } impl<'w, Q, F> Fetch<'w> for Filtered @@ -133,15 +133,15 @@ where } } -impl<'q, Q, F> PreparedFetch<'q> for Filtered +impl PreparedFetch for Filtered where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: PreparedFetch, + F: PreparedFetch, { - type Item = Q::Item; + type Item<'q> = Q::Item<'q> where Self: 'q; #[inline(always)] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { self.fetch.fetch(slot) } @@ -190,9 +190,9 @@ impl FilterIter { } } -impl<'q, Q> Iterator for FilterIter +impl Iterator for FilterIter where - Q: PreparedFetch<'q>, + Q: PreparedFetch, { type Item = Slice; @@ -224,7 +224,7 @@ where } } -impl<'q, F: PreparedFetch<'q>> FusedIterator for FilterIter {} +impl FusedIterator for FilterIter {} #[derive(Debug, Clone)] /// Fetch which only yields if the entity has the specified component @@ -233,8 +233,8 @@ pub struct With { pub(crate) name: &'static str, } -impl<'q> FetchItem<'q> for With { - type Item = (); +impl FetchItem for With { + type Item<'q> = (); } impl<'a> Fetch<'a> for With { @@ -269,8 +269,8 @@ pub struct Without { pub(crate) name: &'static str, } -impl<'q> FetchItem<'q> for Without { - type Item = (); +impl FetchItem for Without { + type Item<'q> = (); } impl<'w> Fetch<'w> for Without { @@ -304,8 +304,8 @@ pub(crate) struct WithObject { pub(crate) object: Entity, } -impl<'q> FetchItem<'q> for WithObject { - type Item = (); +impl FetchItem for WithObject { + type Item<'q> = (); } impl<'w> Fetch<'w> for WithObject { @@ -347,8 +347,8 @@ impl core::fmt::Debug for ArchetypeFilter { } } -impl<'q, F> FetchItem<'q> for ArchetypeFilter { - type Item = (); +impl FetchItem for ArchetypeFilter { + type Item<'q> = (); } impl<'w, F: Fn(&Archetype) -> bool> Fetch<'w> for ArchetypeFilter { @@ -378,8 +378,8 @@ pub struct WithRelation { pub(crate) name: &'static str, } -impl<'q> FetchItem<'q> for WithRelation { - type Item = (); +impl FetchItem for WithRelation { + type Item<'q> = (); } impl<'w> Fetch<'w> for WithRelation { @@ -409,8 +409,8 @@ pub struct WithoutRelation { pub(crate) name: &'static str, } -impl<'q> FetchItem<'q> for WithoutRelation { - type Item = (); +impl FetchItem for WithoutRelation { + type Item<'q> = (); } impl<'a> Fetch<'a> for WithoutRelation { @@ -444,11 +444,11 @@ impl<'a, F> Clone for RefFetch<'a, F> { } } -impl<'a, 'q, F> FetchItem<'q> for RefFetch<'a, F> +impl<'a, F> FetchItem for RefFetch<'a, F> where - F: FetchItem<'q>, + F: FetchItem, { - type Item = F::Item; + type Item<'q> = F::Item<'q>; } impl<'a, 'w, F> Fetch<'w> for RefFetch<'a, F> @@ -485,11 +485,11 @@ where } } -impl<'a, 'q, F> FetchItem<'q> for &'a F +impl<'a, F> FetchItem for &'a F where - F: FetchItem<'q>, + F: FetchItem, { - type Item = F::Item; + type Item<'q> = F::Item<'q>; } impl<'a, 'w, F> Fetch<'w> for &'a F @@ -531,19 +531,19 @@ where #[derive(Copy, Debug, Clone)] pub struct BatchSize(pub(crate) Slot); -impl<'q> PreparedFetch<'q> for BatchSize { - type Item = (); +impl PreparedFetch for BatchSize { + type Item<'q> = (); #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + unsafe fn fetch<'q>(&'q mut self, _: usize) -> Self::Item<'q> {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.start, slots.end.min(slots.start + self.0)) } } -impl<'q> FetchItem<'q> for BatchSize { - type Item = (); +impl FetchItem for BatchSize { + type Item<'q> = (); } impl<'w> Fetch<'w> for BatchSize { diff --git a/src/filter/set.rs b/src/filter/set.rs index bb26d950..8ba5728d 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -19,12 +19,12 @@ use core::{ #[derive(Debug, Clone)] pub struct And(pub L, pub R); -impl<'q, L, R> FetchItem<'q> for And +impl FetchItem for And where - L: FetchItem<'q>, - R: FetchItem<'q>, + L: FetchItem, + R: FetchItem, { - type Item = (L::Item, R::Item); + type Item<'q> = (L::Item<'q>, R::Item<'q>); } impl<'w, L, R> Fetch<'w> for And @@ -64,15 +64,15 @@ where } } -impl<'q, L, R> PreparedFetch<'q> for And +impl PreparedFetch for And where - L: PreparedFetch<'q>, - R: PreparedFetch<'q>, + L: PreparedFetch, + R: PreparedFetch, { - type Item = (L::Item, R::Item); + type Item<'q> = (L::Item<'q>, R::Item<'q>) where Self: 'q; #[inline] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch<'q>(&mut self, slot: Slot) -> Self::Item<'q> { (self.0.fetch(slot), self.1.fetch(slot)) } @@ -97,7 +97,7 @@ pub struct Or(pub T); /// Negate a filter pub struct Not(pub T); -impl<'q, T> FetchItem<'q> for Not { +impl FetchItem for Not { type Item = (); } @@ -127,14 +127,14 @@ where } } -impl<'q, F> PreparedFetch<'q> for Not> +impl PreparedFetch for Not> where - F: PreparedFetch<'q>, + F: PreparedFetch, { type Item = (); #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + unsafe fn fetch<'q>(&'q mut self, _: usize) -> Self::Item<'q> {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { if let Some(fetch) = &mut self.0 { @@ -185,17 +185,17 @@ impl ops::Not for Not { #[derive(Debug, Clone)] pub struct Union(pub T); -impl<'q, T> FetchItem<'q> for Union +impl FetchItem for Union where - T: FetchItem<'q>, + T: FetchItem, { - type Item = T::Item; + type Item<'q> = T::Item<'q>; } impl<'w, T> Fetch<'w> for Union where T: Fetch<'w>, - T::Prepared: for<'q> UnionFilter<'q>, + T::Prepared: UnionFilter, { const MUTABLE: bool = T::MUTABLE; @@ -218,22 +218,22 @@ where } } -impl<'q, T> UnionFilter<'q> for Union +impl UnionFilter for Union where - T: UnionFilter<'q>, + T: UnionFilter, { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { self.0.filter_union(slots) } } -impl<'q, T> PreparedFetch<'q> for Union +impl PreparedFetch for Union where - T: PreparedFetch<'q> + UnionFilter<'q>, + T: PreparedFetch + UnionFilter, { - type Item = T::Item; + type Item<'q> = T::Item<'q> where Self: 'q; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + unsafe fn fetch<'q>(&mut self, slot: usize) -> Self::Item<'q> { self.0.fetch(slot) } @@ -249,8 +249,8 @@ where macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { // Or - impl<'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { - type Item = (); + impl< $($ty, )*> FetchItem<> for Or<($($ty,)*)> { + type Item<'q> = (); } impl<'w, $($ty, )*> Fetch<'w> for Or<($($ty,)*)> @@ -284,8 +284,8 @@ macro_rules! tuple_impl { } - impl<'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)> - where $($ty: PreparedFetch<'q>,)* + impl< $($ty, )*> PreparedFetch<> for Or<($(Option<$ty>,)*)> + where $($ty: PreparedFetch<>,)* { type Item = (); @@ -302,7 +302,7 @@ macro_rules! tuple_impl { } #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + unsafe fn fetch<'q>(&'q mut self, _: usize) -> Self::Item<'q> {} fn set_visited(&mut self, slots: Slice) { $( self.0.$idx.set_visited(slots);)* @@ -311,8 +311,8 @@ macro_rules! tuple_impl { } - impl<'q, $($ty, )*> UnionFilter<'q> for Or<($(Option<$ty>,)*)> - where $($ty: PreparedFetch<'q>,)* + impl< $($ty, )*> UnionFilter for Or<($(Option<$ty>,)*)> + where $($ty: PreparedFetch,)* { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { let inner = &mut self.0; diff --git a/src/query/borrow.rs b/src/query/borrow.rs index 729dd6e0..3779fe0d 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -17,8 +17,8 @@ impl<'w, Q, F> PreparedArchetype<'w, Q, F> { #[inline] pub fn manual_chunk<'q>(&'q mut self, slots: Slice) -> Option> where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: PreparedFetch, + F: PreparedFetch, { let chunk = unsafe { self.fetch.filter_slots(slots) }; if chunk.is_empty() { @@ -85,10 +85,10 @@ struct BatchesWithId<'q, Q, F> { impl<'q, Q, F> Iterator for BatchesWithId<'q, Q, F> where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: PreparedFetch, + F: PreparedFetch, { - type Item = (Entity, Q::Item); + type Item = (Entity, Q::Item<'q>); fn next(&mut self) -> Option { loop { diff --git a/src/query/dfs.rs b/src/query/dfs.rs index b6e35bfa..0ad8bb08 100644 --- a/src/query/dfs.rs +++ b/src/query/dfs.rs @@ -212,7 +212,7 @@ where /// `visit(query, edge, value)` where `value` is the return value of the visit. pub fn traverse_from(&mut self, root: Entity, value: &V, mut visit: Visit) where - Visit: for<'q> FnMut(>::Item, Option<&T>, &V) -> V, + Visit: for<'q> FnMut(::Item<'q>, Option<&T>, &V) -> V, { let Ok(loc) = self.query_state.world.location(root) else { return; @@ -242,7 +242,7 @@ where /// `visit(query, edge, value)` where `value` is the return value of the parent. pub fn traverse(&mut self, value: &V, mut visit: Visit) where - Visit: for<'q> FnMut(>::Item, Option<&T>, &V) -> V, + Visit: for<'q> FnMut(::Item<'q>, Option<&T>, &V) -> V, { let dfs = &self.dfs; let prepared = (&mut self.prepared[..]) as *mut [_] as *mut PreparedArchetype<_, _>; @@ -274,7 +274,7 @@ where value: &V, visit: &mut Visit, ) where - Visit: for<'q> FnMut(>::Item, Option<&T>, &V) -> V, + Visit: for<'q> FnMut(::Item<'q>, Option<&T>, &V) -> V, Q: 'w, F: 'w, { @@ -353,7 +353,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = >::Item; + type Item = ::Item<'q>; fn next(&mut self) -> Option { loop { diff --git a/src/query/entity.rs b/src/query/entity.rs index 4e9df741..8081d20c 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -104,7 +104,7 @@ where /// Returns the results of the fetch. /// /// Fails if the entity does not exist, or the fetch isn't matched. - pub fn get<'q>(&'q mut self) -> Result<>::Item> + pub fn get<'q>(&'q mut self) -> Result<::Item<'q>> where 'w: 'q, { diff --git a/src/query/iter.rs b/src/query/iter.rs index 40db700e..01edb906 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -57,12 +57,12 @@ impl<'q, Q, F> Batch<'q, Q, F> { impl<'q, Q, F> Iterator for Batch<'q, Q, F> where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: PreparedFetch, + F: PreparedFetch, { - type Item = Q::Item; + type Item = Q::Item<'q>; - fn next(&mut self) -> Option { + fn next(&mut self) -> Option> { if self.pos == self.end { None } else { @@ -76,10 +76,10 @@ where impl<'q, Q, F> Batch<'q, Q, F> where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: PreparedFetch, + F: PreparedFetch, { - pub(crate) fn next_with_id(&mut self) -> Option<(Entity, Q::Item)> { + pub(crate) fn next_with_id(&mut self) -> Option<(Entity, Q::Item<'q>)> { if self.pos == self.end { None } else { @@ -91,7 +91,7 @@ where } } - pub(crate) fn next_full(&mut self) -> Option<(Slot, Entity, Q::Item)> { + pub(crate) fn next_full(&mut self) -> Option<(Slot, Entity, Q::Item<'q>)> { if self.pos == self.end { None } else { @@ -116,8 +116,8 @@ pub struct ArchetypeChunks<'q, Q, F> { impl<'q, Q, F> Iterator for ArchetypeChunks<'q, Q, F> where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: PreparedFetch, + F: PreparedFetch, { type Item = Batch<'q, Q, F>; diff --git a/src/query/mod.rs b/src/query/mod.rs index 6522f84f..d3dc0fab 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -182,7 +182,7 @@ where pub fn collect_vec<'w, T>(&'w mut self, world: &'w World) -> Vec where T: 'static, - Q: for<'q> FetchItem<'q, Item = T>, + Q: for<'q> FetchItem = T>, { let mut borrow = self.borrow(world); borrow.iter().collect() diff --git a/src/query/planar.rs b/src/query/planar.rs index a49db0af..db7fe842 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -130,7 +130,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = >::Item; + type Item = ::Item<'q>; type IntoIter = QueryIter<'w, 'q, Q, F>; @@ -156,7 +156,7 @@ where } /// Returns the first item - pub fn first(&mut self) -> Option<>::Item> { + pub fn first(&mut self) -> Option<::Item<'_>> { self.iter().next() } @@ -193,7 +193,7 @@ where /// /// This is more efficient than `.iter().for_each(|v| {})` as the archetypes can be temporarily /// borrowed. - pub fn for_each(&mut self, mut func: impl FnMut(>::Item) + Send + Sync) { + pub fn for_each(&mut self, mut func: impl FnMut(::Item<'_>) + Send + Sync) { self.clear_borrows(); for &arch_id in self.archetypes { let arch = self.state.world.archetypes.get(arch_id); @@ -218,7 +218,7 @@ where /// .for_each(|v| v.for_each(&func)) /// ``` #[cfg(feature = "parallel")] - pub fn par_for_each(&mut self, func: impl Fn(>::Item) + Send + Sync) + pub fn par_for_each(&mut self, func: impl Fn(::Item<'_>) + Send + Sync) where Q: Sync, Q::Prepared: Send, @@ -270,7 +270,7 @@ where } /// Get the fetch items for an entity. - pub fn get(&mut self, id: Entity) -> Result<::Item> { + pub fn get(&mut self, id: Entity) -> Result<::Item<'_>> { let EntityLocation { arch_id, slot } = self.state.world.location(id)?; let idx = @@ -313,7 +313,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = >::Item; + type Item = ::Item<'q>; #[inline(always)] fn next(&mut self) -> Option { diff --git a/src/query/topo.rs b/src/query/topo.rs index 0d3c0b6b..63378ca5 100644 --- a/src/query/topo.rs +++ b/src/query/topo.rs @@ -186,7 +186,7 @@ where Q: Fetch<'w>, F: Fetch<'w>, { - type Item = >::Item; + type Item = ::Item<'q>; type IntoIter = TopoIter<'w, 'q, Q, F>; @@ -238,7 +238,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = >::Item; + type Item = ::Item<'q>; #[inline] fn next(&mut self) -> Option { diff --git a/src/query/walk.rs b/src/query/walk.rs index 5034b685..9630871a 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -234,7 +234,7 @@ where pub fn get<'q>( &self, borrow: &'q mut GraphBorrow<'w, Q, F>, - ) -> Option<>::Item> + ) -> Option<::Item<'q>> where Q: Fetch<'w>, F: Fetch<'w>, diff --git a/src/system/mod.rs b/src/system/mod.rs index edb4bc3c..9d6764d3 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -57,7 +57,7 @@ impl<'a, Func, Q, F> SystemFn<'a, (QueryData<'a, Q, F>,), ()> for ForEach where for<'x> Q: Fetch<'x>, for<'x> F: Fetch<'x>, - for<'x> Func: FnMut(>::Item), + for<'x> Func: FnMut(::Item<'x>), { fn execute(&mut self, mut data: (QueryData,)) { for item in &mut data.0.borrow() { @@ -79,7 +79,7 @@ where for<'x> F: Fetch<'x>, for<'x> >::Prepared: Send, for<'x> >::Prepared: Send, - for<'x> Func: Fn(>::Item) + Send + Sync, + for<'x> Func: Fn(::Item<'x>) + Send + Sync, { fn execute(&mut self, mut data: (QueryData,)) { let mut borrow = data.0.borrow(); @@ -98,7 +98,7 @@ where /// Execute a function for each item in the query pub fn for_each(self, func: Func) -> System, (Query,), (), T> where - for<'x> Func: FnMut(>::Item), + for<'x> Func: FnMut(::Item<'x>), { System::new( self.name.unwrap_or_else(|| type_name::().to_string()), @@ -120,7 +120,7 @@ where /// Execute a function for each item in the query in parallel batches pub fn par_for_each(self, func: Func) -> System, (Query,), (), T> where - for<'x> Func: Fn(>::Item) + Send + Sync, + for<'x> Func: Fn(::Item<'x>) + Send + Sync, { System::new( self.name.unwrap_or_else(|| type_name::().to_string()), From df198d272e1e3f16355cd71cd0e9afabf5869188 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 2 Jul 2023 23:28:44 +0200 Subject: [PATCH 14/52] Revert "chore: attempt to use GAT" This reverts commit 53ea861a0f0e7a8def1ffe247ac104489d69f47a. --- asteroids/src/main.rs | 2 +- flax-derive/src/lib.rs | 8 ++-- src/fetch/as_deref.rs | 22 +++++----- src/fetch/cloned.rs | 24 +++++------ src/fetch/component.rs | 14 +++--- src/fetch/component_mut.rs | 10 ++--- src/fetch/copied.rs | 24 +++++------ src/fetch/entity_ref.rs | 10 ++--- src/fetch/ext.rs | 5 +-- src/fetch/maybe_mut.rs | 14 +++--- src/fetch/mod.rs | 87 ++++++++++++++++++-------------------- src/fetch/opt.rs | 34 +++++++-------- src/fetch/read_only.rs | 10 ++--- src/fetch/relations.rs | 14 +++--- src/fetch/satisfied.rs | 10 ++--- src/fetch/source.rs | 23 +++++----- src/fetch/transform.rs | 13 +++--- src/filter/change.rs | 23 +++++----- src/filter/cmp.rs | 30 ++++++------- src/filter/constant.rs | 40 +++++++++--------- src/filter/mod.rs | 68 ++++++++++++++--------------- src/filter/set.rs | 60 +++++++++++++------------- src/query/borrow.rs | 10 ++--- src/query/dfs.rs | 8 ++-- src/query/entity.rs | 2 +- src/query/iter.rs | 20 ++++----- src/query/mod.rs | 2 +- src/query/planar.rs | 12 +++--- src/query/topo.rs | 4 +- src/query/walk.rs | 2 +- src/system/mod.rs | 8 ++-- 31 files changed, 302 insertions(+), 311 deletions(-) diff --git a/asteroids/src/main.rs b/asteroids/src/main.rs index 012ee73a..594661ca 100644 --- a/asteroids/src/main.rs +++ b/asteroids/src/main.rs @@ -481,7 +481,7 @@ const PLUME_COOLDOWN: f32 = 0.02; /// and refactoring. #[derive(Fetch)] // Ensures the fetch item is debuggable -#[fetch(item = [Debug])] +#[fetch(Debug)] struct PlayerQuery { id: EntityIds, player: Component<()>, diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 1390bf42..fe71b17b 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -248,9 +248,9 @@ fn derive_modified(params: &Params) -> TokenStream { impl #trait_name for #fetch_name { type Output = #crate_name::filter::Union<#transformed_name<#(<#field_types as #trait_name>::Output,)*>>; - fn transform_fetch(self, method: #crate_name::fetch::Modified) -> Self::Output { + fn transform_fetch(self) -> Self::Output { #crate_name::filter::Union(#transformed_name { - #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names, method),)* + #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names),)* }) } } @@ -300,10 +300,10 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[automatically_derived] - impl #prep_impl #crate_name::fetch::PreparedFetch for #prepared_name #prep_ty + impl #prep_impl #crate_name::fetch::PreparedFetch<#q_lf> for #prepared_name #prep_ty where #(#field_types: 'static,)* { - type Item<#q_lf> = #item_name #item_ty; + type Item = #item_name #item_ty; #[inline] unsafe fn fetch(&'q mut self, slot: #crate_name::archetype::Slot) -> Self::Item { diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index 2901114b..8d9158a2 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -6,18 +6,18 @@ use core::{fmt, ops::Deref}; /// Dereferences the fetch item pub struct AsDeref(pub(crate) F); -impl FetchItem for AsDeref +impl<'q, F, V> FetchItem<'q> for AsDeref where - F: for<'q> FetchItem = &'q V>, + F: FetchItem<'q, Item = &'q V>, V: 'static + Deref, { - type Item<'q> = &'q V::Target; + type Item = &'q V::Target; } impl<'w, F, V> Fetch<'w> for AsDeref where F: Fetch<'w>, - F: for<'q> FetchItem = &'q V>, + F: for<'q> FetchItem<'q, Item = &'q V>, V: 'static + Deref, { const MUTABLE: bool = F::MUTABLE; @@ -50,14 +50,14 @@ where } } -impl PreparedFetch for AsDeref +impl<'q, F, V> PreparedFetch<'q> for AsDeref where - for<'q> F: PreparedFetch = &'q V> + 'q, + F: PreparedFetch<'q, Item = &'q V>, V: 'static + Deref, { - type Item<'q> = &'q V::Target where Self: 'q; + type Item = &'q V::Target; - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.0.fetch(slot) } @@ -70,12 +70,12 @@ where } } -impl ReadOnlyFetch for AsDeref +impl<'q, F, V> ReadOnlyFetch<'q> for AsDeref where - for<'q> F: ReadOnlyFetch = &'q V> + 'q, + F: ReadOnlyFetch<'q, Item = &'q V>, V: 'static + Deref, { - unsafe fn fetch_shared<'q>(&self, slot: crate::archetype::Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { self.0.fetch_shared(slot) } } diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index bd5571ea..0ea3d0a4 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -20,9 +20,9 @@ use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; /// See [crate::Component::as_mut] pub struct Cloned(pub(crate) F); -impl FetchItem for Cloned +impl<'q, F, V> FetchItem<'q> for Cloned where - F: for<'q> FetchItem = &'q V>, + F: FetchItem<'q, Item = &'q V>, V: 'static, { type Item = V; @@ -31,7 +31,7 @@ where impl<'w, F, V> Fetch<'w> for Cloned where F: Fetch<'w>, - F: for<'q> FetchItem = &'q V>, + F: for<'q> FetchItem<'q, Item = &'q V>, V: 'static + Clone, { const MUTABLE: bool = F::MUTABLE; @@ -62,16 +62,16 @@ where } } -impl PreparedFetch for Cloned +impl<'q, F, V> PreparedFetch<'q> for Cloned where - F: PreparedFetch, - for<'q> F::Item<'q>: Deref, + F: PreparedFetch<'q>, + F::Item: Deref, V: 'static + Clone, { - type Item<'q> = V where Self: 'q; + type Item = V; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.0.fetch(slot).clone() } @@ -86,13 +86,13 @@ where } } -impl ReadOnlyFetch for Cloned +impl<'q, V, F> ReadOnlyFetch<'q> for Cloned where - F: ReadOnlyFetch, - for<'q> F::Item<'q>: Deref, + F: ReadOnlyFetch<'q>, + F::Item: Deref, V: 'static + Clone, { - unsafe fn fetch_shared<'q>(&'q self, slot: crate::archetype::Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { self.0.fetch_shared(slot).clone() } } diff --git a/src/fetch/component.rs b/src/fetch/component.rs index abd27faf..04bb4755 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -9,18 +9,18 @@ pub struct ReadComponent<'a, T> { borrow: AtomicRef<'a, [T]>, } -impl<'w, T: 'static> PreparedFetch for ReadComponent<'w, T> { - type Item<'q> = &'q T; +impl<'q, 'w, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { + type Item = &'q T; #[inline(always)] - unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { // Safety: bounds guaranteed by callee unsafe { self.borrow.get_unchecked(slot) } } } -impl<'w, T: ComponentValue> ReadOnlyFetch for ReadComponent<'w, T> { - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { +impl<'w, 'p, T: ComponentValue> ReadOnlyFetch<'p> for ReadComponent<'w, T> { + unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { self.borrow.get_unchecked(slot) } } @@ -65,6 +65,6 @@ where } } -impl FetchItem for Component { - type Item<'q> = &'q T; +impl<'q, T: ComponentValue> FetchItem<'q> for Component { + type Item = &'q T; } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 20246280..3aa3e750 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -89,15 +89,15 @@ where } } -impl FetchItem for Mutable { - type Item<'q> = &'q mut T; +impl<'q, T: ComponentValue> FetchItem<'q> for Mutable { + type Item = &'q mut T; } -impl<'w, T: 'static> PreparedFetch for WriteComponent<'w, T> { - type Item<'q> = &'q mut T; +impl<'q, 'w, T: 'q> PreparedFetch<'q> for WriteComponent<'w, T> { + type Item = &'q mut T; #[inline(always)] - unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { // Perform a reborrow // Cast from a immutable to a mutable borrow as all calls to this // function are guaranteed to be disjoint diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index aa545277..1b4df019 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -20,18 +20,18 @@ use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; /// See [crate::Component::as_mut] pub struct Copied(pub(crate) F); -impl FetchItem for Copied +impl<'q, F, V> FetchItem<'q> for Copied where - F: for<'q> FetchItem = &'q V>, + F: FetchItem<'q, Item = &'q V>, V: 'static, { - type Item<'q> = V; + type Item = V; } impl<'w, F, V> Fetch<'w> for Copied where F: Fetch<'w>, - F: for<'q> FetchItem = &'q V>, + F: for<'q> FetchItem<'q, Item = &'q V>, V: 'static + Copy, { const MUTABLE: bool = F::MUTABLE; @@ -63,16 +63,16 @@ where } } -impl PreparedFetch for Copied +impl<'q, F, V> PreparedFetch<'q> for Copied where - F: PreparedFetch, - for<'q> F::Item<'q>: Deref, + F: PreparedFetch<'q>, + F::Item: Deref, V: 'static + Copy, { type Item = V; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { *self.0.fetch(slot) } @@ -87,13 +87,13 @@ where } } -impl ReadOnlyFetch for Copied +impl<'p, F, V> ReadOnlyFetch<'p> for Copied where - F: ReadOnlyFetch, - for<'q> F::Item<'q>: Deref, + F: ReadOnlyFetch<'p>, + F::Item: Deref, V: 'static + Copy, { - unsafe fn fetch_shared<'q>(&'q self, slot: crate::archetype::Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'p self, slot: crate::archetype::Slot) -> Self::Item { *self.0.fetch_shared(slot) } } diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index 78d36a64..6ea5e686 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -16,8 +16,8 @@ pub fn entity_refs() -> EntityRefs { EntityRefs } -impl FetchItem for EntityRefs { - type Item<'q> = EntityRef<'q>; +impl<'q> FetchItem<'q> for EntityRefs { + type Item = EntityRef<'q>; } impl<'w> Fetch<'w> for EntityRefs { @@ -59,11 +59,11 @@ pub struct PreparedEntityRef<'a> { arch: &'a Archetype, } -impl<'w> PreparedFetch for PreparedEntityRef<'w> { - type Item<'q> = EntityRef<'q>; +impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { + type Item = EntityRef<'q>; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: crate::archetype::Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { EntityRef { arch: self.arch, slot, diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index 054c5978..27a604e7 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -7,7 +7,6 @@ use super::{ as_deref::AsDeref, cloned::Cloned, copied::Copied, - map::Map, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, Modified, Satisfied, Source, TransformFetch, @@ -26,7 +25,7 @@ pub trait FetchExt: Sized { fn opt_or(self, default: V) -> OptOr where Self: for<'w> Fetch<'w>, - for<'q> Self: FetchItem = &'q V>, + for<'q> Self: FetchItem<'q, Item = &'q V>, { OptOr::new(self, default) } @@ -41,7 +40,7 @@ pub trait FetchExt: Sized { fn opt_or_default(self) -> OptOr where Self: for<'w> Fetch<'w>, - for<'q> Self: FetchItem = &'q V>, + for<'q> Self: FetchItem<'q, Item = &'q V>, V: Default, { self.opt_or(Default::default()) diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index 05298814..ae1d54e7 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -19,8 +19,8 @@ use super::{FetchAccessData, PreparedFetch, ReadOnlyFetch}; /// to the loop body, rather than the iterator. pub struct MaybeMut(pub(crate) Component); -impl FetchItem for MaybeMut { - type Item<'q> = MutGuard<'q, T>; +impl<'q, T: ComponentValue> FetchItem<'q> for MaybeMut { + type Item = MutGuard<'q, T>; } impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut { @@ -87,11 +87,11 @@ pub struct PreparedMaybeMut<'w, T> { _marker: PhantomData, } -impl<'w, T: ComponentValue> PreparedFetch for PreparedMaybeMut<'w, T> { - type Item<'q> = MutGuard<'q, T>; +impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { + type Item = MutGuard<'q, T>; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { MutGuard { slot, cell: self.cell, @@ -102,9 +102,9 @@ impl<'w, T: ComponentValue> PreparedFetch for PreparedMaybeMut<'w, T> { } } -impl<'w, T: ComponentValue> ReadOnlyFetch for PreparedMaybeMut<'w, T> { +impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { #[inline] - unsafe fn fetch_shared<'q>(&'q self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch_shared(&'q self, slot: usize) -> Self::Item { MutGuard { slot, cell: self.cell, diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 00338cd8..641b5939 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -5,7 +5,6 @@ mod component_mut; mod copied; mod entity_ref; mod ext; -mod map; mod maybe_mut; mod opt; mod read_only; @@ -77,9 +76,9 @@ pub struct FetchPrepareData<'w> { } /// Trait which gives an associated `Item` fetch type -pub trait FetchItem { +pub trait FetchItem<'q> { /// The item yielded by the prepared fetch - type Item<'q>; + type Item; } /// A fetch describes a retrieval of data from the world and archetypes during a query. @@ -89,12 +88,12 @@ pub trait FetchItem { /// /// The PreparedFetch can in turn control the ranges of slots which are requested by the query, /// e.g; filtering changed components -pub trait Fetch<'w>: FetchItem { +pub trait Fetch<'w>: for<'q> FetchItem<'q> { /// true if the fetch mutates any component and thus needs a change event const MUTABLE: bool; /// The prepared version of the fetch - type Prepared: for<'x> PreparedFetch = ::Item<'x>> + 'w; + type Prepared: for<'x> PreparedFetch<'x, Item = >::Item> + 'w; /// Prepares the fetch for an archetype by acquiring borrows. /// @@ -127,11 +126,9 @@ pub trait Fetch<'w>: FetchItem { } /// Borrowed state for a fetch -pub trait PreparedFetch { +pub trait PreparedFetch<'q> { /// Item returned by fetch - type Item<'q>: 'q - where - Self: 'q; + type Item: 'q; /// Fetch the item from entity at the slot in the prepared storage. /// # Safety @@ -139,7 +136,7 @@ pub trait PreparedFetch { /// prepared archetype. /// /// The callee is responsible for assuring disjoint calls. - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q>; + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item; #[inline] /// Filter the slots to visit @@ -158,7 +155,7 @@ pub trait PreparedFetch { } /// Allows filtering the constituent parts of a fetch using a set union -pub trait UnionFilter { +pub trait UnionFilter<'q> { // Filter the slots using a union operation of the constituent part /// /// # Safety @@ -166,13 +163,13 @@ pub trait UnionFilter { unsafe fn filter_union(&mut self, slots: Slice) -> Slice; } -impl PreparedFetch for &mut F +impl<'q, F> PreparedFetch<'q> for &'q mut F where - F: PreparedFetch, + F: PreparedFetch<'q>, { - type Item<'q> = F::Item<'q>where F: 'q; + type Item = F::Item; - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { (*self).fetch(slot) } @@ -185,11 +182,11 @@ where } } -impl FetchItem for () { +impl<'q> FetchItem<'q> for () { type Item = (); } -impl UnionFilter for () { +impl<'q> UnionFilter<'q> for () { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { slots } @@ -216,25 +213,24 @@ impl<'w> Fetch<'w> for () { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl ReadOnlyFetch for () { - unsafe fn fetch_shared<'q>(&'q self, _: Slot) -> Self::Item<'q> {} +impl<'p> ReadOnlyFetch<'p> for () { + unsafe fn fetch_shared(&'p self, _: Slot) -> Self::Item {} } -impl PreparedFetch for () { - type Item<'q> = (); +impl<'q> PreparedFetch<'q> for () { + type Item = (); - unsafe fn fetch<'q>(&'q mut self, _: Slot) -> Self::Item<'q> {} + unsafe fn fetch(&'q mut self, _: Slot) -> Self::Item {} } -impl PreparedFetch for Option +impl<'q, F> PreparedFetch<'q> for Option where - F: PreparedFetch, + F: PreparedFetch<'q>, { - type Item<'q> = Option>where - Self: 'q; + type Item = Option; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.as_mut().map(|fetch| fetch.fetch(slot)) } @@ -263,7 +259,7 @@ pub struct ReadEntities<'a> { entities: &'a [Entity], } -impl FetchItem for EntityIds { +impl<'q> FetchItem<'q> for EntityIds { type Item = Entity; } @@ -290,18 +286,18 @@ impl<'w> Fetch<'w> for EntityIds { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'w> PreparedFetch for ReadEntities<'w> { - type Item<'q> = Entity; +impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { + type Item = Entity; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&mut self, slot: usize) -> Self::Item { self.entities[slot] } } -impl<'w> ReadOnlyFetch for ReadEntities<'w> { +impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { #[inline] - unsafe fn fetch_shared<'q>(&'q self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch_shared(&self, slot: usize) -> Self::Item { self.entities[slot] } } @@ -309,19 +305,19 @@ impl<'w> ReadOnlyFetch for ReadEntities<'w> { // Implement for tuples macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { - impl<$($ty, )*> FetchItem for ($($ty,)*) - where $($ty: FetchItem,)* + impl<'q, $($ty, )*> FetchItem<'q> for ($($ty,)*) + where $($ty: FetchItem<'q>,)* { - type Item<'q> = ($($ty::Item<'q>,)*); + type Item = ($($ty::Item,)*); } - impl<$($ty, )*> ReadOnlyFetch for ($($ty,)*) - where $($ty: ReadOnlyFetch,)* + impl<'q, $($ty, )*> ReadOnlyFetch<'q> for ($($ty,)*) + where $($ty: ReadOnlyFetch<'q>,)* { #[inline(always)] - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { ($( (self.$idx).fetch_shared(slot), )*) @@ -329,14 +325,13 @@ macro_rules! tuple_impl { } - impl<$($ty, )*> PreparedFetch for ($($ty,)*) - where $($ty: PreparedFetch,)* + impl<'q, $($ty, )*> PreparedFetch<'q> for ($($ty,)*) + where $($ty: PreparedFetch<'q>,)* { - type Item<'q> = ($($ty::Item<'q>,)*) where Self: 'q; - + type Item = ($($ty::Item,)*); #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { ($( (self.$idx).fetch(slot), )*) @@ -358,8 +353,8 @@ macro_rules! tuple_impl { } } - impl<$($ty, )*> UnionFilter for ($($ty,)*) - where $($ty: PreparedFetch,)* + impl<'q, $($ty, )*> UnionFilter<'q> for ($($ty,)*) + where $($ty: PreparedFetch<'q>,)* { #[inline] diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 40acc9cb..862906f5 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -16,8 +16,8 @@ use super::{FetchAccessData, FetchItem, ReadOnlyFetch}; #[derive(Debug, Clone)] pub struct Opt(pub(crate) F); -impl FetchItem for Opt { - type Item<'q> = Option>; +impl<'q, F: FetchItem<'q>> FetchItem<'q> for Opt { + type Item = Option; } impl<'w, F> Fetch<'w> for Opt @@ -49,23 +49,23 @@ where #[doc(hidden)] pub struct PreparedOpt(pub(crate) Option); -impl<'p, F> ReadOnlyFetch for PreparedOpt +impl<'p, F> ReadOnlyFetch<'p> for PreparedOpt where - F: ReadOnlyFetch, + F: ReadOnlyFetch<'p>, { - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { self.0.as_ref().map(|fetch| fetch.fetch_shared(slot)) } } -impl PreparedFetch for PreparedOpt +impl<'q, F> PreparedFetch<'q> for PreparedOpt where - F: PreparedFetch, + F: PreparedFetch<'q>, { - type Item<'q> = Option> where Self: 'q; + type Item = Option; #[inline] - unsafe fn fetch<'q>(&mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.0.as_mut().map(|fetch| fetch.fetch(slot)) } @@ -101,8 +101,8 @@ impl OptOr { impl<'w, F, V> Fetch<'w> for OptOr where - F: Fetch<'w> + for<'q> FetchItem = &'q V>, - OptOr, &'w V>: PreparedFetch, + F: Fetch<'w> + for<'q> FetchItem<'q, Item = &'q V>, + for<'q> F::Prepared: PreparedFetch<'q, Item = &'q V>, V: ComponentValue, { const MUTABLE: bool = F::MUTABLE; @@ -131,18 +131,18 @@ where } } -impl FetchItem = &'q V>, V: ComponentValue> FetchItem for OptOr { - type Item<'q> = &'q V; +impl<'q, F: FetchItem<'q, Item = &'q V>, V: ComponentValue> FetchItem<'q> for OptOr { + type Item = &'q V; } -impl<'w, F, V> PreparedFetch for OptOr, &'w V> +impl<'q, 'w, F, V> PreparedFetch<'q> for OptOr, &'w V> where - for<'q> F: PreparedFetch = &'q V> + 'q, + F: PreparedFetch<'q, Item = &'q V>, V: 'static, { - type Item<'q> = &'q V where Self: 'q; + type Item = &'q V; - unsafe fn fetch<'q>(&'q mut self, slot: crate::archetype::Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { match self.fetch { Some(ref mut v) => v.fetch(slot), None => self.or, diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index 135b1c12..b8d70cec 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -5,19 +5,19 @@ use super::PreparedFetch; /// A fetch which only yields items which can freely *alias*. /// /// This makes the `fetch` method *safer* to implement and can be called with a covariant lifetime. -pub trait ReadOnlyFetch: PreparedFetch { +pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { /// Fetch the shared item from the given slot /// /// # Safety /// Slot must be valid - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q>; + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; } -impl ReadOnlyFetch for Option +impl<'p, F> ReadOnlyFetch<'p> for Option where - F: ReadOnlyFetch, + F: ReadOnlyFetch<'p>, { - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { self.as_ref().map(|fetch| fetch.fetch_shared(slot)) } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 8fade529..4d950828 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -72,8 +72,8 @@ where } } -impl FetchItem for Relations { - type Item<'q> = RelationsIter<'q, T>; +impl<'q, T: ComponentValue> FetchItem<'q> for Relations { + type Item = RelationsIter<'q, T>; } #[doc(hidden)] @@ -81,13 +81,13 @@ pub struct PreparedRelations<'a, T> { borrows: SmallVec<[(Entity, AtomicRef<'a, [T]>); 4]>, } -impl<'w, T> PreparedFetch for PreparedRelations<'w, T> +impl<'q, 'w, T> PreparedFetch<'q> for PreparedRelations<'w, T> where T: ComponentValue, { - type Item<'q> = RelationsIter<'q, T>; + type Item = RelationsIter<'q, T>; - unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { RelationsIter { borrows: self.borrows.iter(), slot, @@ -101,8 +101,8 @@ pub struct RelationsIter<'a, T> { slot: Slot, } -impl<'q, T> Iterator for RelationsIter<'q, T> { - type Item = (Entity, &'q T); +impl<'a, T> Iterator for RelationsIter<'a, T> { + type Item = (Entity, &'a T); fn next(&mut self) -> Option { let (id, borrow) = self.borrows.next()?; diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 1e367822..c99c6a76 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -10,8 +10,8 @@ use super::{FmtQuery, PreparedFetch}; /// Yields true iff `F` would match the query pub struct Satisfied(pub(crate) F); -impl FetchItem for Satisfied { - type Item<'q> = bool; +impl<'q, F: FetchItem<'q>> FetchItem<'q> for Satisfied { + type Item = bool; } impl<'w, F: Fetch<'w>> Fetch<'w> for Satisfied { @@ -41,10 +41,10 @@ impl<'w, F: Fetch<'w>> Fetch<'w> for Satisfied { #[doc(hidden)] pub struct PreparedSatisfied(Option); -impl PreparedFetch for PreparedSatisfied { - type Item<'q> = bool; +impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { + type Item = bool; - unsafe fn fetch<'q>(&'q mut self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { if let Some(fetch) = &mut self.0 { !fetch.filter_slots(Slice::single(slot)).is_empty() } else { diff --git a/src/fetch/source.rs b/src/fetch/source.rs index 6fb2561e..a55e5b54 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -79,18 +79,18 @@ impl Source { } } -impl FetchItem for Source +impl<'q, Q, S> FetchItem<'q> for Source where - Q: FetchItem, + Q: FetchItem<'q>, S: FetchSource, { - type Item<'q> = Q::Item<'q>; + type Item = Q::Item; } impl<'w, Q, S> Fetch<'w> for Source where Q: Fetch<'w>, - PreparedSource: PreparedFetch, + Q::Prepared: for<'x> ReadOnlyFetch<'x>, S: FetchSource, { const MUTABLE: bool = Q::MUTABLE; @@ -146,23 +146,22 @@ where } } -impl ReadOnlyFetch for PreparedSource +impl<'q, Q> ReadOnlyFetch<'q> for PreparedSource where - Q: ReadOnlyFetch, + Q: ReadOnlyFetch<'q>, { - unsafe fn fetch_shared<'q>(&'q self, _: crate::archetype::Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'q self, _: crate::archetype::Slot) -> Self::Item { self.fetch.fetch_shared(self.slot) } } -impl PreparedFetch for PreparedSource +impl<'q, Q> PreparedFetch<'q> for PreparedSource where - Q: ReadOnlyFetch, + Q: ReadOnlyFetch<'q>, { - type Item<'q> = Q::Item<'q> where Self: 'q; + type Item = Q::Item; - #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.fetch_shared(slot) } diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index bdf9da29..406fd0b6 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -1,4 +1,4 @@ -use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch, FetchItem}; +use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch}; /// Allows transforming a fetch into another. /// @@ -10,26 +10,25 @@ pub trait TransformFetch: for<'w> Fetch<'w> { /// May of may not have the same `Item` type Output; /// Transform the fetch using the provided method - fn transform_fetch(self, method: Method) -> Self::Output; + fn transform_fetch(self) -> Self::Output; } impl TransformFetch for Component { type Output = ChangeFilter; - fn transform_fetch(self, _: Modified) -> Self::Output { + fn transform_fetch(self) -> Self::Output { self.modified() } } /// Marker for a fetch which has been transformed to filter modified items. -#[derive(Debug, Clone, Copy)] pub struct Modified; macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { type Output = Union<($($ty::Output,)*)>; - fn transform_fetch(self, method: Modified) -> Self::Output { - Union(($(self.$idx.transform_fetch(method),)*)) + fn transform_fetch(self) -> Self::Output { + Union(($(self.$idx.transform_fetch(),)*)) } } }; @@ -169,7 +168,7 @@ mod tests { .spawn(&mut world); let query = MyFetch { a: a(), b: b() }.modified(); - let mut query = Query::new((entity_ids(), query).map(|(id, v)| (id, v.a, v.b))); + let mut query = Query::new((entity_ids(), query)); let mut collect = move |world| { query diff --git a/src/filter/change.rs b/src/filter/change.rs index fcc6802a..174f7bb2 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -39,19 +39,19 @@ impl ChangeFilter { } } -impl FetchItem for ChangeFilter +impl<'q, T> FetchItem<'q> for ChangeFilter where T: ComponentValue, { - type Item<'q> = &'q T; + type Item = &'q T; } -impl ReadOnlyFetch for PreparedChangeFilter +impl<'q, Q: ReadOnlyFetch<'q>, A> ReadOnlyFetch<'q> for PreparedChangeFilter where - Q: PreparedFetch, + Q: PreparedFetch<'q>, A: Deref, { - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.fetch.fetch_shared(slot) } } @@ -167,14 +167,15 @@ where } } -impl PreparedFetch for PreparedChangeFilter +impl<'q, Q, A> PreparedFetch<'q> for PreparedChangeFilter where - Q: PreparedFetch, + Q: PreparedFetch<'q>, A: Deref, { - type Item<'q> = Q::Item<'q> where Self: 'q; + type Item = Q::Item; + #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.fetch.fetch(slot) } @@ -217,8 +218,8 @@ impl RemovedFilter { } } -impl FetchItem for RemovedFilter { - type Item<'q> = (); +impl<'q, T: ComponentValue> FetchItem<'q> for RemovedFilter { + type Item = (); } impl<'a, T: ComponentValue> Fetch<'a> for RemovedFilter { diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index e8d928a7..4f8ab5b6 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -115,17 +115,15 @@ impl Cmp { } } -impl FetchItem for Cmp { - type Item<'q> = F::Item<'q>; +impl<'q, F: FetchItem<'q>, M> FetchItem<'q> for Cmp { + type Item = F::Item; } impl<'w, F, M> Fetch<'w> for Cmp where - F: Fetch<'w> + 'w, - F::Prepared: for<'x> ReadOnlyFetch, - for<'x> PreparedCmp<'w, F::Prepared, M>: PreparedFetch, - // M: for<'x> CmpMethod<::Item<'x>>, - M: 'static, + F: Fetch<'w>, + F::Prepared: for<'x> ReadOnlyFetch<'x>, + M: for<'x> CmpMethod<>::Item> + 'w, { const MUTABLE: bool = F::MUTABLE; @@ -161,25 +159,25 @@ pub struct PreparedCmp<'w, F, M> { method: &'w M, } -impl<'w, F, M> ReadOnlyFetch for PreparedCmp<'w, F, M> +impl<'p, 'w, F, M> ReadOnlyFetch<'p> for PreparedCmp<'w, F, M> where - F: for<'x> ReadOnlyFetch, - M: for<'x> CmpMethod<::Item<'x>> + 'w, + F: for<'x> ReadOnlyFetch<'x>, + M: for<'x> CmpMethod<>::Item> + 'w, { - unsafe fn fetch_shared<'q>(&'q self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { self.fetch.fetch_shared(slot) } } -impl<'w, F, M> PreparedFetch for PreparedCmp<'w, F, M> +impl<'q, 'w, F, M> PreparedFetch<'q> for PreparedCmp<'w, F, M> where - F: for<'x> ReadOnlyFetch, - M: for<'x> CmpMethod<::Item<'x>> + 'w, + F: for<'x> ReadOnlyFetch<'x>, + M: for<'x> CmpMethod<>::Item> + 'w, { - type Item<'q> = ::Item<'q> where Self: 'q; + type Item = >::Item; #[inline] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.fetch.fetch(slot) } diff --git a/src/filter/constant.rs b/src/filter/constant.rs index 65b10cdd..689edb4d 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -11,8 +11,8 @@ use core::fmt::{self, Formatter}; /// A filter that yields, well, nothing pub struct Nothing; -impl FetchItem for Nothing { - type Item<'q> = (); +impl<'q> FetchItem<'q> for Nothing { + type Item = (); } impl<'a> Fetch<'a> for Nothing { @@ -37,10 +37,10 @@ impl<'a> Fetch<'a> for Nothing { fn access(&self, _data: FetchAccessData, _dst: &mut Vec) {} } -impl PreparedFetch for Nothing { - type Item<'q> = (); +impl<'q> PreparedFetch<'q> for Nothing { + type Item = (); - unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> {} + unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.end, slots.end) @@ -53,8 +53,8 @@ impl PreparedFetch for Nothing { #[derive(Debug, Clone)] pub struct All; -impl FetchItem for All { - type Item<'q> = (); +impl<'q> FetchItem<'q> for All { + type Item = (); } impl<'w> Fetch<'w> for All { @@ -77,14 +77,14 @@ impl<'w> Fetch<'w> for All { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl PreparedFetch for All { - type Item<'q> = (); +impl<'q> PreparedFetch<'q> for All { + type Item = (); - unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> {} + unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} } -impl FetchItem for Slice { - type Item<'q> = (); +impl<'q> FetchItem<'q> for Slice { + type Item = (); } impl<'w> Fetch<'w> for Slice { @@ -108,11 +108,11 @@ impl<'w> Fetch<'w> for Slice { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl PreparedFetch for Slice { - type Item<'q> = (); +impl<'q> PreparedFetch<'q> for Slice { + type Item = (); #[inline] - unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> {} + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -121,8 +121,8 @@ impl PreparedFetch for Slice { } } -impl FetchItem for bool { - type Item<'q> = bool; +impl<'q> FetchItem<'q> for bool { + type Item = bool; } impl<'w> Fetch<'w> for bool { @@ -148,11 +148,11 @@ impl<'w> Fetch<'w> for bool { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl PreparedFetch for bool { - type Item<'q> = bool; +impl<'q> PreparedFetch<'q> for bool { + type Item = bool; #[inline] - unsafe fn fetch<'q>(&mut self, _: usize) -> Self::Item<'q> { + unsafe fn fetch(&mut self, _: usize) -> Self::Item { *self } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 9c4e5af4..9699ac36 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -80,11 +80,11 @@ impl Filtered { } } -impl<'w, Q, F> FetchItem for Filtered +impl<'w, Q, F> FetchItem<'w> for Filtered where - Q: FetchItem, + Q: FetchItem<'w>, { - type Item<'q> = Q::Item<'q>; + type Item = Q::Item; } impl<'w, Q, F> Fetch<'w> for Filtered @@ -133,15 +133,15 @@ where } } -impl PreparedFetch for Filtered +impl<'q, Q, F> PreparedFetch<'q> for Filtered where - Q: PreparedFetch, - F: PreparedFetch, + Q: PreparedFetch<'q>, + F: PreparedFetch<'q>, { - type Item<'q> = Q::Item<'q> where Self: 'q; + type Item = Q::Item; #[inline(always)] - unsafe fn fetch<'q>(&'q mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.fetch.fetch(slot) } @@ -190,9 +190,9 @@ impl FilterIter { } } -impl Iterator for FilterIter +impl<'q, Q> Iterator for FilterIter where - Q: PreparedFetch, + Q: PreparedFetch<'q>, { type Item = Slice; @@ -224,7 +224,7 @@ where } } -impl FusedIterator for FilterIter {} +impl<'q, F: PreparedFetch<'q>> FusedIterator for FilterIter {} #[derive(Debug, Clone)] /// Fetch which only yields if the entity has the specified component @@ -233,8 +233,8 @@ pub struct With { pub(crate) name: &'static str, } -impl FetchItem for With { - type Item<'q> = (); +impl<'q> FetchItem<'q> for With { + type Item = (); } impl<'a> Fetch<'a> for With { @@ -269,8 +269,8 @@ pub struct Without { pub(crate) name: &'static str, } -impl FetchItem for Without { - type Item<'q> = (); +impl<'q> FetchItem<'q> for Without { + type Item = (); } impl<'w> Fetch<'w> for Without { @@ -304,8 +304,8 @@ pub(crate) struct WithObject { pub(crate) object: Entity, } -impl FetchItem for WithObject { - type Item<'q> = (); +impl<'q> FetchItem<'q> for WithObject { + type Item = (); } impl<'w> Fetch<'w> for WithObject { @@ -347,8 +347,8 @@ impl core::fmt::Debug for ArchetypeFilter { } } -impl FetchItem for ArchetypeFilter { - type Item<'q> = (); +impl<'q, F> FetchItem<'q> for ArchetypeFilter { + type Item = (); } impl<'w, F: Fn(&Archetype) -> bool> Fetch<'w> for ArchetypeFilter { @@ -378,8 +378,8 @@ pub struct WithRelation { pub(crate) name: &'static str, } -impl FetchItem for WithRelation { - type Item<'q> = (); +impl<'q> FetchItem<'q> for WithRelation { + type Item = (); } impl<'w> Fetch<'w> for WithRelation { @@ -409,8 +409,8 @@ pub struct WithoutRelation { pub(crate) name: &'static str, } -impl FetchItem for WithoutRelation { - type Item<'q> = (); +impl<'q> FetchItem<'q> for WithoutRelation { + type Item = (); } impl<'a> Fetch<'a> for WithoutRelation { @@ -444,11 +444,11 @@ impl<'a, F> Clone for RefFetch<'a, F> { } } -impl<'a, F> FetchItem for RefFetch<'a, F> +impl<'a, 'q, F> FetchItem<'q> for RefFetch<'a, F> where - F: FetchItem, + F: FetchItem<'q>, { - type Item<'q> = F::Item<'q>; + type Item = F::Item; } impl<'a, 'w, F> Fetch<'w> for RefFetch<'a, F> @@ -485,11 +485,11 @@ where } } -impl<'a, F> FetchItem for &'a F +impl<'a, 'q, F> FetchItem<'q> for &'a F where - F: FetchItem, + F: FetchItem<'q>, { - type Item<'q> = F::Item<'q>; + type Item = F::Item; } impl<'a, 'w, F> Fetch<'w> for &'a F @@ -531,19 +531,19 @@ where #[derive(Copy, Debug, Clone)] pub struct BatchSize(pub(crate) Slot); -impl PreparedFetch for BatchSize { - type Item<'q> = (); +impl<'q> PreparedFetch<'q> for BatchSize { + type Item = (); #[inline] - unsafe fn fetch<'q>(&'q mut self, _: usize) -> Self::Item<'q> {} + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.start, slots.end.min(slots.start + self.0)) } } -impl FetchItem for BatchSize { - type Item<'q> = (); +impl<'q> FetchItem<'q> for BatchSize { + type Item = (); } impl<'w> Fetch<'w> for BatchSize { diff --git a/src/filter/set.rs b/src/filter/set.rs index 8ba5728d..bb26d950 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -19,12 +19,12 @@ use core::{ #[derive(Debug, Clone)] pub struct And(pub L, pub R); -impl FetchItem for And +impl<'q, L, R> FetchItem<'q> for And where - L: FetchItem, - R: FetchItem, + L: FetchItem<'q>, + R: FetchItem<'q>, { - type Item<'q> = (L::Item<'q>, R::Item<'q>); + type Item = (L::Item, R::Item); } impl<'w, L, R> Fetch<'w> for And @@ -64,15 +64,15 @@ where } } -impl PreparedFetch for And +impl<'q, L, R> PreparedFetch<'q> for And where - L: PreparedFetch, - R: PreparedFetch, + L: PreparedFetch<'q>, + R: PreparedFetch<'q>, { - type Item<'q> = (L::Item<'q>, R::Item<'q>) where Self: 'q; + type Item = (L::Item, R::Item); #[inline] - unsafe fn fetch<'q>(&mut self, slot: Slot) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { (self.0.fetch(slot), self.1.fetch(slot)) } @@ -97,7 +97,7 @@ pub struct Or(pub T); /// Negate a filter pub struct Not(pub T); -impl FetchItem for Not { +impl<'q, T> FetchItem<'q> for Not { type Item = (); } @@ -127,14 +127,14 @@ where } } -impl PreparedFetch for Not> +impl<'q, F> PreparedFetch<'q> for Not> where - F: PreparedFetch, + F: PreparedFetch<'q>, { type Item = (); #[inline] - unsafe fn fetch<'q>(&'q mut self, _: usize) -> Self::Item<'q> {} + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { if let Some(fetch) = &mut self.0 { @@ -185,17 +185,17 @@ impl ops::Not for Not { #[derive(Debug, Clone)] pub struct Union(pub T); -impl FetchItem for Union +impl<'q, T> FetchItem<'q> for Union where - T: FetchItem, + T: FetchItem<'q>, { - type Item<'q> = T::Item<'q>; + type Item = T::Item; } impl<'w, T> Fetch<'w> for Union where T: Fetch<'w>, - T::Prepared: UnionFilter, + T::Prepared: for<'q> UnionFilter<'q>, { const MUTABLE: bool = T::MUTABLE; @@ -218,22 +218,22 @@ where } } -impl UnionFilter for Union +impl<'q, T> UnionFilter<'q> for Union where - T: UnionFilter, + T: UnionFilter<'q>, { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { self.0.filter_union(slots) } } -impl PreparedFetch for Union +impl<'q, T> PreparedFetch<'q> for Union where - T: PreparedFetch + UnionFilter, + T: PreparedFetch<'q> + UnionFilter<'q>, { - type Item<'q> = T::Item<'q> where Self: 'q; + type Item = T::Item; - unsafe fn fetch<'q>(&mut self, slot: usize) -> Self::Item<'q> { + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { self.0.fetch(slot) } @@ -249,8 +249,8 @@ where macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { // Or - impl< $($ty, )*> FetchItem<> for Or<($($ty,)*)> { - type Item<'q> = (); + impl<'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { + type Item = (); } impl<'w, $($ty, )*> Fetch<'w> for Or<($($ty,)*)> @@ -284,8 +284,8 @@ macro_rules! tuple_impl { } - impl< $($ty, )*> PreparedFetch<> for Or<($(Option<$ty>,)*)> - where $($ty: PreparedFetch<>,)* + impl<'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)> + where $($ty: PreparedFetch<'q>,)* { type Item = (); @@ -302,7 +302,7 @@ macro_rules! tuple_impl { } #[inline] - unsafe fn fetch<'q>(&'q mut self, _: usize) -> Self::Item<'q> {} + unsafe fn fetch(&mut self, _: usize) -> Self::Item {} fn set_visited(&mut self, slots: Slice) { $( self.0.$idx.set_visited(slots);)* @@ -311,8 +311,8 @@ macro_rules! tuple_impl { } - impl< $($ty, )*> UnionFilter for Or<($(Option<$ty>,)*)> - where $($ty: PreparedFetch,)* + impl<'q, $($ty, )*> UnionFilter<'q> for Or<($(Option<$ty>,)*)> + where $($ty: PreparedFetch<'q>,)* { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { let inner = &mut self.0; diff --git a/src/query/borrow.rs b/src/query/borrow.rs index 3779fe0d..729dd6e0 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -17,8 +17,8 @@ impl<'w, Q, F> PreparedArchetype<'w, Q, F> { #[inline] pub fn manual_chunk<'q>(&'q mut self, slots: Slice) -> Option> where - Q: PreparedFetch, - F: PreparedFetch, + Q: PreparedFetch<'q>, + F: PreparedFetch<'q>, { let chunk = unsafe { self.fetch.filter_slots(slots) }; if chunk.is_empty() { @@ -85,10 +85,10 @@ struct BatchesWithId<'q, Q, F> { impl<'q, Q, F> Iterator for BatchesWithId<'q, Q, F> where - Q: PreparedFetch, - F: PreparedFetch, + Q: PreparedFetch<'q>, + F: PreparedFetch<'q>, { - type Item = (Entity, Q::Item<'q>); + type Item = (Entity, Q::Item); fn next(&mut self) -> Option { loop { diff --git a/src/query/dfs.rs b/src/query/dfs.rs index 0ad8bb08..b6e35bfa 100644 --- a/src/query/dfs.rs +++ b/src/query/dfs.rs @@ -212,7 +212,7 @@ where /// `visit(query, edge, value)` where `value` is the return value of the visit. pub fn traverse_from(&mut self, root: Entity, value: &V, mut visit: Visit) where - Visit: for<'q> FnMut(::Item<'q>, Option<&T>, &V) -> V, + Visit: for<'q> FnMut(>::Item, Option<&T>, &V) -> V, { let Ok(loc) = self.query_state.world.location(root) else { return; @@ -242,7 +242,7 @@ where /// `visit(query, edge, value)` where `value` is the return value of the parent. pub fn traverse(&mut self, value: &V, mut visit: Visit) where - Visit: for<'q> FnMut(::Item<'q>, Option<&T>, &V) -> V, + Visit: for<'q> FnMut(>::Item, Option<&T>, &V) -> V, { let dfs = &self.dfs; let prepared = (&mut self.prepared[..]) as *mut [_] as *mut PreparedArchetype<_, _>; @@ -274,7 +274,7 @@ where value: &V, visit: &mut Visit, ) where - Visit: for<'q> FnMut(::Item<'q>, Option<&T>, &V) -> V, + Visit: for<'q> FnMut(>::Item, Option<&T>, &V) -> V, Q: 'w, F: 'w, { @@ -353,7 +353,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = ::Item<'q>; + type Item = >::Item; fn next(&mut self) -> Option { loop { diff --git a/src/query/entity.rs b/src/query/entity.rs index 8081d20c..4e9df741 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -104,7 +104,7 @@ where /// Returns the results of the fetch. /// /// Fails if the entity does not exist, or the fetch isn't matched. - pub fn get<'q>(&'q mut self) -> Result<::Item<'q>> + pub fn get<'q>(&'q mut self) -> Result<>::Item> where 'w: 'q, { diff --git a/src/query/iter.rs b/src/query/iter.rs index 01edb906..40db700e 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -57,12 +57,12 @@ impl<'q, Q, F> Batch<'q, Q, F> { impl<'q, Q, F> Iterator for Batch<'q, Q, F> where - Q: PreparedFetch, - F: PreparedFetch, + Q: PreparedFetch<'q>, + F: PreparedFetch<'q>, { - type Item = Q::Item<'q>; + type Item = Q::Item; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { if self.pos == self.end { None } else { @@ -76,10 +76,10 @@ where impl<'q, Q, F> Batch<'q, Q, F> where - Q: PreparedFetch, - F: PreparedFetch, + Q: PreparedFetch<'q>, + F: PreparedFetch<'q>, { - pub(crate) fn next_with_id(&mut self) -> Option<(Entity, Q::Item<'q>)> { + pub(crate) fn next_with_id(&mut self) -> Option<(Entity, Q::Item)> { if self.pos == self.end { None } else { @@ -91,7 +91,7 @@ where } } - pub(crate) fn next_full(&mut self) -> Option<(Slot, Entity, Q::Item<'q>)> { + pub(crate) fn next_full(&mut self) -> Option<(Slot, Entity, Q::Item)> { if self.pos == self.end { None } else { @@ -116,8 +116,8 @@ pub struct ArchetypeChunks<'q, Q, F> { impl<'q, Q, F> Iterator for ArchetypeChunks<'q, Q, F> where - Q: PreparedFetch, - F: PreparedFetch, + Q: PreparedFetch<'q>, + F: PreparedFetch<'q>, { type Item = Batch<'q, Q, F>; diff --git a/src/query/mod.rs b/src/query/mod.rs index d3dc0fab..6522f84f 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -182,7 +182,7 @@ where pub fn collect_vec<'w, T>(&'w mut self, world: &'w World) -> Vec where T: 'static, - Q: for<'q> FetchItem = T>, + Q: for<'q> FetchItem<'q, Item = T>, { let mut borrow = self.borrow(world); borrow.iter().collect() diff --git a/src/query/planar.rs b/src/query/planar.rs index db7fe842..a49db0af 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -130,7 +130,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = ::Item<'q>; + type Item = >::Item; type IntoIter = QueryIter<'w, 'q, Q, F>; @@ -156,7 +156,7 @@ where } /// Returns the first item - pub fn first(&mut self) -> Option<::Item<'_>> { + pub fn first(&mut self) -> Option<>::Item> { self.iter().next() } @@ -193,7 +193,7 @@ where /// /// This is more efficient than `.iter().for_each(|v| {})` as the archetypes can be temporarily /// borrowed. - pub fn for_each(&mut self, mut func: impl FnMut(::Item<'_>) + Send + Sync) { + pub fn for_each(&mut self, mut func: impl FnMut(>::Item) + Send + Sync) { self.clear_borrows(); for &arch_id in self.archetypes { let arch = self.state.world.archetypes.get(arch_id); @@ -218,7 +218,7 @@ where /// .for_each(|v| v.for_each(&func)) /// ``` #[cfg(feature = "parallel")] - pub fn par_for_each(&mut self, func: impl Fn(::Item<'_>) + Send + Sync) + pub fn par_for_each(&mut self, func: impl Fn(>::Item) + Send + Sync) where Q: Sync, Q::Prepared: Send, @@ -270,7 +270,7 @@ where } /// Get the fetch items for an entity. - pub fn get(&mut self, id: Entity) -> Result<::Item<'_>> { + pub fn get(&mut self, id: Entity) -> Result<::Item> { let EntityLocation { arch_id, slot } = self.state.world.location(id)?; let idx = @@ -313,7 +313,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = ::Item<'q>; + type Item = >::Item; #[inline(always)] fn next(&mut self) -> Option { diff --git a/src/query/topo.rs b/src/query/topo.rs index 63378ca5..0d3c0b6b 100644 --- a/src/query/topo.rs +++ b/src/query/topo.rs @@ -186,7 +186,7 @@ where Q: Fetch<'w>, F: Fetch<'w>, { - type Item = ::Item<'q>; + type Item = >::Item; type IntoIter = TopoIter<'w, 'q, Q, F>; @@ -238,7 +238,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = ::Item<'q>; + type Item = >::Item; #[inline] fn next(&mut self) -> Option { diff --git a/src/query/walk.rs b/src/query/walk.rs index 9630871a..5034b685 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -234,7 +234,7 @@ where pub fn get<'q>( &self, borrow: &'q mut GraphBorrow<'w, Q, F>, - ) -> Option<::Item<'q>> + ) -> Option<>::Item> where Q: Fetch<'w>, F: Fetch<'w>, diff --git a/src/system/mod.rs b/src/system/mod.rs index 9d6764d3..edb4bc3c 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -57,7 +57,7 @@ impl<'a, Func, Q, F> SystemFn<'a, (QueryData<'a, Q, F>,), ()> for ForEach where for<'x> Q: Fetch<'x>, for<'x> F: Fetch<'x>, - for<'x> Func: FnMut(::Item<'x>), + for<'x> Func: FnMut(>::Item), { fn execute(&mut self, mut data: (QueryData,)) { for item in &mut data.0.borrow() { @@ -79,7 +79,7 @@ where for<'x> F: Fetch<'x>, for<'x> >::Prepared: Send, for<'x> >::Prepared: Send, - for<'x> Func: Fn(::Item<'x>) + Send + Sync, + for<'x> Func: Fn(>::Item) + Send + Sync, { fn execute(&mut self, mut data: (QueryData,)) { let mut borrow = data.0.borrow(); @@ -98,7 +98,7 @@ where /// Execute a function for each item in the query pub fn for_each(self, func: Func) -> System, (Query,), (), T> where - for<'x> Func: FnMut(::Item<'x>), + for<'x> Func: FnMut(>::Item), { System::new( self.name.unwrap_or_else(|| type_name::().to_string()), @@ -120,7 +120,7 @@ where /// Execute a function for each item in the query in parallel batches pub fn par_for_each(self, func: Func) -> System, (Query,), (), T> where - for<'x> Func: Fn(::Item<'x>) + Send + Sync, + for<'x> Func: Fn(>::Item) + Send + Sync, { System::new( self.name.unwrap_or_else(|| type_name::().to_string()), From 582f9f601f07c01fa98fdf60eb21400b737e3223 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 2 Jul 2023 23:59:12 +0200 Subject: [PATCH 15/52] feat: fetch map --- asteroids/src/main.rs | 2 +- flax-derive/src/lib.rs | 6 ++-- src/fetch/ext.rs | 13 ++++++-- src/fetch/map.rs | 76 ++++++++++++++++++++++++++++++++++++++++++ src/fetch/mod.rs | 2 ++ src/fetch/transform.rs | 63 +++++++++++++++------------------- src/filter/set.rs | 5 +-- 7 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 src/fetch/map.rs diff --git a/asteroids/src/main.rs b/asteroids/src/main.rs index 594661ca..012ee73a 100644 --- a/asteroids/src/main.rs +++ b/asteroids/src/main.rs @@ -481,7 +481,7 @@ const PLUME_COOLDOWN: f32 = 0.02; /// and refactoring. #[derive(Fetch)] // Ensures the fetch item is debuggable -#[fetch(Debug)] +#[fetch(item = [Debug])] struct PlayerQuery { id: EntityIds, player: Component<()>, diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index fe71b17b..1665a082 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -179,8 +179,6 @@ fn prepend_generics(prepend: &[GenericParam], generics: &Generics) -> Generics { fn derive_union(params: &Params) -> TokenStream { let Params { crate_name, - fetch_name, - field_types, field_names, prepared_name, q_lf, @@ -248,9 +246,9 @@ fn derive_modified(params: &Params) -> TokenStream { impl #trait_name for #fetch_name { type Output = #crate_name::filter::Union<#transformed_name<#(<#field_types as #trait_name>::Output,)*>>; - fn transform_fetch(self) -> Self::Output { + fn transform_fetch(self, method: #crate_name::fetch::Modified) -> Self::Output { #crate_name::filter::Union(#transformed_name { - #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names),)* + #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names, method),)* }) } } diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index 27a604e7..c2a86955 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -9,7 +9,7 @@ use super::{ copied::Copied, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, - Modified, Satisfied, Source, TransformFetch, + Map, Modified, Satisfied, Source, TransformFetch, }; /// Extension trait for [crate::Fetch] @@ -147,7 +147,16 @@ pub trait FetchExt: Sized { where Self: TransformFetch, { - self.transform_fetch() + self.transform_fetch(Modified) + } + + /// Map each item of the query to another type using the provided function. + fn map(self, func: F) -> Map + where + Self: for<'x> FetchItem<'x>, + for<'x> F: Fn(>::Item) -> T, + { + Map { query: self, func } } } diff --git a/src/fetch/map.rs b/src/fetch/map.rs new file mode 100644 index 00000000..ea5d0428 --- /dev/null +++ b/src/fetch/map.rs @@ -0,0 +1,76 @@ +use crate::{Fetch, FetchItem}; + +use super::{FmtQuery, PreparedFetch}; + +/// Maps the result of a query to another type on the query level. +/// +/// **Note**: Due to limitations in the Rust trait system and lifetimes, the provided function must +/// return `'static` items. This is because same function can't be polymorphic over temporary lifetimes issued when the query is prepared and borrowed. The `.map` iterator circumvents this by binding to an already existing lifetime, but will have to be repeated when iterating, and is more difficult to bake into a larger fetch. +pub struct Map { + pub(crate) query: Q, + pub(crate) func: F, +} + +impl<'q, Q, F, T> FetchItem<'q> for Map +where + Q: FetchItem<'q>, + F: Fn(Q::Item) -> T, + F: 'static, +{ + type Item = T; +} + +impl<'w, Q, F, T> Fetch<'w> for Map +where + Q: Fetch<'w>, + // for<> Map: PreparedFetch<>, + F: for<'q> Fn(>::Item) -> T, + F: 'static, + T: 'static, +{ + const MUTABLE: bool = Q::MUTABLE; + + type Prepared = Map; + + fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { + Some(Map { + query: self.query.prepare(data)?, + func: &self.func, + }) + } + + fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { + self.query.filter_arch(arch) + } + + fn access(&self, data: super::FetchAccessData, dst: &mut Vec) { + self.query.access(data, dst) + } + + fn describe(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Map").field(&FmtQuery(&self.query)).finish() + } +} + +impl<'w, 'q, Q, F, T> PreparedFetch<'q> for Map +where + Q: PreparedFetch<'q>, + F: Fn(Q::Item) -> T, + F: 'static, + T: 'static, +{ + type Item = T; + + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { + (self.func)(self.query.fetch(slot)) + } + + unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { + self.query.filter_slots(slots) + } + + #[inline] + fn set_visited(&mut self, slots: crate::archetype::Slice) { + self.query.set_visited(slots) + } +} diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 641b5939..4e04f854 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -5,6 +5,7 @@ mod component_mut; mod copied; mod entity_ref; mod ext; +mod map; mod maybe_mut; mod opt; mod read_only; @@ -29,6 +30,7 @@ pub use component::*; pub use component_mut::*; pub use entity_ref::*; pub use ext::FetchExt; +pub use map::Map; pub use maybe_mut::{MaybeMut, MutGuard}; pub use opt::*; pub use read_only::*; diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index 406fd0b6..99011683 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -10,25 +10,26 @@ pub trait TransformFetch: for<'w> Fetch<'w> { /// May of may not have the same `Item` type Output; /// Transform the fetch using the provided method - fn transform_fetch(self) -> Self::Output; + fn transform_fetch(self, method: Method) -> Self::Output; } impl TransformFetch for Component { type Output = ChangeFilter; - fn transform_fetch(self) -> Self::Output { + fn transform_fetch(self, _: Modified) -> Self::Output { self.modified() } } /// Marker for a fetch which has been transformed to filter modified items. +#[derive(Debug, Clone, Copy)] pub struct Modified; macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { type Output = Union<($($ty::Output,)*)>; - fn transform_fetch(self) -> Self::Output { - Union(($(self.$idx.transform_fetch(),)*)) + fn transform_fetch(self, method: Modified) -> Self::Output { + Union(($(self.$idx.transform_fetch(method),)*)) } } }; @@ -49,8 +50,7 @@ mod tests { use itertools::Itertools; use crate::{ - component, entity_ids, filter::ChangeFilter, filter::Union, CommandBuffer, Component, - Entity, Fetch, FetchExt, Query, QueryBorrow, World, + component, entity_ids, CommandBuffer, Component, Entity, Fetch, FetchExt, Query, World, }; #[test] @@ -167,19 +167,14 @@ mod tests { .tag(other()) .spawn(&mut world); - let query = MyFetch { a: a(), b: b() }.modified(); - let mut query = Query::new((entity_ids(), query)); + let query = MyFetch { a: a(), b: b() } + .modified() + .map(|v| (*v.a, v.b.clone())); - let mut collect = move |world| { - query - .borrow(world) - .iter() - .map(|(id, v)| (id, (*v.a, v.b.clone()))) - .collect_vec() - }; + let mut query = Query::new((entity_ids(), query)); assert_eq!( - collect(&world), + query.collect_vec(&world), [ (id1, (0, "Hello".to_string())), (id2, (1, "World".to_string())), @@ -187,34 +182,28 @@ mod tests { ] ); - // assert_eq!(query.borrow(&world).iter().collect_vec(), []); + assert_eq!(query.collect_vec(&world), []); - // // Get mut *without* a mut deref is not a change - // assert_eq!(*world.get_mut(id2, a()).unwrap(), 1); + // Get mut *without* a mut deref is not a change + assert_eq!(*world.get_mut(id2, a()).unwrap(), 1); - // assert_eq!(query.borrow(&world).iter().collect_vec(), []); + assert_eq!(query.collect_vec(&world), []); - // *world.get_mut(id2, a()).unwrap() = 5; + *world.get_mut(id2, a()).unwrap() = 5; - // assert_eq!( - // query.borrow(&world).iter().collect_vec(), - // [(id2, (&5, &"World".to_string()))] - // ); + assert_eq!(query.collect_vec(&world), [(id2, (5, "World".to_string()))]); - // // Adding the required component to id3 will cause it to be picked up by the query - // let mut cmd = CommandBuffer::new(); - // cmd.set(id3, a(), -1).apply(&mut world).unwrap(); + // Adding the required component to id3 will cause it to be picked up by the query + let mut cmd = CommandBuffer::new(); + cmd.set(id3, a(), -1).apply(&mut world).unwrap(); - // assert_eq!( - // query.borrow(&world).iter().collect_vec(), - // [(id3, (&-1, &"There".to_string()))] - // ); + assert_eq!( + query.collect_vec(&world), + [(id3, (-1, "There".to_string()))] + ); - // cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap(); + cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap(); - // assert_eq!( - // query.borrow(&world).iter().collect_vec(), - // [(id3, (&-1, &":P".to_string()))] - // ); + assert_eq!(query.collect_vec(&world), [(id3, (-1, ":P".to_string()))]); } } diff --git a/src/filter/set.rs b/src/filter/set.rs index bb26d950..6c3fe123 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -343,10 +343,7 @@ tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H } mod tests { use itertools::Itertools; - use crate::{ - filter::{All, FilterIter, Nothing}, - World, - }; + use crate::filter::{FilterIter, Nothing}; use super::*; From 64f79ab63710d1127d5d252e313c68c5f9596c90 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Mon, 3 Jul 2023 00:07:30 +0200 Subject: [PATCH 16/52] chore: use fully qualified syntax for derive --- asteroids/src/main.rs | 2 +- flax-derive/src/lib.rs | 20 ++++------- src/fetch/transform.rs | 2 +- tests/derive.rs | 2 +- tests/derive_generic.rs | 74 ++++++++++++++++++++--------------------- 5 files changed, 46 insertions(+), 54 deletions(-) diff --git a/asteroids/src/main.rs b/asteroids/src/main.rs index 012ee73a..0c294ef8 100644 --- a/asteroids/src/main.rs +++ b/asteroids/src/main.rs @@ -481,7 +481,7 @@ const PLUME_COOLDOWN: f32 = 0.02; /// and refactoring. #[derive(Fetch)] // Ensures the fetch item is debuggable -#[fetch(item = [Debug])] +#[fetch(item_derives = [Debug])] struct PlayerQuery { id: EntityIds, player: Component<()>, diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 1665a082..6f717417 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -13,7 +13,7 @@ use syn::{ /// ```rust,ignore /// use glam::*; /// #[derive(Fetch)] -/// #[fetch(Debug)] +/// #[fetch(item_derives = [Debug], transforms = [Modified])] /// struct CustomFetch { /// position: Component, /// rotation: Mutable, @@ -144,7 +144,7 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { #[inline] fn filter_arch(&self, arch: &#crate_name::archetype::Archetype) -> bool { - #(self.#field_names.filter_arch(arch))&&* + #(#crate_name::Fetch::filter_arch(&self.#field_names, arch))&&* } fn describe(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { @@ -158,11 +158,11 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { } fn access(&self, data: #crate_name::fetch::FetchAccessData, dst: &mut Vec<#crate_name::system::Access>) { - #(self.#field_names.access(data, dst));* + #(#crate_name::Fetch::access(&self.#field_names, data, dst));* } fn searcher(&self, searcher: &mut #crate_name::query::ArchetypeSearcher) { - #(self.#field_names.searcher(searcher);)* + #(#crate_name::Fetch::searcher(&self.#field_names, searcher);)* } } } @@ -306,7 +306,7 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { #[inline] unsafe fn fetch(&'q mut self, slot: #crate_name::archetype::Slot) -> Self::Item { Self::Item { - #(#field_names: self.#field_names.fetch(slot),)* + #(#field_names: #crate_name::fetch::PreparedFetch::fetch(&mut self.#field_names, slot),)* } } @@ -344,21 +344,13 @@ impl Attrs { list.parse_nested_meta(|meta| { // item = [Debug, PartialEq] - if meta.path.is_ident("item") { + if meta.path.is_ident("item_derives") { let value = meta.value()?; let content; bracketed!(content in value); let content = >::parse_terminated(&content)?; - // let derives = syn::parse2::(value.to_token_stream()) - // .map_err(|_| { - // Error::new( - // value.span(), - // "Expected a MetaList for item derives", - // ) - // })?; - res.item_derives = Some(content); Ok(()) } else if meta.path.is_ident("transforms") { diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index 99011683..d293fa9b 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -137,7 +137,7 @@ mod tests { } #[derive(Fetch)] - #[fetch(item = [Debug], transforms = [Modified])] + #[fetch(item_derives = [Debug], transforms = [Modified])] struct MyFetch { a: Component, b: Component, diff --git a/tests/derive.rs b/tests/derive.rs index 9e4b0fa4..8b3a3248 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -12,7 +12,7 @@ fn derive_fetch() { use flax::{Fetch, *}; #[derive(Fetch)] - #[fetch(item = [Debug, PartialEq])] + #[fetch(item_derives = [Debug, PartialEq])] struct TransformQuery { pos: Component, rot: Opt>, diff --git a/tests/derive_generic.rs b/tests/derive_generic.rs index bbfd498f..5758f1b4 100644 --- a/tests/derive_generic.rs +++ b/tests/derive_generic.rs @@ -12,47 +12,47 @@ fn derive_fetch_generic() { use flax::{Fetch, *}; #[derive(Fetch)] - // #[fetch(Debug, PartialEq)] + #[fetch(item_derives = [Debug, PartialEq])] struct TransformQuery { pos: Component, rot: Opt>, scale: Opt>, } - // let mut world = World::new(); - - // let id1 = Entity::builder() - // .set(position(), vec3(3.4, 2.4, 2.1)) - // .spawn(&mut world); - - // let id2 = Entity::builder() - // .set(position(), vec3(7.4, 9.2, 3.4)) - // .set(rotation(), Quat::from_axis_angle(Vec3::Z, 1.0)) - // .spawn(&mut world); - - // let mut query = Query::new(TransformQuery { - // pos: position(), - // rot: rotation().opt(), - // scale: scale().opt(), - // }); - - // let mut query = query.borrow(&world); - - // assert_eq!( - // query.get(id1), - // Ok(TransformQueryItem { - // pos: &vec3(3.4, 2.4, 2.1), - // rot: None, - // scale: None - // }) - // ); - - // assert_eq!( - // query.get(id2), - // Ok(TransformQueryItem { - // pos: &vec3(7.4, 9.2, 3.4), - // rot: Some(&Quat::from_axis_angle(Vec3::Z, 1.0)), - // scale: None - // }) - // ); + let mut world = World::new(); + + let id1 = Entity::builder() + .set(position(), vec3(3.4, 2.4, 2.1)) + .spawn(&mut world); + + let id2 = Entity::builder() + .set(position(), vec3(7.4, 9.2, 3.4)) + .set(rotation(), Quat::from_axis_angle(Vec3::Z, 1.0)) + .spawn(&mut world); + + let mut query = Query::new(TransformQuery { + pos: position(), + rot: rotation().opt(), + scale: scale().opt(), + }); + + let mut query = query.borrow(&world); + + assert_eq!( + query.get(id1), + Ok(TransformQueryItem { + pos: &vec3(3.4, 2.4, 2.1), + rot: None, + scale: None + }) + ); + + assert_eq!( + query.get(id2), + Ok(TransformQueryItem { + pos: &vec3(7.4, 9.2, 3.4), + rot: Some(&Quat::from_axis_angle(Vec3::Z, 1.0)), + scale: None + }) + ); } From 8e1031eced0750b1c1af750e3d59e0367055195d Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Mon, 3 Jul 2023 00:10:33 +0200 Subject: [PATCH 17/52] fix: no std tests --- src/fetch/map.rs | 2 ++ src/fetch/transform.rs | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fetch/map.rs b/src/fetch/map.rs index ea5d0428..d84ab9fc 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -1,3 +1,5 @@ +use alloc::vec::Vec; + use crate::{Fetch, FetchItem}; use super::{FmtQuery, PreparedFetch}; diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index d293fa9b..e31594e5 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -49,9 +49,7 @@ mod tests { use alloc::string::{String, ToString}; use itertools::Itertools; - use crate::{ - component, entity_ids, CommandBuffer, Component, Entity, Fetch, FetchExt, Query, World, - }; + use crate::{component, entity_ids, CommandBuffer, Entity, FetchExt, Query, World}; #[test] fn query_modified() { @@ -130,6 +128,8 @@ mod tests { #[test] #[cfg(feature = "derive")] fn query_modified_struct() { + use crate::{Component, Fetch}; + component! { a: i32, b: String, From a7268b1bc01e3d85beeeafa743fa0d33ac8f8096 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Wed, 5 Jul 2023 00:17:42 +0200 Subject: [PATCH 18/52] chore: implement transform for Opt, Cloned, Copied --- src/fetch/cloned.rs | 31 +++++++++++++++++++------- src/fetch/copied.rs | 31 +++++++++++++++++++------- src/fetch/opt.rs | 50 +++++++++++++++++++++++++++++++++--------- src/fetch/transform.rs | 15 ++++++++----- 4 files changed, 95 insertions(+), 32 deletions(-) diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index 0ea3d0a4..a51aefe3 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -11,7 +11,7 @@ use crate::{ Fetch, FetchItem, }; -use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; +use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch, TransformFetch}; #[derive(Debug, Clone)] /// Component which cloned the value. @@ -20,19 +20,21 @@ use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; /// See [crate::Component::as_mut] pub struct Cloned(pub(crate) F); -impl<'q, F, V> FetchItem<'q> for Cloned +impl<'q, F> FetchItem<'q> for Cloned where - F: FetchItem<'q, Item = &'q V>, - V: 'static, + F: FetchItem<'q>, + >::Item: Deref, + <>::Item as Deref>::Target: 'static + Clone, { - type Item = V; + type Item = <>::Item as Deref>::Target; } -impl<'w, F, V> Fetch<'w> for Cloned +impl<'w, F> Fetch<'w> for Cloned where F: Fetch<'w>, - F: for<'q> FetchItem<'q, Item = &'q V>, - V: 'static + Clone, + F: for<'q> FetchItem<'q>, + for<'q> >::Item: Deref, + for<'q> <>::Item as Deref>::Target: 'static + Clone, { const MUTABLE: bool = F::MUTABLE; @@ -96,3 +98,16 @@ where self.0.fetch_shared(slot).clone() } } + +impl TransformFetch for Cloned +where + F: TransformFetch, + Cloned: for<'x> Fetch<'x>, + Cloned: for<'x> Fetch<'x>, +{ + type Output = Cloned; + + fn transform_fetch(self, method: K) -> Self::Output { + Cloned(self.0.transform_fetch(method)) + } +} diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index 1b4df019..ad160e60 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -11,7 +11,7 @@ use crate::{ Fetch, FetchItem, }; -use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; +use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch, TransformFetch}; #[derive(Debug, Clone)] /// Component which copied the value. @@ -20,19 +20,21 @@ use super::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; /// See [crate::Component::as_mut] pub struct Copied(pub(crate) F); -impl<'q, F, V> FetchItem<'q> for Copied +impl<'q, F> FetchItem<'q> for Copied where - F: FetchItem<'q, Item = &'q V>, - V: 'static, + F: FetchItem<'q>, + >::Item: Deref, + <>::Item as Deref>::Target: 'static + Copy, { - type Item = V; + type Item = <>::Item as Deref>::Target; } -impl<'w, F, V> Fetch<'w> for Copied +impl<'w, F> Fetch<'w> for Copied where F: Fetch<'w>, - F: for<'q> FetchItem<'q, Item = &'q V>, - V: 'static + Copy, + F: for<'q> FetchItem<'q>, + for<'q> >::Item: Deref, + for<'q> <>::Item as Deref>::Target: 'static + Copy, { const MUTABLE: bool = F::MUTABLE; @@ -97,3 +99,16 @@ where *self.0.fetch_shared(slot) } } + +impl TransformFetch for Copied +where + F: TransformFetch, + Copied: for<'x> Fetch<'x>, + Copied: for<'x> Fetch<'x>, +{ + type Output = Copied; + + fn transform_fetch(self, method: K) -> Self::Output { + Copied(self.0.transform_fetch(method)) + } +} diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 862906f5..389ab070 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -7,10 +7,10 @@ use crate::{ fetch::FetchPrepareData, fetch::PreparedFetch, system::Access, - ComponentValue, Fetch, + Fetch, }; -use super::{FetchAccessData, FetchItem, ReadOnlyFetch}; +use super::{FetchAccessData, FetchItem, ReadOnlyFetch, TransformFetch}; /// Transform a fetch into a optional fetch #[derive(Debug, Clone)] @@ -90,20 +90,22 @@ where #[derive(Debug, Clone)] pub struct OptOr { fetch: F, - or: V, + value: V, } impl OptOr { pub(crate) fn new(inner: F, or: V) -> Self { - Self { fetch: inner, or } + Self { + fetch: inner, + value: or, + } } } impl<'w, F, V> Fetch<'w> for OptOr where F: Fetch<'w> + for<'q> FetchItem<'q, Item = &'q V>, - for<'q> F::Prepared: PreparedFetch<'q, Item = &'q V>, - V: ComponentValue, + V: 'static, { const MUTABLE: bool = F::MUTABLE; @@ -112,7 +114,7 @@ where fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option { Some(OptOr { fetch: self.fetch.prepare(data), - or: &self.or, + value: &self.value, }) } @@ -131,21 +133,21 @@ where } } -impl<'q, F: FetchItem<'q, Item = &'q V>, V: ComponentValue> FetchItem<'q> for OptOr { +impl<'q, F: FetchItem<'q, Item = &'q V>, V: 'static> FetchItem<'q> for OptOr { type Item = &'q V; } impl<'q, 'w, F, V> PreparedFetch<'q> for OptOr, &'w V> where F: PreparedFetch<'q, Item = &'q V>, - V: 'static, + V: 'q, { type Item = &'q V; unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { match self.fetch { Some(ref mut v) => v.fetch(slot), - None => self.or, + None => self.value, } } @@ -164,3 +166,31 @@ where } } } + +impl TransformFetch for Opt +where + F: TransformFetch, +{ + type Output = Opt; + + fn transform_fetch(self, method: K) -> Self::Output { + Opt(self.0.transform_fetch(method)) + } +} + +impl TransformFetch for OptOr +where + F: TransformFetch, + F: for<'q> FetchItem<'q, Item = &'q V>, + F::Output: for<'q> FetchItem<'q, Item = &'q V>, + V: 'static, +{ + type Output = OptOr; + + fn transform_fetch(self, method: K) -> Self::Output { + OptOr { + fetch: self.fetch.transform_fetch(method), + value: self.value, + } + } +} diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index e31594e5..f63cfc2e 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -8,7 +8,7 @@ pub trait TransformFetch: for<'w> Fetch<'w> { /// The transformed type. /// /// May of may not have the same `Item` - type Output; + type Output: for<'w> Fetch<'w>; /// Transform the fetch using the provided method fn transform_fetch(self, method: Method) -> Self::Output; } @@ -128,7 +128,7 @@ mod tests { #[test] #[cfg(feature = "derive")] fn query_modified_struct() { - use crate::{Component, Fetch}; + use crate::{fetch::Cloned, Component, Fetch}; component! { a: i32, @@ -140,7 +140,7 @@ mod tests { #[fetch(item_derives = [Debug], transforms = [Modified])] struct MyFetch { a: Component, - b: Component, + b: Cloned>, } let mut world = World::new(); @@ -167,9 +167,12 @@ mod tests { .tag(other()) .spawn(&mut world); - let query = MyFetch { a: a(), b: b() } - .modified() - .map(|v| (*v.a, v.b.clone())); + let query = MyFetch { + a: a(), + b: b().cloned(), + } + .modified() + .map(|v| (*v.a, v.b)); let mut query = Query::new((entity_ids(), query)); From 6b549e55b5e8b0135bed5eaeecc9030177bfa57b Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 8 Jul 2023 20:22:00 +0200 Subject: [PATCH 19/52] chore: remove adjacent atomic ref cell borrowing --- .vscode/settings.json | 3 + src/archetype/guard.rs | 180 ++++++++++++----- src/archetype/mod.rs | 402 ++++++++++++++++++------------------- src/archetype/storage.rs | 15 +- src/component.rs | 6 +- src/fetch/component.rs | 4 +- src/fetch/component_mut.rs | 62 +++--- src/fetch/maybe_mut.rs | 22 +- src/fetch/relations.rs | 16 +- src/filter/change.rs | 173 ++++++++++------ src/filter/mod.rs | 18 +- src/format.rs | 6 +- src/lib.rs | 1 + src/relation.rs | 14 +- src/serialize/ser.rs | 13 +- 15 files changed, 514 insertions(+), 421 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..39a5ca1e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": "all" +} diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 75d29d98..e0c9f8a1 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -1,70 +1,114 @@ use core::{ fmt::Debug, ops::{Deref, DerefMut}, + ptr::NonNull, }; -use atomic_refcell::AtomicRefMut; +use atomic_refcell::{AtomicRef, AtomicRefMut}; use crate::{ events::{EventData, EventKind}, - Entity, + ComponentValue, Entity, }; -use super::{Cell, Change, Changes, Slice, Slot}; +use super::{Archetype, CellData, Change, Changes, Slice, Slot}; -pub(crate) struct CellMutGuard<'a, T: ?Sized> { - pub(crate) storage: AtomicRefMut<'a, T>, - pub(crate) changes: AtomicRefMut<'a, Changes>, - pub(crate) cell: &'a Cell, - pub(crate) ids: &'a [Entity], - pub(crate) tick: u32, +/// Type safe abstraction over a borrowed cell data +pub(crate) struct CellMutGuard<'a, T> { + value: AtomicRefMut<'a, [T]>, + // From the refcell + orig: NonNull, } -impl<'a, T: Debug + ?Sized> Debug for CellMutGuard<'a, T> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - self.storage.fmt(f) +unsafe impl<'a, T> Send for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Send {} +unsafe impl<'a, T> Sync for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Sync {} + +impl<'a, T: ComponentValue> CellMutGuard<'a, T> { + pub(super) fn new(mut value: AtomicRefMut<'a, CellData>) -> Self { + // Store the original pointer. This will be used when dropped + let orig = NonNull::from(&mut *value); + + let value = AtomicRefMut::map(value, |v| v.storage.downcast_mut::()); + + Self { value, orig } } -} -impl<'a, T: ?Sized> CellMutGuard<'a, T> { - pub(crate) fn set_modified(&mut self, slots: Slice) { - let event = EventData { - ids: &self.ids[slots.as_range()], - key: self.cell.info.key, + pub(crate) fn set_modified(&mut self, entities: &[Entity], slots: Slice, tick: u32) { + // SAFETY: `value` is not accessed in this function + let orig = unsafe { self.orig.as_mut() }; + + orig.on_event(EventData { + ids: &entities[slots.as_range()], + key: orig.key, kind: EventKind::Modified, - }; + }); - for handler in self.cell.subscribers.iter() { - handler.on_event(&event) - } + orig.changes + .set_modified_if_tracking(Change::new(slots, tick)); + } + + pub(crate) fn changes_mut(&mut self) -> &mut Changes { + // SAFETY: `value` is not accessed in this function + let orig = unsafe { self.orig.as_mut() }; - self.changes - .set_modified_if_tracking(Change::new(slots, self.tick)); + &mut orig.changes } +} - #[inline] - pub(crate) fn filter_map(self, func: F) -> Option> - where - F: FnOnce(&mut T) -> Option<&mut U>, - { - let storage = AtomicRefMut::filter_map(self.storage, func)?; - Some(CellMutGuard { - storage, - changes: self.changes, - cell: self.cell, - ids: self.ids, - tick: self.tick, - }) +impl<'w, T> Deref for CellMutGuard<'w, T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl<'w, T> DerefMut for CellMutGuard<'w, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.value + } +} + +/// Type safe abstraction over a borrowed cell data +pub(crate) struct CellGuard<'a, T> { + value: AtomicRef<'a, [T]>, + orig: NonNull, +} + +unsafe impl<'a, T> Send for CellGuard<'a, T> where AtomicRef<'a, T>: Send {} +unsafe impl<'a, T> Sync for CellGuard<'a, T> where AtomicRef<'a, T>: Sync {} + +impl<'a, T: ComponentValue> CellGuard<'a, T> { + pub(super) fn new(value: AtomicRef<'a, CellData>) -> Self { + // Store the original pointer. This will be used when dropped + let orig = NonNull::from(&*value); + + let value = AtomicRef::map(value, |v| v.storage.downcast_ref::()); + + Self { value, orig } } #[inline] - pub(crate) fn get(&self) -> &T { - &self.storage + pub fn into_inner(self) -> AtomicRef<'a, [T]> { + self.value } #[inline] - pub(crate) fn get_mut(&mut self) -> &mut T { - &mut self.storage + pub(crate) fn changes(&self) -> &Changes { + // SAFETY: `value` is not accessed in this function + unsafe { &self.orig.as_ref().changes } + } + + pub(crate) fn orig(&self) -> &CellData { + unsafe { self.orig.as_ref() } + } +} + +impl<'w, T> Deref for CellGuard<'w, T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.value } } @@ -72,33 +116,52 @@ impl<'a, T: ?Sized> CellMutGuard<'a, T> { /// /// A modification invent is only generated *if* if this is mutably dereferenced. pub struct RefMut<'a, T> { - guard: CellMutGuard<'a, T>, + value: AtomicRefMut<'a, T>, + // From the refcell + orig: *mut CellData, + + archetype: &'a Archetype, slot: Slot, modified: bool, + tick: u32, } -impl<'a, T: Debug> Debug for RefMut<'a, T> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - self.guard.fmt(f) - } -} - -impl<'a, T> RefMut<'a, T> { - pub(crate) fn new(guard: CellMutGuard<'a, [T]>, slot: Slot) -> Option { - Some(RefMut { - guard: guard.filter_map(|v| v.get_mut(slot))?, +impl<'a, T: ComponentValue> RefMut<'a, T> { + pub(super) fn new( + mut value: AtomicRefMut<'a, CellData>, + archetype: &'a Archetype, + slot: Slot, + tick: u32, + ) -> Option { + // Store the original pointer. This will be used when dropped + let orig = &mut *value as *mut CellData; + + let value = + AtomicRefMut::filter_map(value, |v| v.storage.downcast_mut::().get_mut(slot))?; + + Some(Self { + value, + orig, + archetype, slot, modified: false, + tick, }) } } +impl<'a, T: Debug> Debug for RefMut<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.value.fmt(f) + } +} + impl<'a, T> Deref for RefMut<'a, T> { type Target = T; #[inline] fn deref(&self) -> &Self::Target { - self.guard.get() + &self.value } } @@ -106,7 +169,7 @@ impl<'a, T> DerefMut for RefMut<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.modified = true; - self.guard.get_mut() + &mut self.value } } @@ -114,7 +177,14 @@ impl<'a, T> Drop for RefMut<'a, T> { #[inline] fn drop(&mut self) { if self.modified { - self.guard.set_modified(Slice::single(self.slot)); + // SAFETY: `value` is not accessed beyond this point + let orig = unsafe { &mut *self.orig }; + + orig.set_modified( + &self.archetype.entities, + Slice::single(self.slot), + self.tick, + ) } } } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 57f0e6cc..687e58de 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -5,7 +5,7 @@ use alloc::{ }; use core::{fmt::Debug, mem}; -use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut, BorrowError, BorrowMutError}; +use atomic_refcell::{AtomicRef, AtomicRefCell, BorrowError, BorrowMutError}; use itertools::Itertools; use crate::{ @@ -85,33 +85,85 @@ impl ArchetypeInfo { } } +pub(crate) struct CellData { + pub(crate) storage: Storage, + pub(crate) changes: Changes, + subscribers: Vec>, + pub(crate) key: ComponentKey, +} + +impl CellData { + pub fn set_modified(&mut self, entities: &[Entity], slice: Slice, change_tick: u32) { + let component = self.key; + self.on_event(EventData { + ids: &entities[slice.as_range()], + key: component, + kind: EventKind::Modified, + }); + + self.changes + .set_modified_if_tracking(Change::new(slice, change_tick)); + } + + pub fn set_added(&mut self, entities: &[Entity], slice: Slice, change_tick: u32) { + let component = self.key; + self.on_event(EventData { + ids: &entities[slice.as_range()], + key: component, + kind: EventKind::Added, + }); + + self.changes.set_inserted(Change::new(slice, change_tick)); + } + + /// **Note**: must be called *before* data is dropped + pub fn set_removed(&mut self, entities: &[Entity], slice: Slice, change_tick: u32) { + let component = self.key; + self.on_event(EventData { + ids: &entities[slice.as_range()], + key: component, + kind: EventKind::Added, + }); + + self.changes.set_inserted(Change::new(slice, change_tick)); + } +} + /// Stores a list of component values, changes, and subscribers pub(crate) struct Cell { - storage: AtomicRefCell, - changes: AtomicRefCell, + pub(crate) data: AtomicRefCell, info: ComponentInfo, - pub(crate) subscribers: Vec>, } impl Cell { + pub(crate) fn new(info: ComponentInfo) -> Self { + Self { + data: AtomicRefCell::new(CellData { + storage: Storage::new(info), + changes: Changes::new(), + subscribers: Vec::new(), + key: info.key, + }), + info, + } + } + /// Moves a slot in the cell to another cell and slot while migrating all changes. fn move_to(&mut self, slot: Slot, dst: &mut Self, dst_slot: Slot) { - let storage = self.storage.get_mut(); - let changes = self.changes.get_mut(); + let data = self.data.get_mut(); - let last = storage.len() - 1; + let last = data.storage.len() - 1; - let dst_storage = dst.storage.get_mut(); - let dst_changes = dst.changes.get_mut(); + let dst = dst.data.get_mut(); - storage.swap_remove(slot, |p| unsafe { - dst_storage.extend(p, 1); + data.storage.swap_remove(slot, |p| unsafe { + dst.storage.extend(p, 1); }); // Replace this slot with the last slot and move everything to the dst archetype - changes.swap_remove(slot, last, |kind, mut v| { + data.changes.swap_remove(slot, last, |kind, mut v| { v.slice = Slice::single(dst_slot); - dst_changes.set(kind, v); + dst.changes.set(kind, v); }); // Do not notify of removal, since the component is still intact, but in another archetype @@ -119,16 +171,14 @@ impl Cell { /// Moves all slots to another cell fn move_all(&mut self, dst: &mut Self, dst_start: Slot) { - let storage = self.storage.get_mut(); - let changes = self.changes.get_mut(); + let data = self.data.get_mut(); - let dst_storage = dst.storage.get_mut(); - let dst_changes = dst.changes.get_mut(); + let dst = dst.data.get_mut(); - debug_assert_eq!(dst_storage.len(), dst_start); - unsafe { dst_storage.append(storage) } + debug_assert_eq!(dst.storage.len(), dst_start); + unsafe { dst.storage.append(&mut data.storage) } - changes.zip_map(dst_changes, |_, a, b| { + data.changes.zip_map(&mut dst.changes, |_, a, b| { a.drain(..).for_each(|mut change| { change.slice.start += dst_start; change.slice.end += dst_start; @@ -140,19 +190,18 @@ impl Cell { /// Move a slot out of the cell by swapping with the last fn take(&mut self, slot: Slot, mut on_move: impl FnMut(ComponentInfo, *mut u8)) { - let storage = self.storage.get_mut(); - let changes = self.changes.get_mut(); + let data = self.data.get_mut(); - let last = storage.len() - 1; + let last = data.storage.len() - 1; - storage.swap_remove(slot, |p| on_move(self.info, p)); - changes.swap_remove(slot, last, |_, _| {}); + data.storage.swap_remove(slot, |p| on_move(self.info, p)); + data.changes.swap_remove(slot, last, |_, _| {}); } /// Silently clears (and drops) all components and changes. fn clear(&mut self) { - let storage = self.storage.get_mut(); - let changes = self.changes.get_mut(); + let data = self.data.get_mut(); + // if !storage.is_empty() { // // Notify removed // for v in self.subscribers.iter() { @@ -160,31 +209,28 @@ impl Cell { // } // } - storage.clear(); - changes.clear(); + data.storage.clear(); + data.changes.clear(); // Notify subscribers } /// Drain the values in the cell. pub(crate) fn drain(&mut self) -> Storage { - let storage = mem::replace(self.storage.get_mut(), Storage::new(self.info)); - self.changes.get_mut().clear(); + let data = self.data.get_mut(); + let storage = mem::replace(&mut data.storage, Storage::new(self.info)); + data.changes.clear(); // Notify subscribers storage } - pub(crate) fn storage(&self) -> &AtomicRefCell { - &self.storage - } - /// # Safety /// /// Assumes `self` is of type `T` pub(crate) unsafe fn get(&self, slot: Slot) -> Option> { - let storage = self.storage.borrow(); - AtomicRef::filter_map(storage, |v| v.downcast_ref::().get(slot)) + let data = self.data.borrow(); + AtomicRef::filter_map(data, |v| v.storage.downcast_ref::().get(slot)) } /// # Safety @@ -194,76 +240,42 @@ impl Cell { &self, slot: Slot, ) -> Result>, BorrowError> { - let storage = self.storage.try_borrow()?; - Ok(AtomicRef::filter_map(storage, |v| { - v.downcast_ref::().get(slot) + let data = self.data.try_borrow()?; + Ok(AtomicRef::filter_map(data, |v| { + v.storage.downcast_ref::().get(slot) })) } #[inline] - pub fn borrow_mut<'a, T: ComponentValue>( - &'a self, - entities: &'a [Entity], - tick: u32, - ) -> CellMutGuard<'a, [T]> { - let storage = self.storage.borrow_mut(); - let changes = self.changes.borrow_mut(); - - CellMutGuard { - storage: AtomicRefMut::map(storage, |v| v.downcast_mut()), - changes, - cell: self, - ids: entities, - tick, - } + pub fn borrow(&self) -> CellGuard { + CellGuard::new(self.data.borrow()) } #[inline] - pub fn try_borrow_mut<'a, T: ComponentValue>( - &'a self, - entities: &'a [Entity], - tick: u32, - ) -> Result, BorrowMutError> { - let storage = self.storage.try_borrow_mut()?; - let changes = self.changes.try_borrow_mut()?; + pub fn borrow_mut(&self) -> CellMutGuard { + CellMutGuard::new(self.data.borrow_mut()) + } - Ok(CellMutGuard { - storage: AtomicRefMut::map(storage, |v| v.downcast_mut()), - changes, - cell: self, - ids: entities, - tick, - }) + #[inline] + pub fn try_borrow(&self) -> Result, BorrowError> { + Ok(CellGuard::new(self.data.try_borrow()?)) } - /// # Safety - /// - /// Assumes `self` is of type `T` - pub(crate) unsafe fn get_mut<'a, T: ComponentValue>( - &'a self, - entities: &'a [Entity], - slot: Slot, - tick: u32, - ) -> Option> { - RefMut::new(self.borrow_mut(entities, tick), slot) + #[inline] + pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { + Ok(CellMutGuard::new(self.data.try_borrow_mut()?)) } - /// # Safety - /// - /// Assumes `self` is of type `T` - pub(crate) unsafe fn try_get_mut<'a, T: ComponentValue>( + #[inline] + pub fn get_mut<'a, T: ComponentValue>( &'a self, - entities: &'a [Entity], + archetype: &'a Archetype, slot: Slot, tick: u32, - ) -> Result>, BorrowMutError> { - Ok(RefMut::new(self.try_borrow_mut(entities, tick)?, slot)) + ) -> Option> { + RefMut::new(self.data.borrow_mut(), archetype, slot, tick) } - // pub(crate) fn info(&self) -> ComponentInfo { - // self.info - // } - #[inline] pub(crate) fn info(&self) -> ComponentInfo { self.info @@ -291,14 +303,9 @@ pub struct Archetype { unsafe impl Send for Cell {} unsafe impl Sync for Cell {} -impl Cell { - fn on_event(&self, all_ids: &[Entity], slots: Slice, kind: EventKind) { - let event = EventData { - ids: &all_ids[slots.as_range()], - key: self.info.key, - kind, - }; - +impl CellData { + #[inline] + fn on_event(&self, event: EventData) { for handler in self.subscribers.iter() { handler.on_event(&event) } @@ -328,15 +335,7 @@ impl Archetype { .map(|info| { let key = info.key(); - ( - key, - Cell { - info, - storage: AtomicRefCell::new(Storage::new(info)), - changes: AtomicRefCell::new(Changes::new()), - subscribers: Vec::new(), - }, - ) + (key, Cell::new(info)) }) .collect(); @@ -398,9 +397,8 @@ impl Archetype { pub(crate) fn borrow( &self, component: ComponentKey, - ) -> Option> { - let storage = self.cell(component)?.storage.borrow(); - Some(AtomicRef::map(storage, |v| unsafe { v.borrow() })) + ) -> Option> { + Some(self.cell(component)?.borrow()) } /// Access a component storage mutably. @@ -412,10 +410,11 @@ impl Archetype { /// If the storage or changes is already borrowed pub(crate) fn borrow_mut( &self, - component: Component, - tick: u32, - ) -> Option> { - Some(self.cell(component.key())?.borrow_mut(&self.entities, tick)) + component: ComponentKey, + ) -> Option> { + let cell = self.cell(component)?; + let data = cell.borrow_mut(); + Some(data) } /// Removes a slot and swaps in the last slot @@ -438,12 +437,12 @@ impl Archetype { .cells .values() .map(|v| { - let s = v.storage.borrow(); + let data = v.data.borrow(); ( v.info, StorageInfo { - cap: s.capacity(), - len: s.len(), + cap: data.storage.capacity(), + len: data.storage.len(), }, ) }) @@ -456,23 +455,10 @@ impl Archetype { } } - /// Borrow the change list - pub(crate) fn changes(&self, component: ComponentKey) -> Option> { - let changes = self.cell(component)?.changes.borrow(); - Some(changes) - } - pub(crate) fn removals(&self, component: ComponentKey) -> Option<&ChangeList> { self.removals.get(&component) } - /// Borrow the change list mutably - #[cfg(test)] - pub(crate) fn changes_mut(&self, component: ComponentKey) -> Option> { - let changes = self.cell(component)?.changes.borrow_mut(); - Some(changes) - } - /// Get a component from the entity at `slot` pub(crate) fn get_mut( &self, @@ -480,9 +466,7 @@ impl Archetype { component: Component, tick: u32, ) -> Option> { - let cell = self.cell(component.key())?; - - unsafe { cell.get_mut(&self.entities, slot, tick) } + self.cell(component.key())?.get_mut(&self, slot, tick) } /// Get a component from the entity at `slot` @@ -497,7 +481,7 @@ impl Archetype { None => return Ok(None), }; - unsafe { cell.try_get_mut(&self.entities, slot, tick) } + Ok(cell.get_mut(&self, slot, tick)) } /// Get a component from the entity at `slot` @@ -511,14 +495,12 @@ impl Archetype { ) -> Option { let cell = self.cells.get_mut(&component)?; - let value = unsafe { cell.storage.get_mut().at_mut(slot)? }; - let value = (modify)(value); + let data = cell.data.get_mut(); - cell.on_event(&self.entities, Slice::single(slot), EventKind::Modified); + let value = unsafe { data.storage.at_mut(slot)? }; + let value = (modify)(value); - cell.changes - .get_mut() - .set_modified_if_tracking(Change::new(Slice::single(slot), change_tick)); + data.set_modified(&self.entities, Slice::single(slot), change_tick); Some(value) } @@ -534,16 +516,14 @@ impl Archetype { ) -> Option { let cell = self.cells.get(&component.key())?; + let mut data = cell.data.borrow_mut(); + // Safety // Component - let value = unsafe { &mut *(cell.storage.borrow_mut().at_mut(slot)? as *mut T) }; + let value = unsafe { &mut *(data.storage.at_mut(slot)? as *mut T) }; let value = (f)(value); - cell.on_event(&self.entities, Slice::single(slot), EventKind::Modified); - - cell.changes - .borrow_mut() - .set_modified_if_tracking(Change::new(Slice::single(slot), change_tick)); + data.set_modified(&self.entities, Slice::single(slot), change_tick); Some(value) } @@ -585,9 +565,9 @@ impl Archetype { let slot = self.allocate(id); for (info, src) in buffer.drain() { unsafe { - let storage = self.cells.get_mut(&info.key).unwrap().storage.get_mut(); + let data = self.cells.get_mut(&info.key).unwrap().data.get_mut(); - storage.extend(src, 1); + data.storage.extend(src, 1); } } @@ -640,25 +620,21 @@ impl Archetype { pub unsafe fn push(&mut self, component: ComponentKey, src: *mut u8, tick: u32) -> Option<()> { let len = self.len(); let cell = self.cells.get_mut(&component)?; - let storage = cell.storage.get_mut(); + let data = cell.data.get_mut(); - let slot = storage.len(); + let slot = data.storage.len(); assert_eq!(slot, len - 1, "Not inserting at end"); - storage.extend(src, 1); + data.storage.extend(src, 1); // TODO remove and make internal assert!( - storage.len() <= len, + data.storage.len() <= len, "Attempt to insert more values than entities {} > {}", - storage.len(), + data.storage.len(), self.entities.len() ); - cell.on_event(&self.entities, Slice::single(slot), EventKind::Added); - - cell.changes - .get_mut() - .set_inserted(Change::new(Slice::single(slot), tick)); + data.set_added(&self.entities, Slice::single(slot), tick); Some(()) } @@ -671,19 +647,15 @@ impl Archetype { pub(crate) unsafe fn extend(&mut self, src: &mut Storage, tick: u32) -> Option<()> { let len = self.len(); let cell = self.cells.get_mut(&src.info().key())?; - let storage = cell.storage.get_mut(); + let mut data = cell.data.get_mut(); - let slots = Slice::new(storage.len(), storage.len() + src.len()); + let slots = Slice::new(data.storage.len(), data.storage.len() + src.len()); debug_assert!(slots.start <= len); - cell.storage.get_mut().append(src); - debug_assert!(cell.storage.get_mut().len() <= len); + data.storage.append(src); + debug_assert!(data.storage.len() <= len); - cell.on_event(&self.entities, slots, EventKind::Added); - - cell.changes - .get_mut() - .set_inserted(Change::new(slots, tick)); + data.set_added(&self.entities, slots, tick); Some(()) } @@ -710,24 +682,23 @@ impl Archetype { let dst_slot = dst.allocate(id); - // // Before the cells - // for subscriber in &self.subscribers { - // subscriber.on_moved_pre(id, slot, self, dst); - // } - for (&key, cell) in &mut self.cells { - // let info = cell.info; - // let storage = cell.storage.get_mut(); - // let changes = cell.changes.get_mut(); + let data = cell.data.get_mut(); let dst_cell = dst.cells.get_mut(&key); if let Some(dst_cell) = dst_cell { cell.move_to(slot, dst_cell, dst_slot); } else { // Notify the subscribers that the component was removed - cell.on_event(&self.entities, Slice::single(slot), EventKind::Removed); + data.on_event(EventData { + ids: &[id], + key, + kind: EventKind::Removed, + }); cell.take(slot, &mut on_drop); + // Make the destination know of the component that was removed for the entity to + // get there dst.push_removed(key, Change::new(Slice::single(dst_slot), tick)); } } @@ -741,10 +712,6 @@ impl Archetype { }) } - // for subscriber in &dst.subscribers { - // subscriber.on_moved_post(id, self, dst); - // } - let swapped = self.remove_slot(slot); (dst_slot, swapped) @@ -763,29 +730,22 @@ impl Archetype { slot: Slot, mut on_move: impl FnMut(ComponentInfo, *mut u8), ) -> Option<(Entity, Slot)> { - self.entity(slot).expect("Invalid entity"); + let id = self.entity(slot).expect("Invalid entity"); // for subscriber in &self.subscribers { // subscriber.on_despawned(id, slot, self); // } for cell in self.cells.values_mut() { - cell.on_event(&self.entities, Slice::single(slot), EventKind::Removed); + let data = cell.data.get_mut(); + // data.on_event(&self.entities, Slice::single(slot), EventKind::Removed); + data.on_event(EventData { + ids: &[id], + key: data.key, + kind: EventKind::Removed, + }); cell.take(slot, &mut on_move) - // let storage = cell.storage.get_mut(); - // let info = cell.info; - - // storage.swap_remove(slot, |p| { - // (on_take)(info, p); - // }); - - // cell.changes.get_mut().swap_remove(slot, last, |_, _| {}); - - // // Notify the subscribers that the component was removed - // cell.subscribers - // .iter() - // .for_each(|v| v.on_change(self, key, ChangeKind::Removed)); } // Remove the component removals for slot @@ -831,10 +791,14 @@ impl Archetype { let dst_slots = dst.allocate_n(&entities); for (key, cell) in &mut self.cells { + let data = cell.data.get_mut(); + let dst_cell = dst.cells.get_mut(key); if let Some(dst) = dst_cell { - assert_eq!(cell.storage.get_mut().len(), len); + let dst_data = dst.data.get_mut(); + + assert_eq!(data.storage.len(), len); cell.move_all(dst, dst_slots.start); // let dst_changes = dst.changes.get_mut(); @@ -854,7 +818,11 @@ impl Archetype { // unsafe { dst.storage.get_mut().append(storage) } } else { // Notify the subscribers that the component was removed - cell.on_event(&entities, slots, EventKind::Removed); + data.on_event(EventData { + ids: &entities, + key: data.key, + kind: EventKind::Removed, + }); cell.clear(); dst.push_removed(*key, Change::new(dst_slots, tick)) @@ -882,8 +850,8 @@ impl Archetype { /// len remains unchanged, as does the internal order pub fn reserve(&mut self, additional: usize) { for cell in self.cells.values_mut() { - let storage = cell.storage.get_mut(); - storage.reserve(additional); + let data = cell.data.get_mut(); + data.storage.reserve(additional); } } @@ -896,8 +864,15 @@ impl Archetype { pub(crate) fn clear(&mut self) { let slots = self.slots(); for cell in self.cells.values_mut() { + let data = cell.data.get_mut(); // Notify the subscribers that the component was removed - cell.on_event(&self.entities, slots, EventKind::Removed); + // data.on_event(&self.entities, slots, EventKind::Removed); + data.on_event(EventData { + ids: &self.entities[slots.as_range()], + key: data.key, + kind: EventKind::Removed, + }); + cell.clear() } @@ -927,8 +902,8 @@ impl Archetype { } /// Returns a iterator which attempts to borrows each storage in the archetype - pub(crate) fn try_borrow_all(&self) -> impl Iterator>> { - self.cells.values().map(|v| v.storage.try_borrow().ok()) + pub(crate) fn try_borrow_all(&self) -> impl Iterator>> { + self.cells.values().map(|v| v.data.try_borrow().ok()) } /// Access the entities in the archetype for each slot. Entity is None if /// the slot is not occupied, only for the last slots. @@ -943,7 +918,12 @@ impl Archetype { pub(crate) fn drain(&mut self) -> ArchetypeDrain { let slots = self.slots(); for cell in self.cells.values_mut() { - cell.on_event(&self.entities, slots, EventKind::Removed); + let data = cell.data.get_mut(); + data.on_event(EventData { + ids: &self.entities[slots.as_range()], + key: data.key, + kind: EventKind::Removed, + }) } self.removals.clear(); @@ -966,11 +946,12 @@ impl Archetype { pub(crate) fn add_handler(&mut self, s: Arc) { // For component changes for cell in self.cells.values_mut() { + let data = cell.data.get_mut(); if s.matches_component(cell.info) { - cell.subscribers.push(s.clone()); + data.subscribers.push(s.clone()); } - cell.subscribers.retain(|v| v.is_connected()) + data.subscribers.retain(|v| v.is_connected()) } } @@ -979,6 +960,11 @@ impl Archetype { self.cells.get(&key) } + #[inline(always)] + pub(crate) fn cell_mut(&mut self, key: ComponentKey) -> Option<&mut Cell> { + self.cells.get_mut(&key) + } + fn last(&self) -> Option { self.entities.last().copied() } @@ -988,6 +974,12 @@ impl Archetype { self.children.remove(&component); assert!(linked.is_some()); } + + /// Borrow the change list mutably + #[cfg(test)] + pub(crate) fn changes_mut(&mut self, component: ComponentKey) -> Option<&mut Changes> { + Some(&mut self.cell_mut(component)?.data.get_mut().changes) + } } impl Drop for Archetype { diff --git a/src/archetype/storage.rs b/src/archetype/storage.rs index 12267d1a..a42e7875 100644 --- a/src/archetype/storage.rs +++ b/src/archetype/storage.rs @@ -204,15 +204,6 @@ impl Storage { unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast::(), self.len) } } - // #[inline(always)] - /// # Safety - /// The types must match - pub unsafe fn borrow(&self) -> &[T] { - debug_assert!(self.info.is::(), "Mismatched types"); - - core::slice::from_raw_parts(self.data.as_ptr().cast::(), self.len) - } - pub fn clear(&mut self) { // Drop all contained valid values for slot in 0..self.len { @@ -307,10 +298,10 @@ mod test { storage.push(5); storage.push(7); - assert_eq!(storage.borrow::(), [5, 7]); + assert_eq!(storage.downcast_ref::(), [5, 7]); storage.swap_remove(0, |v| ptr::drop_in_place(v.cast::())); - assert_eq!(storage.borrow::(), [7]); + assert_eq!(storage.downcast_ref::(), [7]); let mut other = Storage::new(a().info()); other.push(8); @@ -318,7 +309,7 @@ mod test { other.push(10); storage.append(&mut other); - assert_eq!(storage.borrow::(), [7, 8, 9, 10]); + assert_eq!(storage.downcast_ref::(), [7, 8, 9, 10]); } } diff --git a/src/component.rs b/src/component.rs index 97a9d564..10501081 100644 --- a/src/component.rs +++ b/src/component.rs @@ -145,9 +145,9 @@ crate::component! { /// Defines a strongly typed component. /// -/// Implements a *Read* fetch when used as part of a query +/// Implements a *read only* fetch when used as part of a query /// -/// Use `.as_mut()` to get a *Write* fetch. +/// Use `.as_mut()` to acquire a *mutable* fetch. pub struct Component { key: ComponentKey, marker: PhantomData, @@ -419,7 +419,7 @@ impl ComponentInfo { } #[inline] - pub(crate) fn is(&self) -> bool { + pub(crate) fn is(&self) -> bool { (self.vtable.type_id)() == TypeId::of::() } diff --git a/src/fetch/component.rs b/src/fetch/component.rs index 04bb4755..a3eb93d3 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -36,7 +36,9 @@ where #[inline] fn prepare(&self, data: FetchPrepareData<'w>) -> Option { let borrow = data.arch.borrow(self.key())?; - Some(ReadComponent { borrow }) + Some(ReadComponent { + borrow: borrow.into_inner(), + }) } #[inline] diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 3aa3e750..43c622c1 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -11,15 +11,6 @@ use crate::{ use super::{FetchAccessData, FetchPrepareData, PreparedFetch}; -#[doc(hidden)] -pub struct WriteComponent<'a, T> { - storage: AtomicRefMut<'a, [T]>, - changes: AtomicRefMut<'a, Changes>, - cell: &'a Cell, - ids: &'a [Entity], - tick: u32, -} - #[derive(Debug, Clone)] /// Mutable component fetch /// See [crate::Component::as_mut] @@ -35,20 +26,12 @@ where #[inline] fn prepare(&self, data: FetchPrepareData<'w>) -> Option { - let CellMutGuard { - storage, - changes, - cell, - ids, - tick, - } = data.arch.borrow_mut(self.0, data.new_tick)?; + let guard = data.arch.borrow_mut(self.0.key())?; Some(WriteComponent { - storage, - changes, - cell, - ids, - tick, + guard, + arch: data.arch, + tick: data.new_tick, }) } @@ -93,7 +76,14 @@ impl<'q, T: ComponentValue> FetchItem<'q> for Mutable { type Item = &'q mut T; } -impl<'q, 'w, T: 'q> PreparedFetch<'q> for WriteComponent<'w, T> { +#[doc(hidden)] +pub struct WriteComponent<'a, T> { + guard: CellMutGuard<'a, T>, + arch: &'a Archetype, + tick: u32, +} + +impl<'q, 'w, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> { type Item = &'q mut T; #[inline(always)] @@ -101,21 +91,23 @@ impl<'q, 'w, T: 'q> PreparedFetch<'q> for WriteComponent<'w, T> { // Perform a reborrow // Cast from a immutable to a mutable borrow as all calls to this // function are guaranteed to be disjoint - unsafe { &mut *(self.storage.get_unchecked_mut(slot) as *mut T) } + unsafe { &mut *(self.guard.get_unchecked_mut(slot) as *mut T) } } fn set_visited(&mut self, slots: Slice) { - let event = EventData { - ids: &self.ids[slots.as_range()], - key: self.cell.info().key, - kind: EventKind::Modified, - }; - - for handler in self.cell.subscribers.iter() { - handler.on_event(&event) - } - - self.changes - .set_modified_if_tracking(Change::new(slots, self.tick)); + self.guard + .set_modified(&self.arch.entities, slots, self.tick); + // let event = EventData { + // ids: &self.ids[slots.as_range()], + // key: self.cell.info().key, + // kind: EventKind::Modified, + // }; + + // for handler in self.cell.subscribers.iter() { + // handler.on_event(&event) + // } + + // self.changes + // .set_modified_if_tracking(Change::new(slots, self.tick)); } } diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index ae1d54e7..7842304c 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -3,9 +3,9 @@ use atomic_refcell::AtomicRef; use core::marker::PhantomData; use crate::{ - archetype::{Cell, RefMut, Slot}, + archetype::{Archetype, Cell, RefMut, Slot}, system::{Access, AccessKind}, - Component, ComponentValue, Entity, Fetch, FetchItem, + Component, ComponentValue, Fetch, FetchItem, }; use super::{FetchAccessData, PreparedFetch, ReadOnlyFetch}; @@ -33,7 +33,7 @@ impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut { Some(PreparedMaybeMut { cell, new_tick: data.new_tick, - entities: data.arch.entities(), + arch: data.arch, _marker: PhantomData, }) } @@ -83,7 +83,7 @@ impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut { pub struct PreparedMaybeMut<'w, T> { cell: &'w Cell, new_tick: u32, - entities: &'w [Entity], + arch: &'w Archetype, _marker: PhantomData, } @@ -96,7 +96,7 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { slot, cell: self.cell, new_tick: self.new_tick, - entities: self.entities, + arch: self.arch, _marker: PhantomData, } } @@ -109,7 +109,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { slot, cell: self.cell, new_tick: self.new_tick, - entities: self.entities, + arch: self.arch, _marker: PhantomData, } } @@ -120,7 +120,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { /// See: [`MaybeMut`] pub struct MutGuard<'w, T> { slot: Slot, - entities: &'w [Entity], + arch: &'w Archetype, cell: &'w Cell, new_tick: u32, _marker: PhantomData, @@ -138,10 +138,8 @@ impl<'w, T: ComponentValue> MutGuard<'w, T> { /// Triggers a change pub fn write(&self) -> RefMut { // Type is guaranteed by constructor - unsafe { - self.cell - .get_mut(self.entities, self.slot, self.new_tick) - .unwrap() - } + self.cell + .get_mut(&self.arch, self.slot, self.new_tick) + .unwrap() } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 4d950828..e6f77947 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -4,11 +4,10 @@ use core::{ }; use alloc::vec::Vec; -use atomic_refcell::AtomicRef; use smallvec::SmallVec; use crate::{ - archetype::{Archetype, Slot}, + archetype::{Archetype, CellGuard, Slot}, component::dummy, system::{Access, AccessKind}, Component, ComponentValue, Entity, Fetch, FetchItem, RelationExt, @@ -31,15 +30,10 @@ where type Prepared = PreparedRelations<'w, T>; fn prepare(&self, data: FetchPrepareData<'w>) -> Option { - let borrows: SmallVec<[(Entity, AtomicRef<[T]>); 4]> = { + let borrows: SmallVec<[(Entity, CellGuard); 4]> = { data.arch .relations_like(self.component.id()) - .map(|(info, cell)| { - ( - info.object.unwrap(), - AtomicRef::map(cell.storage().borrow(), |v| unsafe { v.borrow() }), - ) - }) + .map(|(info, cell)| (info.object.unwrap(), cell.borrow())) .collect() }; @@ -78,7 +72,7 @@ impl<'q, T: ComponentValue> FetchItem<'q> for Relations { #[doc(hidden)] pub struct PreparedRelations<'a, T> { - borrows: SmallVec<[(Entity, AtomicRef<'a, [T]>); 4]>, + borrows: SmallVec<[(Entity, CellGuard<'a, T>); 4]>, } impl<'q, 'w, T> PreparedFetch<'q> for PreparedRelations<'w, T> @@ -97,7 +91,7 @@ where /// Iterates the relation object and data for the yielded query item pub struct RelationsIter<'a, T> { - borrows: slice::Iter<'a, (Entity, AtomicRef<'a, [T]>)>, + borrows: slice::Iter<'a, (Entity, CellGuard<'a, T>)>, slot: Slot, } diff --git a/src/filter/change.rs b/src/filter/change.rs index 174f7bb2..75c76014 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -1,13 +1,9 @@ use alloc::vec::Vec; -use atomic_refcell::AtomicRef; use core::fmt::Formatter; -use core::ops::Deref; use itertools::Itertools; -use crate::archetype::{Archetype, Change, Slot}; -use crate::fetch::{ - FetchAccessData, FetchPrepareData, PreparedFetch, ReadComponent, ReadOnlyFetch, -}; +use crate::archetype::{Archetype, CellGuard, Change, Slot}; +use crate::fetch::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; use crate::system::{Access, AccessKind}; use crate::{ archetype::{ChangeKind, ChangeList, Slice}, @@ -46,13 +42,9 @@ where type Item = &'q T; } -impl<'q, Q: ReadOnlyFetch<'q>, A> ReadOnlyFetch<'q> for PreparedChangeFilter -where - Q: PreparedFetch<'q>, - A: Deref, -{ +impl<'q, 'w, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T> { unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { - self.fetch.fetch_shared(slot) + unsafe { self.data.get_unchecked(slot) } } } @@ -62,20 +54,22 @@ where { const MUTABLE: bool = false; - type Prepared = PreparedChangeFilter, AtomicRef<'w, [Change]>>; + type Prepared = PreparedChangeFilter<'w, T>; fn prepare(&'w self, data: crate::fetch::FetchPrepareData<'w>) -> Option { - let changes = data.arch.changes(self.component.key())?; + let cell = data.arch.cell(self.component.key())?; + let guard = cell.borrow(); // Make sure to enable modification tracking if it is actively used if self.kind.is_modified() { - changes.set_track_modified() + guard.changes().set_track_modified() } - let changes = AtomicRef::map(changes, |changes| changes.get(self.kind).as_slice()); - - let fetch = self.component.prepare(data)?; - Some(PreparedChangeFilter::new(fetch, changes, data.old_tick)) + Some(PreparedChangeFilter { + data: guard, + kind: self.kind, + cursor: ChangeCursor::new(data.old_tick), + }) } fn filter_arch(&self, arch: &Archetype) -> bool { @@ -105,37 +99,22 @@ where } } -#[doc(hidden)] -pub struct PreparedChangeFilter { - fetch: Q, - changes: A, - cur: Option, +struct ChangeCursor { cursor: usize, old_tick: u32, + cur: Option, } -impl core::fmt::Debug for PreparedChangeFilter { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("PreparedChangeFilter") - .finish_non_exhaustive() - } -} - -impl PreparedChangeFilter -where - A: Deref, -{ - pub(crate) fn new(fetch: Q, changes: A, old_tick: u32) -> Self { +impl ChangeCursor { + fn new(old_tick: u32) -> Self { Self { - fetch, - changes, - cur: None, cursor: 0, old_tick, + cur: None, } } - pub(crate) fn find_slice(&mut self, slots: Slice) -> Option { + pub(crate) fn find_slice(&mut self, changes: &[Change], slots: Slice) -> Option { // Short circuit if let Some(cur) = self.cur { if cur.overlaps(slots) { @@ -143,7 +122,7 @@ where } } - let change = self.changes[self.cursor..] + let change = changes[self.cursor..] .iter() .filter(|v| v.tick > self.old_tick) .find_position(|change| change.slice.overlaps(slots)); @@ -154,7 +133,7 @@ where return Some(change.slice); } - let change = self.changes[..self.cursor] + let change = changes[..self.cursor] .iter() .filter(|v| v.tick > self.old_tick) .find_position(|change| change.slice.overlaps(slots)); @@ -167,21 +146,34 @@ where } } -impl<'q, Q, A> PreparedFetch<'q> for PreparedChangeFilter -where - Q: PreparedFetch<'q>, - A: Deref, -{ - type Item = Q::Item; +#[doc(hidden)] +pub struct PreparedChangeFilter<'w, T> { + data: CellGuard<'w, T>, + kind: ChangeKind, + cursor: ChangeCursor, +} + +impl<'w, T> core::fmt::Debug for PreparedChangeFilter<'w, T> { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PreparedChangeFilter") + .finish_non_exhaustive() + } +} + +impl<'q, 'w, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T> { + type Item = &'q T; #[inline] unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.fetch.fetch(slot) + unsafe { self.data.get_unchecked(slot) } } #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let cur = match self.find_slice(slots) { + let cur = match self + .cursor + .find_slice(&self.data.changes().get(self.kind), slots) + { Some(v) => v, None => return Slice::new(slots.end, slots.end), }; @@ -189,10 +181,6 @@ where cur.intersect(&slots) .unwrap_or(Slice::new(slots.end, slots.end)) } - - fn set_visited(&mut self, slots: Slice) { - self.fetch.set_visited(slots) - } } #[derive(Clone)] @@ -221,19 +209,21 @@ impl RemovedFilter { impl<'q, T: ComponentValue> FetchItem<'q> for RemovedFilter { type Item = (); } - -impl<'a, T: ComponentValue> Fetch<'a> for RemovedFilter { +impl<'w, T: ComponentValue> Fetch<'w> for RemovedFilter { const MUTABLE: bool = false; - type Prepared = PreparedChangeFilter<(), &'a [Change]>; + type Prepared = PreparedRemoveFilter<'w>; - fn prepare(&self, data: FetchPrepareData<'a>) -> Option { + fn prepare(&self, data: FetchPrepareData<'w>) -> Option { let changes = data .arch .removals(self.component.key()) .unwrap_or(&EMPTY_CHANGELIST); - Some(PreparedChangeFilter::new((), changes, data.old_tick)) + Some(PreparedRemoveFilter { + changes, + cursor: ChangeCursor::new(data.old_tick), + }) } fn filter_arch(&self, _: &Archetype) -> bool { @@ -255,11 +245,59 @@ impl<'a, T: ComponentValue> Fetch<'a> for RemovedFilter { } } +#[doc(hidden)] +pub struct PreparedRemoveFilter<'w> { + changes: &'w [Change], + cursor: ChangeCursor, +} + +impl<'w> PreparedRemoveFilter<'w> { + pub fn new(changes: &'w [Change], new_tick: u32) -> Self { + Self { + changes, + cursor: ChangeCursor::new(new_tick), + } + } +} + +impl<'w> core::fmt::Debug for PreparedRemoveFilter<'w> { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PreparedRemoveFilter") + .finish_non_exhaustive() + } +} + +impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item {} +} + +impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { + type Item = (); + + #[inline] + unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item {} + + #[inline] + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + let cur = match self.cursor.find_slice(&self.changes, slots) { + Some(v) => v, + None => return Slice::new(slots.end, slots.end), + }; + + cur.intersect(&slots) + .unwrap_or(Slice::new(slots.end, slots.end)) + } +} + #[cfg(test)] mod test { use pretty_assertions::assert_eq; - use crate::filter::FilterIter; + use crate::{ + archetype::{Cell, Change}, + filter::FilterIter, + name, + }; use super::*; @@ -272,7 +310,10 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let mut filter = PreparedChangeFilter::new((), &changes[..], 2); + let mut filter = PreparedRemoveFilter { + changes: &changes[..], + cursor: ChangeCursor::new(2), + }; unsafe { assert_eq!(filter.filter_slots(Slice::new(0, 10)), Slice::new(10, 10)); @@ -300,7 +341,10 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let filter = PreparedChangeFilter::new((), &changes[..], 2); + let mut filter = PreparedRemoveFilter { + changes: &changes[..], + cursor: ChangeCursor::new(2), + }; let slices = FilterIter::new(Slice::new(0, 500), filter).collect_vec(); @@ -324,7 +368,10 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let filter = PreparedChangeFilter::new((), &changes[..], 2); + let mut filter = PreparedRemoveFilter { + changes: &changes[..], + cursor: ChangeCursor::new(2), + }; let slices = FilterIter::new(Slice::new(25, 150), filter) .take(100) diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 9699ac36..7bc12577 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -19,7 +19,7 @@ use crate::{ ArchetypeSearcher, ComponentKey, Entity, Fetch, FetchItem, }; -pub use change::*; +pub use change::{ChangeFilter, RemovedFilter}; pub use cmp::{Cmp, Equal, Greater, GreaterEq, Less, LessEq}; pub use constant::*; pub use set::*; @@ -594,7 +594,9 @@ mod tests { use crate::{ archetype::{Change, ChangeKind, ChangeList}, - component, ArchetypeId, World, + component, + filter::change::PreparedRemoveFilter, + ArchetypeId, World, }; use super::*; @@ -610,7 +612,7 @@ mod tests { changes.set(Change::new(Slice::new(784, 800), 7)); changes.set(Change::new(Slice::new(945, 1139), 8)); - let filter = PreparedChangeFilter::new((), changes.as_slice(), 2); + let filter = PreparedRemoveFilter::new(&changes, 2); // The whole "archetype" let slots = Slice::new(0, 1238); @@ -644,8 +646,8 @@ mod tests { let slots = Slice::new(0, 1000); // Or - let a = PreparedChangeFilter::new((), changes_1.as_slice(), 1); - let b = PreparedChangeFilter::new((), changes_2.as_slice(), 2); + let a = PreparedRemoveFilter::new(changes_1.as_slice(), 1); + let b = PreparedRemoveFilter::new(changes_2.as_slice(), 2); let filter = Or((Some(a), Some(b))); @@ -661,8 +663,8 @@ mod tests { // And - let a = PreparedChangeFilter::new((), changes_1.as_slice(), 1); - let b = PreparedChangeFilter::new((), changes_2.as_slice(), 2); + let a = PreparedRemoveFilter::new(changes_1.as_slice(), 1); + let b = PreparedRemoveFilter::new(changes_2.as_slice(), 2); let filter = And(a, b); @@ -685,7 +687,7 @@ mod tests { c: u32, } - let archetype = Archetype::new([a().info(), b().info(), c().info()]); + let mut archetype = Archetype::new([a().info(), b().info(), c().info()]); let filter = (ChangeFilter::new(a(), ChangeKind::Modified) & ChangeFilter::new(b(), ChangeKind::Modified)) diff --git a/src/format.rs b/src/format.rs index bf2bf3eb..71543fde 100644 --- a/src/format.rs +++ b/src/format.rs @@ -135,11 +135,11 @@ impl Debug for ComponentName { impl<'a> Debug for RowValueFormatter<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let mut map = f.debug_map(); - for storage in self.arch.try_borrow_all().flatten() { - let info = storage.info(); + for data in self.arch.try_borrow_all().flatten() { + let info = data.storage.info(); if let Ok(visitor) = self.world.get(info.key().id, debuggable()) { - map.entry(&info, (visitor.debug_storage)(&storage, self.slot)); + map.entry(&info, (visitor.debug_storage)(&data.storage, self.slot)); } else { map.entry(&info, &MissingDebug); } diff --git a/src/lib.rs b/src/lib.rs index 14890e43..8ec09cfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -243,6 +243,7 @@ pub mod serialize; mod util; /// vtable implementation for dynamic dispatching pub mod vtable; +mod set_traits; // Required due to macro pub use archetype::{ArchetypeId, BatchSpawn, RefMut}; diff --git a/src/relation.rs b/src/relation.rs index 97b6bbe2..84b9f39b 100644 --- a/src/relation.rs +++ b/src/relation.rs @@ -207,7 +207,7 @@ where /// See: [crate::RelationIter] pub struct RelationIterMut<'a, T> { - entities: &'a [Entity], + arch: &'a Archetype, cells: Range<'a, ComponentKey, Cell>, slot: Slot, change_tick: u32, @@ -230,7 +230,7 @@ impl<'a, T: ComponentValue> RelationIterMut<'a, T> { slot, marker: PhantomData, change_tick, - entities: arch.entities(), + arch, } } } @@ -243,10 +243,10 @@ where fn next(&mut self) -> Option { let (&key, cell) = self.cells.next()?; - // Safety: the type matches the relation ext - Some((key.object().unwrap(), unsafe { - cell.get_mut::(self.entities, self.slot, self.change_tick) - .unwrap() - })) + Some(( + key.object().unwrap(), + cell.get_mut::(self.arch, self.slot, self.change_tick) + .unwrap(), + )) } } diff --git a/src/serialize/ser.rs b/src/serialize/ser.rs index 25c2370b..617857e4 100644 --- a/src/serialize/ser.rs +++ b/src/serialize/ser.rs @@ -255,9 +255,9 @@ impl<'a> Serialize for SerializeEntityData<'a> { let mut state = serializer.serialize_map(Some(len))?; for cell in self.arch.cells().values() { - let storage = cell.storage().borrow(); - if let Some(slot) = self.context.slots.get(&storage.info().key()) { - state.serialize_entry(&slot.key, (slot.ser)(&storage, self.slot))?; + let data = cell.data.borrow(); + if let Some(slot) = self.context.slots.get(&data.key) { + state.serialize_entry(&slot.key, (slot.ser)(&data.storage, self.slot))?; } } @@ -333,13 +333,14 @@ impl<'a> serde::Serialize for SerializeStorages<'a> { let mut state = serializer.serialize_map(Some(len))?; for cell in self.arch.cells().values() { - let storage = cell.storage().borrow(); - let id = storage.info().key; + let data = cell.data.borrow(); + + let id = data.key; if let Some(slot) = self.context.slots.get(&id) { state.serialize_entry( &slot.key, &SerializeStorage { - storage: &storage, + storage: &data.storage, slot, }, )?; From 57b591219078d73ad50ca1ccd7b8e5d604c7b6b8 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 8 Jul 2023 20:51:49 +0200 Subject: [PATCH 20/52] chore: use entity slice directly --- src/archetype/guard.rs | 39 +++++--------------------------------- src/archetype/mod.rs | 16 ++++++++-------- src/fetch/component_mut.rs | 7 +++---- src/fetch/maybe_mut.rs | 16 ++++++++-------- src/filter/change.rs | 18 +++++++----------- src/relation.rs | 6 +++--- 6 files changed, 34 insertions(+), 68 deletions(-) diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index e0c9f8a1..0787eb5e 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -11,7 +11,7 @@ use crate::{ ComponentValue, Entity, }; -use super::{Archetype, CellData, Change, Changes, Slice, Slot}; +use super::{CellData, Change, Changes, Slice, Slot}; /// Type safe abstraction over a borrowed cell data pub(crate) struct CellMutGuard<'a, T> { @@ -98,10 +98,6 @@ impl<'a, T: ComponentValue> CellGuard<'a, T> { // SAFETY: `value` is not accessed in this function unsafe { &self.orig.as_ref().changes } } - - pub(crate) fn orig(&self) -> &CellData { - unsafe { self.orig.as_ref() } - } } impl<'w, T> Deref for CellGuard<'w, T> { @@ -120,7 +116,7 @@ pub struct RefMut<'a, T> { // From the refcell orig: *mut CellData, - archetype: &'a Archetype, + entities: &'a [Entity], slot: Slot, modified: bool, tick: u32, @@ -129,7 +125,7 @@ pub struct RefMut<'a, T> { impl<'a, T: ComponentValue> RefMut<'a, T> { pub(super) fn new( mut value: AtomicRefMut<'a, CellData>, - archetype: &'a Archetype, + entities: &'a [Entity], slot: Slot, tick: u32, ) -> Option { @@ -142,7 +138,7 @@ impl<'a, T: ComponentValue> RefMut<'a, T> { Some(Self { value, orig, - archetype, + entities, slot, modified: false, tick, @@ -180,32 +176,7 @@ impl<'a, T> Drop for RefMut<'a, T> { // SAFETY: `value` is not accessed beyond this point let orig = unsafe { &mut *self.orig }; - orig.set_modified( - &self.archetype.entities, - Slice::single(self.slot), - self.tick, - ) + orig.set_modified(self.entities, Slice::single(self.slot), self.tick) } } } - -// pub(crate) struct UniqueRefMut<'a, T> { -// value: &'a mut T, -// slot: Slot, -// pub(super) cell: &'a mut Cell, -// pub(super) ids: &'a [Entity], -// pub(super) tick: u32, -// } - -// impl<'a> Drop for UniqueRefMut<'a> { -// #[inline] -// fn drop(&mut self) { -// self.cell -// .on_event(self.ids, Slice::single(self.slot), EventKind::Modified); - -// self.cell -// .changes -// .get_mut() -// .set_modified_if_tracking(Change::new(Slice::single(self.slot), self.tick)); -// } -// } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 687e58de..53683f3a 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -269,11 +269,11 @@ impl Cell { #[inline] pub fn get_mut<'a, T: ComponentValue>( &'a self, - archetype: &'a Archetype, + entities: &'a [Entity], slot: Slot, tick: u32, ) -> Option> { - RefMut::new(self.data.borrow_mut(), archetype, slot, tick) + RefMut::new(self.data.borrow_mut(), entities, slot, tick) } #[inline] @@ -466,7 +466,8 @@ impl Archetype { component: Component, tick: u32, ) -> Option> { - self.cell(component.key())?.get_mut(&self, slot, tick) + self.cell(component.key())? + .get_mut(&self.entities, slot, tick) } /// Get a component from the entity at `slot` @@ -481,7 +482,7 @@ impl Archetype { None => return Ok(None), }; - Ok(cell.get_mut(&self, slot, tick)) + Ok(cell.get_mut(&self.entities, slot, tick)) } /// Get a component from the entity at `slot` @@ -647,7 +648,7 @@ impl Archetype { pub(crate) unsafe fn extend(&mut self, src: &mut Storage, tick: u32) -> Option<()> { let len = self.len(); let cell = self.cells.get_mut(&src.info().key())?; - let mut data = cell.data.get_mut(); + let data = cell.data.get_mut(); let slots = Slice::new(data.storage.len(), data.storage.len() + src.len()); debug_assert!(slots.start <= len); @@ -796,8 +797,6 @@ impl Archetype { let dst_cell = dst.cells.get_mut(key); if let Some(dst) = dst_cell { - let dst_data = dst.data.get_mut(); - assert_eq!(data.storage.len(), len); cell.move_all(dst, dst_slots.start); // let dst_changes = dst.changes.get_mut(); @@ -819,7 +818,7 @@ impl Archetype { } else { // Notify the subscribers that the component was removed data.on_event(EventData { - ids: &entities, + ids: &entities[slots.as_range()], key: data.key, kind: EventKind::Removed, }); @@ -907,6 +906,7 @@ impl Archetype { } /// Access the entities in the archetype for each slot. Entity is None if /// the slot is not occupied, only for the last slots. + #[inline] pub fn entities(&self) -> &[Entity] { self.entities.as_ref() } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 43c622c1..9d69ca96 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -1,12 +1,11 @@ use alloc::vec::Vec; -use atomic_refcell::AtomicRefMut; + use core::fmt::{self, Formatter}; use crate::{ - archetype::{Archetype, Cell, CellMutGuard, Change, Changes, Slice, Slot}, - events::{EventData, EventKind}, + archetype::{Archetype, CellMutGuard, Slice, Slot}, system::{Access, AccessKind}, - Component, ComponentValue, Entity, Fetch, FetchItem, + Component, ComponentValue, Fetch, FetchItem, }; use super::{FetchAccessData, FetchPrepareData, PreparedFetch}; diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index 7842304c..31b020c2 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -3,9 +3,9 @@ use atomic_refcell::AtomicRef; use core::marker::PhantomData; use crate::{ - archetype::{Archetype, Cell, RefMut, Slot}, + archetype::{Cell, RefMut, Slot}, system::{Access, AccessKind}, - Component, ComponentValue, Fetch, FetchItem, + Component, ComponentValue, Entity, Fetch, FetchItem, }; use super::{FetchAccessData, PreparedFetch, ReadOnlyFetch}; @@ -33,7 +33,7 @@ impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut { Some(PreparedMaybeMut { cell, new_tick: data.new_tick, - arch: data.arch, + entities: data.arch.entities(), _marker: PhantomData, }) } @@ -83,7 +83,7 @@ impl<'w, T: ComponentValue> Fetch<'w> for MaybeMut { pub struct PreparedMaybeMut<'w, T> { cell: &'w Cell, new_tick: u32, - arch: &'w Archetype, + entities: &'w [Entity], _marker: PhantomData, } @@ -96,7 +96,7 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { slot, cell: self.cell, new_tick: self.new_tick, - arch: self.arch, + entities: self.entities, _marker: PhantomData, } } @@ -109,7 +109,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { slot, cell: self.cell, new_tick: self.new_tick, - arch: self.arch, + entities: self.entities, _marker: PhantomData, } } @@ -120,7 +120,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { /// See: [`MaybeMut`] pub struct MutGuard<'w, T> { slot: Slot, - arch: &'w Archetype, + entities: &'w [Entity], cell: &'w Cell, new_tick: u32, _marker: PhantomData, @@ -139,7 +139,7 @@ impl<'w, T: ComponentValue> MutGuard<'w, T> { pub fn write(&self) -> RefMut { // Type is guaranteed by constructor self.cell - .get_mut(&self.arch, self.slot, self.new_tick) + .get_mut(self.entities, self.slot, self.new_tick) .unwrap() } } diff --git a/src/filter/change.rs b/src/filter/change.rs index 75c76014..e1ea68db 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -172,7 +172,7 @@ impl<'q, 'w, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { let cur = match self .cursor - .find_slice(&self.data.changes().get(self.kind), slots) + .find_slice(self.data.changes().get(self.kind), slots) { Some(v) => v, None => return Slice::new(slots.end, slots.end), @@ -268,18 +268,18 @@ impl<'w> core::fmt::Debug for PreparedRemoveFilter<'w> { } impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { - unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item {} + unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} } impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { type Item = (); #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item {} + unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let cur = match self.cursor.find_slice(&self.changes, slots) { + let cur = match self.cursor.find_slice(self.changes, slots) { Some(v) => v, None => return Slice::new(slots.end, slots.end), }; @@ -293,11 +293,7 @@ impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { mod test { use pretty_assertions::assert_eq; - use crate::{ - archetype::{Cell, Change}, - filter::FilterIter, - name, - }; + use crate::{archetype::Change, filter::FilterIter}; use super::*; @@ -341,7 +337,7 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let mut filter = PreparedRemoveFilter { + let filter = PreparedRemoveFilter { changes: &changes[..], cursor: ChangeCursor::new(2), }; @@ -368,7 +364,7 @@ mod test { Change::new(Slice::new(100, 200), 4), ]; - let mut filter = PreparedRemoveFilter { + let filter = PreparedRemoveFilter { changes: &changes[..], cursor: ChangeCursor::new(2), }; diff --git a/src/relation.rs b/src/relation.rs index 84b9f39b..74f60770 100644 --- a/src/relation.rs +++ b/src/relation.rs @@ -207,7 +207,7 @@ where /// See: [crate::RelationIter] pub struct RelationIterMut<'a, T> { - arch: &'a Archetype, + entites: &'a [Entity], cells: Range<'a, ComponentKey, Cell>, slot: Slot, change_tick: u32, @@ -230,7 +230,7 @@ impl<'a, T: ComponentValue> RelationIterMut<'a, T> { slot, marker: PhantomData, change_tick, - arch, + entites: arch.entities(), } } } @@ -245,7 +245,7 @@ where let (&key, cell) = self.cells.next()?; Some(( key.object().unwrap(), - cell.get_mut::(self.arch, self.slot, self.change_tick) + cell.get_mut::(self.entites, self.slot, self.change_tick) .unwrap(), )) } From 71b06fe33538b499fb7da5895ffa982ed799d4ec Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 9 Jul 2023 21:51:35 +0200 Subject: [PATCH 21/52] wip: generalize set --- src/archetype/guard.rs | 8 +-- src/archetype/mod.rs | 33 +++++---- src/lib.rs | 2 +- src/world.rs | 65 +++++++++++++----- src/writer.rs | 148 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 37 deletions(-) create mode 100644 src/writer.rs diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 0787eb5e..408c6c04 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -116,7 +116,7 @@ pub struct RefMut<'a, T> { // From the refcell orig: *mut CellData, - entities: &'a [Entity], + id: Entity, slot: Slot, modified: bool, tick: u32, @@ -125,7 +125,7 @@ pub struct RefMut<'a, T> { impl<'a, T: ComponentValue> RefMut<'a, T> { pub(super) fn new( mut value: AtomicRefMut<'a, CellData>, - entities: &'a [Entity], + id: Entity, slot: Slot, tick: u32, ) -> Option { @@ -138,7 +138,7 @@ impl<'a, T: ComponentValue> RefMut<'a, T> { Some(Self { value, orig, - entities, + id, slot, modified: false, tick, @@ -176,7 +176,7 @@ impl<'a, T> Drop for RefMut<'a, T> { // SAFETY: `value` is not accessed beyond this point let orig = unsafe { &mut *self.orig }; - orig.set_modified(self.entities, Slice::single(self.slot), self.tick) + orig.set_modified(&[self.id], Slice::single(self.slot), self.tick) } } } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 53683f3a..1113e45f 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -93,10 +93,12 @@ pub(crate) struct CellData { } impl CellData { - pub fn set_modified(&mut self, entities: &[Entity], slice: Slice, change_tick: u32) { + /// Sets the specified entities and slots as modified and invokes subscribers + /// **Note**: `ids` must be the slice of entities pointed to by `slice` + pub(crate) fn set_modified(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { let component = self.key; self.on_event(EventData { - ids: &entities[slice.as_range()], + ids: &ids, key: component, kind: EventKind::Modified, }); @@ -105,10 +107,12 @@ impl CellData { .set_modified_if_tracking(Change::new(slice, change_tick)); } - pub fn set_added(&mut self, entities: &[Entity], slice: Slice, change_tick: u32) { + /// Sets the specified entities and slots as modified and invokes subscribers + /// **Note**: `ids` must be the slice of entities pointed to by `slice` + pub(crate) fn set_added(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { let component = self.key; self.on_event(EventData { - ids: &entities[slice.as_range()], + ids: &ids, key: component, kind: EventKind::Added, }); @@ -117,10 +121,12 @@ impl CellData { } /// **Note**: must be called *before* data is dropped - pub fn set_removed(&mut self, entities: &[Entity], slice: Slice, change_tick: u32) { + /// Sets the specified entities and slots as modified and invokes subscribers + /// **Note**: `ids` must be the slice of entities pointed to by `slice` + pub(crate) fn set_removed(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { let component = self.key; self.on_event(EventData { - ids: &entities[slice.as_range()], + ids: &ids, key: component, kind: EventKind::Added, }); @@ -501,7 +507,7 @@ impl Archetype { let value = unsafe { data.storage.at_mut(slot)? }; let value = (modify)(value); - data.set_modified(&self.entities, Slice::single(slot), change_tick); + data.set_modified(&self.entities[slot..slot], Slice::single(slot), change_tick); Some(value) } @@ -524,7 +530,8 @@ impl Archetype { let value = unsafe { &mut *(data.storage.at_mut(slot)? as *mut T) }; let value = (f)(value); - data.set_modified(&self.entities, Slice::single(slot), change_tick); + // TODO: fix deliberate bug + data.set_modified(&self.entities[slot..slot], Slice::single(slot), change_tick); Some(value) } @@ -618,9 +625,9 @@ impl Archetype { /// # Safety /// Must be called only **ONCE**. Returns Err(src) if move was unsuccessful /// The component must be Send + Sync - pub unsafe fn push(&mut self, component: ComponentKey, src: *mut u8, tick: u32) -> Option<()> { + pub unsafe fn push(&mut self, component: ComponentKey, src: *mut u8, tick: u32) { let len = self.len(); - let cell = self.cells.get_mut(&component)?; + let cell = self.cells.get_mut(&component).unwrap(); let data = cell.data.get_mut(); let slot = data.storage.len(); @@ -635,9 +642,7 @@ impl Archetype { self.entities.len() ); - data.set_added(&self.entities, Slice::single(slot), tick); - - Some(()) + data.set_added(&self.entities[slot..=slot], Slice::single(slot), tick); } /// Moves the components in `storage` to the not yet initialized space in a @@ -656,7 +661,7 @@ impl Archetype { data.storage.append(src); debug_assert!(data.storage.len() <= len); - data.set_added(&self.entities, slots, tick); + data.set_added(&self.entities[slots.as_range()], slots, tick); Some(()) } diff --git a/src/lib.rs b/src/lib.rs index 8ec09cfd..8963f4ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -243,7 +243,7 @@ pub mod serialize; mod util; /// vtable implementation for dynamic dispatching pub mod vtable; -mod set_traits; +mod writer; // Required due to macro pub use archetype::{ArchetypeId, BatchSpawn, RefMut}; diff --git a/src/world.rs b/src/world.rs index 98954154..b32161f7 100644 --- a/src/world.rs +++ b/src/world.rs @@ -29,6 +29,7 @@ use crate::{ is_static, metadata::exclusive, relation::Relation, + writer::{ComponentUpdater, ComponentWriter}, ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; @@ -203,10 +204,7 @@ impl World { let (loc, arch) = self.spawn_at_inner(id, arch_id)?; for (info, src) in buffer.drain() { - unsafe { - arch.push(info.key(), src, change_tick) - .expect("Component not in archetype") - } + unsafe { arch.push(info.key(), src, change_tick) } } Ok((id, loc)) @@ -227,9 +225,7 @@ impl World { for (info, src) in buffer.drain() { unsafe { - if arch.push(info.key, src, change_tick).is_none() { - info.drop(src); - } + arch.push(info.key, src, change_tick); } } @@ -394,7 +390,7 @@ impl World { // Insert the missing components for &(component, data) in &new_data { - dst.push(component.key, data, change_tick).unwrap(); + dst.push(component.key, data, change_tick); } assert_eq!(dst.entity(dst_slot), Some(id)); @@ -421,8 +417,7 @@ impl World { } /// Set metadata for a given component if they do not already exist - #[inline] - fn init_component(&mut self, info: ComponentInfo) { + pub(crate) fn init_component(&mut self, info: ComponentInfo) { assert!( info.key().id.kind().contains(EntityKind::COMPONENT), "Component is not a component kind id" @@ -665,12 +660,6 @@ impl World { // Initialize component self.init_component(info); - // Ensure exclusive property - // if info.key.object.is_some() && self.has(info.key.id, exclusive()) { - // strict_superset = false; - // components.retain(|v| v.key == info.key || v.key.id != info.key.id) - // } - // assert in order let (dst_id, _) = self.archetypes.find(components); @@ -691,8 +680,7 @@ impl World { // Insert the missing component unsafe { - dst.push(info.key, value, change_tick) - .expect("Insert should not fail"); + dst.push(info.key, value, change_tick); } debug_assert_eq!(dst.entity(dst_slot), Some(id)); @@ -715,6 +703,47 @@ impl World { Ok(loc) } + #[inline] + pub(crate) fn set_impl( + &mut self, + id: Entity, + info: ComponentInfo, + updater: U, + ) -> Result { + // We know things will change either way + let change_tick = self.advance_change_tick(); + + let src_loc = self.init_location(id)?; + + let src = self.archetypes.get_mut(src_loc.arch_id); + + if let Some(writer) = unsafe { updater.update(src, id, src_loc.slot, change_tick) } { + // Move to a new archetype + let (dst_loc, swapped) = + writer.migrate(self, src_loc.arch_id, src_loc.slot, change_tick); + + debug_assert_eq!( + self.archetypes.get(dst_loc.arch_id).entity(dst_loc.slot), + Some(id) + ); + + if let Some((swapped, slot)) = swapped { + // The last entity in src was moved into the slot occupied by id + let swapped_ns = self.entities.init(swapped.kind()); + swapped_ns.get_mut(swapped).expect("Invalid entity id").slot = slot; + } + self.archetypes.prune_arch(src_loc.arch_id); + + let ns = self.entities.init(id.kind()); + + *ns.get_mut(id).expect("Entity is not valid") = dst_loc; + + Ok(dst_loc) + } else { + Ok(src_loc) + } + } + /// TODO benchmark with fully generic function #[inline] pub(crate) fn set_inner( diff --git a/src/writer.rs b/src/writer.rs new file mode 100644 index 00000000..640835a8 --- /dev/null +++ b/src/writer.rs @@ -0,0 +1,148 @@ +use core::{iter::Copied, mem, ptr, slice}; + +use itertools::{Either, Itertools}; + +use crate::{ + archetype::{Archetype, CellData, Slice, Slot}, + archetypes::Archetypes, + entity::EntityLocation, + ArchetypeId, Component, ComponentInfo, ComponentKey, ComponentValue, Entity, World, +}; + +pub(crate) unsafe trait ComponentUpdater { + /// Used for filling in the missing types + type Writer: ComponentWriter; + + /// # Safety + /// `dst` is a valid pointer to targeted component + unsafe fn update( + self, + archetype: &mut Archetype, + id: Entity, + slot: Slot, + tick: u32, + ) -> Option; +} + +pub(crate) unsafe trait ComponentWriter { + fn migrate( + &self, + world: &mut World, + src_id: ArchetypeId, + src_slot: Slot, + tick: u32, + ) -> (EntityLocation, Option<(Entity, Slot)>); +} + +struct Replace { + component: Component, + value: T, +} + +unsafe impl ComponentUpdater for Replace { + type Writer = ReplaceWriter; + + unsafe fn update( + self, + arch: &mut Archetype, + id: Entity, + slot: Slot, + tick: u32, + ) -> Option { + let key = self.component.key(); + + if let Some(cell) = arch.cell_mut(key) { + let data = cell.data.get_mut(); + + let storage = data.storage.downcast_mut::(); + let old = mem::replace(&mut storage[slot], self.value); + + None + } else if let Some(&dst) = arch.outgoing.get(&key) { + eprintln!("Outgoing edge: {:?}", self.component); + + Some(ReplaceWriter { + dst: Either::Left(dst), + component: self.component, + value: self.value, + }) + } else { + // Oh no! The archetype is missing the component + // + // Generate a list of component infos which fully satisfy the requirements for the + // desired archetype to move to + let pivot = arch.components().take_while(|v| v.key < key).count(); + + // Split the components + // A B C [new] D E F + let left = arch.components().take(pivot); + let right = arch.components().skip(pivot); + + let components = left + .chain([self.component.info()]) + .chain(right) + .collect_vec(); + + Some(ReplaceWriter { + dst: Either::Right(components), + component: self.component, + value: self.value, + }) + } + } +} + +struct ReplaceWriter { + dst: Either>, + component: Component, + value: T, +} + +unsafe impl ComponentWriter for ReplaceWriter { + fn migrate( + &self, + world: &mut World, + src_id: ArchetypeId, + src_slot: Slot, + tick: u32, + ) -> (EntityLocation, Option<(Entity, Slot)>) { + let key = self.component.key(); + + let (src, dst, dst_id) = match &self.dst { + &Either::Left(dst_id) => { + let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + (src, dst, dst_id) + } + Either::Right(components) => { + // Initialize component + world.init_component(self.component.info()); + + let (dst_id, _) = world.archetypes.find(components.iter().copied()); + + // Add a quick edge to refer to later + let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + src.add_outgoing(key, dst_id); + dst.add_incoming(key, src_id); + (src, dst, dst_id) + } + }; + + let (dst_slot, swapped) = unsafe { src.move_to(dst, src_slot, |c, ptr| c.drop(ptr), tick) }; + + // Insert the missing component + unsafe { + let mut value = self.value; + dst.push(key, &mut self.value as *mut T as *mut u8, tick); + + mem::forget(self.value); + } + + ( + EntityLocation { + slot: dst_slot, + arch_id: dst_id, + }, + swapped, + ) + } +} From b4c35057384543db9239ba6bbe5ba10e1f23faac Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Mon, 10 Jul 2023 22:41:46 +0200 Subject: [PATCH 22/52] chore: cleanup --- src/archetype/guard.rs | 13 +++++++++---- src/archetype/mod.rs | 10 +++++++--- src/relation.rs | 6 +++--- src/world.rs | 2 +- src/writer.rs | 32 ++++++++++++++------------------ 5 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 408c6c04..9de6309e 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -116,7 +116,8 @@ pub struct RefMut<'a, T> { // From the refcell orig: *mut CellData, - id: Entity, + // All entities in the archetype + ids: &'a [Entity], slot: Slot, modified: bool, tick: u32, @@ -125,7 +126,7 @@ pub struct RefMut<'a, T> { impl<'a, T: ComponentValue> RefMut<'a, T> { pub(super) fn new( mut value: AtomicRefMut<'a, CellData>, - id: Entity, + ids: &'a [Entity], slot: Slot, tick: u32, ) -> Option { @@ -138,7 +139,7 @@ impl<'a, T: ComponentValue> RefMut<'a, T> { Some(Self { value, orig, - id, + ids, slot, modified: false, tick, @@ -176,7 +177,11 @@ impl<'a, T> Drop for RefMut<'a, T> { // SAFETY: `value` is not accessed beyond this point let orig = unsafe { &mut *self.orig }; - orig.set_modified(&[self.id], Slice::single(self.slot), self.tick) + orig.set_modified( + &self.ids[self.slot..=self.slot], + Slice::single(self.slot), + self.tick, + ) } } } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 1113e45f..5e659221 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -98,7 +98,7 @@ impl CellData { pub(crate) fn set_modified(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { let component = self.key; self.on_event(EventData { - ids: &ids, + ids, key: component, kind: EventKind::Modified, }); @@ -112,7 +112,7 @@ impl CellData { pub(crate) fn set_added(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { let component = self.key; self.on_event(EventData { - ids: &ids, + ids, key: component, kind: EventKind::Added, }); @@ -507,7 +507,11 @@ impl Archetype { let value = unsafe { data.storage.at_mut(slot)? }; let value = (modify)(value); - data.set_modified(&self.entities[slot..slot], Slice::single(slot), change_tick); + data.set_modified( + &self.entities[slot..=slot], + Slice::single(slot), + change_tick, + ); Some(value) } diff --git a/src/relation.rs b/src/relation.rs index 74f60770..7a2ef669 100644 --- a/src/relation.rs +++ b/src/relation.rs @@ -207,7 +207,7 @@ where /// See: [crate::RelationIter] pub struct RelationIterMut<'a, T> { - entites: &'a [Entity], + entities: &'a [Entity], cells: Range<'a, ComponentKey, Cell>, slot: Slot, change_tick: u32, @@ -230,7 +230,7 @@ impl<'a, T: ComponentValue> RelationIterMut<'a, T> { slot, marker: PhantomData, change_tick, - entites: arch.entities(), + entities: arch.entities(), } } } @@ -245,7 +245,7 @@ where let (&key, cell) = self.cells.next()?; Some(( key.object().unwrap(), - cell.get_mut::(self.entites, self.slot, self.change_tick) + cell.get_mut::(self.entities, self.slot, self.change_tick) .unwrap(), )) } diff --git a/src/world.rs b/src/world.rs index b32161f7..8370c9f7 100644 --- a/src/world.rs +++ b/src/world.rs @@ -717,7 +717,7 @@ impl World { let src = self.archetypes.get_mut(src_loc.arch_id); - if let Some(writer) = unsafe { updater.update(src, id, src_loc.slot, change_tick) } { + if let Some(writer) = updater.update(src, id, src_loc.slot, change_tick) { // Move to a new archetype let (dst_loc, swapped) = writer.migrate(self, src_loc.arch_id, src_loc.slot, change_tick); diff --git a/src/writer.rs b/src/writer.rs index 640835a8..4339186b 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,21 +1,18 @@ -use core::{iter::Copied, mem, ptr, slice}; +use core::mem; use itertools::{Either, Itertools}; use crate::{ - archetype::{Archetype, CellData, Slice, Slot}, - archetypes::Archetypes, + archetype::{Archetype, Slot}, entity::EntityLocation, - ArchetypeId, Component, ComponentInfo, ComponentKey, ComponentValue, Entity, World, + ArchetypeId, Component, ComponentInfo, ComponentValue, Entity, World, }; -pub(crate) unsafe trait ComponentUpdater { - /// Used for filling in the missing types +pub(crate) trait ComponentUpdater { + /// If returned, will be used to migrate the entity to a new archetype type Writer: ComponentWriter; - /// # Safety - /// `dst` is a valid pointer to targeted component - unsafe fn update( + fn update( self, archetype: &mut Archetype, id: Entity, @@ -24,9 +21,9 @@ pub(crate) unsafe trait ComponentUpdater { ) -> Option; } -pub(crate) unsafe trait ComponentWriter { +pub(crate) trait ComponentWriter { fn migrate( - &self, + self, world: &mut World, src_id: ArchetypeId, src_slot: Slot, @@ -39,10 +36,10 @@ struct Replace { value: T, } -unsafe impl ComponentUpdater for Replace { +impl ComponentUpdater for Replace { type Writer = ReplaceWriter; - unsafe fn update( + fn update( self, arch: &mut Archetype, id: Entity, @@ -98,9 +95,9 @@ struct ReplaceWriter { value: T, } -unsafe impl ComponentWriter for ReplaceWriter { +impl ComponentWriter for ReplaceWriter { fn migrate( - &self, + self, world: &mut World, src_id: ArchetypeId, src_slot: Slot, @@ -132,9 +129,8 @@ unsafe impl ComponentWriter for ReplaceWriter { // Insert the missing component unsafe { let mut value = self.value; - dst.push(key, &mut self.value as *mut T as *mut u8, tick); - - mem::forget(self.value); + dst.push(key, &mut value as *mut T as *mut u8, tick); + mem::forget(value); } ( From 07c3507f5606a38f38e6bcce75ba1c03b9419a89 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Mon, 10 Jul 2023 22:54:54 +0200 Subject: [PATCH 23/52] chore: make set use writer abstraction --- src/world.rs | 36 ++++++++++++------------------------ src/writer.rs | 17 +++++++++++------ 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/world.rs b/src/world.rs index 8370c9f7..3a94b711 100644 --- a/src/world.rs +++ b/src/world.rs @@ -29,7 +29,7 @@ use crate::{ is_static, metadata::exclusive, relation::Relation, - writer::{ComponentUpdater, ComponentWriter}, + writer::{self, ComponentUpdater, ComponentWriter}, ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; @@ -572,20 +572,9 @@ impl World { &mut self, id: Entity, component: Component, - mut value: T, + value: T, ) -> Result> { - let mut old: Option = None; - - self.set_dyn( - id, - component.info(), - &mut value as *mut T as *mut u8, - |ptr| unsafe { old = Some(ptr.cast::().read()) }, - )?; - - mem::forget(value); - - Ok(old) + self.set_inner(id, component, value).map(|v| v.0) } /// Updates a component in place @@ -707,7 +696,6 @@ impl World { pub(crate) fn set_impl( &mut self, id: Entity, - info: ComponentInfo, updater: U, ) -> Result { // We know things will change either way @@ -750,20 +738,20 @@ impl World { &mut self, id: Entity, component: Component, - mut value: T, + value: T, ) -> Result<(Option, EntityLocation)> { - let mut old: Option = None; + let mut output = None; - let loc = self.set_dyn( + let loc = self.set_impl( id, - component.info(), - &mut value as *mut T as *mut u8, - |ptr| unsafe { old = Some(ptr.cast::().read()) }, + writer::Replace { + component, + value, + output: &mut output, + }, )?; - mem::forget(value); - - Ok((old, loc)) + Ok((output, loc)) } #[inline] diff --git a/src/writer.rs b/src/writer.rs index 4339186b..c0f52b1b 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -3,7 +3,7 @@ use core::mem; use itertools::{Either, Itertools}; use crate::{ - archetype::{Archetype, Slot}, + archetype::{Archetype, Slice, Slot}, entity::EntityLocation, ArchetypeId, Component, ComponentInfo, ComponentValue, Entity, World, }; @@ -31,12 +31,13 @@ pub(crate) trait ComponentWriter { ) -> (EntityLocation, Option<(Entity, Slot)>); } -struct Replace { - component: Component, - value: T, +pub(crate) struct Replace<'a, T: ComponentValue> { + pub(crate) component: Component, + pub(crate) value: T, + pub(crate) output: &'a mut Option, } -impl ComponentUpdater for Replace { +impl<'a, T: ComponentValue> ComponentUpdater for Replace<'a, T> { type Writer = ReplaceWriter; fn update( @@ -54,6 +55,10 @@ impl ComponentUpdater for Replace { let storage = data.storage.downcast_mut::(); let old = mem::replace(&mut storage[slot], self.value); + data.set_modified(&[id], Slice::single(slot), tick); + + *self.output = Some(old); + None } else if let Some(&dst) = arch.outgoing.get(&key) { eprintln!("Outgoing edge: {:?}", self.component); @@ -89,7 +94,7 @@ impl ComponentUpdater for Replace { } } -struct ReplaceWriter { +pub(crate) struct ReplaceWriter { dst: Either>, component: Component, value: T, From bc20d1e5e9634b35dc075f3731ce8da3386d95ed Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Mon, 10 Jul 2023 23:38:23 +0200 Subject: [PATCH 24/52] feat: buffer component writer --- src/archetype/mod.rs | 3 +- src/buffer.rs | 13 +++++ src/world.rs | 2 +- src/writer.rs | 122 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 133 insertions(+), 7 deletions(-) diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 5e659221..3f09cb6c 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -126,7 +126,7 @@ impl CellData { pub(crate) fn set_removed(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { let component = self.key; self.on_event(EventData { - ids: &ids, + ids, key: component, kind: EventKind::Added, }); @@ -624,7 +624,6 @@ impl Archetype { } /// Push a type erased component into the new slot - /// `src` shall be considered moved if Some is returned. /// `component` must match the type of data. /// # Safety /// Must be called only **ONCE**. Returns Err(src) if move was unsuccessful diff --git a/src/buffer.rs b/src/buffer.rs index 38f81177..07dd52da 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -340,6 +340,19 @@ impl ComponentBuffer { pub fn is_empty(&self) -> bool { self.entries.is_empty() } + + /// Retains only the components specified by the predicate + /// If the closure returns true the element is removed and **not** dropped at the end of + /// collection + /// # Safety + /// If the passed closure returns *false* the element is considered moved and shall be handled by + /// the caller. + pub(crate) unsafe fn retain(&mut self, mut f: impl FnMut(ComponentInfo, *mut ()) -> bool) { + self.entries.retain(|_, (info, offset)| { + let ptr = unsafe { self.storage.at_mut(*offset) }; + f(*info, ptr as *mut ()) + }) + } } pub(crate) struct ComponentBufferIter<'a> { diff --git a/src/world.rs b/src/world.rs index 3a94b711..5d76fa8a 100644 --- a/src/world.rs +++ b/src/world.rs @@ -29,7 +29,7 @@ use crate::{ is_static, metadata::exclusive, relation::Relation, - writer::{self, ComponentUpdater, ComponentWriter}, + writer::{self, ComponentUpdater, MigrateEntity}, ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; diff --git a/src/writer.rs b/src/writer.rs index c0f52b1b..9ced4228 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,16 +1,18 @@ -use core::mem; +use core::{mem, ptr}; use itertools::{Either, Itertools}; use crate::{ archetype::{Archetype, Slice, Slot}, + buffer::ComponentBuffer, entity::EntityLocation, + metadata::exclusive, ArchetypeId, Component, ComponentInfo, ComponentValue, Entity, World, }; pub(crate) trait ComponentUpdater { /// If returned, will be used to migrate the entity to a new archetype - type Writer: ComponentWriter; + type Writer: MigrateEntity; fn update( self, @@ -21,7 +23,9 @@ pub(crate) trait ComponentUpdater { ) -> Option; } -pub(crate) trait ComponentWriter { +/// # Safety +/// *All* components of the new slot must be initialized +pub(crate) unsafe trait MigrateEntity { fn migrate( self, world: &mut World, @@ -100,7 +104,7 @@ pub(crate) struct ReplaceWriter { value: T, } -impl ComponentWriter for ReplaceWriter { +unsafe impl MigrateEntity for ReplaceWriter { fn migrate( self, world: &mut World, @@ -147,3 +151,113 @@ impl ComponentWriter for ReplaceWriter { ) } } + +pub(crate) struct Buffered<'a> { + pub(crate) buffer: &'a mut ComponentBuffer, +} + +impl<'a> ComponentUpdater for Buffered<'a> { + type Writer = BufferedMigrate<'a>; + + fn update( + self, + arch: &mut Archetype, + id: Entity, + slot: Slot, + tick: u32, + ) -> Option { + let mut exclusive_relations = Vec::new(); + unsafe { + self.buffer.retain(|info, src| { + let key = info.key; + if let Some(cell) = arch.cell_mut(key) { + let data = cell.data.get_mut(); + + let dst = data.storage.at_mut(slot).unwrap(); + info.drop(dst); + ptr::copy_nonoverlapping(dst as *mut (), src, info.size()); + + data.set_modified(&[id], Slice::single(slot), tick); + false + } else { + // Component does not exist yet, so defer a move + + // Exclusive relation + if key.object.is_some() + && info.meta_ref().has(exclusive()) + && !exclusive_relations.contains(&key.id) + { + exclusive_relations.push(key.id); + } + + true + } + }); + } + + if self.buffer.is_empty() { + eprintln!("Archetype fully matched"); + None + } else { + // Add the existing components, making sure new exclusive relations are favored + let components = self + .buffer + .components() + .copied() + .chain( + arch.components() + .filter(|v| !exclusive_relations.contains(&v.key.id)), + ) + .sorted_unstable() + .collect_vec(); + + Some(BufferedMigrate { + components, + buffer: self.buffer, + }) + } + } +} + +pub(crate) struct BufferedMigrate<'a> { + components: Vec, + buffer: &'a mut ComponentBuffer, +} + +unsafe impl<'a> MigrateEntity for BufferedMigrate<'a> { + fn migrate( + self, + world: &mut World, + src_id: ArchetypeId, + src_slot: Slot, + tick: u32, + ) -> (EntityLocation, Option<(Entity, Slot)>) { + for &info in self.buffer.components() { + eprintln!("Initializing component {:?}", info); + world.init_component(info); + } + + let (dst_id, _) = world.archetypes.find(self.components.iter().copied()); + + let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + let (dst_slot, swapped) = unsafe { src.move_to(dst, src_slot, |c, ptr| c.drop(ptr), tick) }; + + // Insert the missing components + for (info, src) in self.buffer.drain() { + unsafe { + // src moves into herer + dst.push(info.key, src, tick); + } + } + + eprintln!("Buffer retained {} items", self.buffer.len()); + + ( + EntityLocation { + slot: dst_slot, + arch_id: dst_id, + }, + swapped, + ) + } +} From a3a0579a2bb2c3d7bd662e96ebca15a1eb1e7992 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Thu, 13 Jul 2023 00:20:50 +0200 Subject: [PATCH 25/52] feat: CellMutGuard and CellGuard mapping --- recipes.json | 3 + src/archetype/guard.rs | 145 ++++++++++++++++++++++--------------- src/archetype/mod.rs | 14 ++-- src/fetch/component.rs | 2 +- src/fetch/component_mut.rs | 2 +- src/fetch/relations.rs | 6 +- src/filter/change.rs | 2 +- 7 files changed, 103 insertions(+), 71 deletions(-) diff --git a/recipes.json b/recipes.json index e2dcfda9..9cb105dd 100644 --- a/recipes.json +++ b/recipes.json @@ -32,6 +32,9 @@ "cmd": "cargo nextest run --all-features", "kind": "term" }, + "test-miri": { + "cmd": "cargo miri nextest run --no-default-features --features std,serde,flume,derive" + }, "doc": { "cmd": "cargo doc --all-features --open" }, diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 9de6309e..0adb2309 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -14,97 +14,134 @@ use crate::{ use super::{CellData, Change, Changes, Slice, Slot}; /// Type safe abstraction over a borrowed cell data -pub(crate) struct CellMutGuard<'a, T> { - value: AtomicRefMut<'a, [T]>, +pub(crate) struct CellMutGuard<'a, T: ?Sized> { + data: AtomicRefMut<'a, CellData>, // From the refcell - orig: NonNull, + storage: NonNull, } -unsafe impl<'a, T> Send for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Send {} -unsafe impl<'a, T> Sync for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Sync {} +unsafe impl<'a, T: ComponentValue> Send for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Send {} +unsafe impl<'a, T: ComponentValue> Sync for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Sync {} -impl<'a, T: ComponentValue> CellMutGuard<'a, T> { +impl<'a, T: ComponentValue + Sized> CellMutGuard<'a, [T]> { pub(super) fn new(mut value: AtomicRefMut<'a, CellData>) -> Self { - // Store the original pointer. This will be used when dropped - let orig = NonNull::from(&mut *value); - - let value = AtomicRefMut::map(value, |v| v.storage.downcast_mut::()); + let storage: NonNull<[T]> = NonNull::from(value.storage.downcast_mut::()); - Self { value, orig } + Self { + data: value, + storage, + } } +} +impl<'a, T: ?Sized> CellMutGuard<'a, T> { pub(crate) fn set_modified(&mut self, entities: &[Entity], slots: Slice, tick: u32) { // SAFETY: `value` is not accessed in this function - let orig = unsafe { self.orig.as_mut() }; - - orig.on_event(EventData { + let data = &mut *self.data; + data.on_event(EventData { ids: &entities[slots.as_range()], - key: orig.key, + key: data.key, kind: EventKind::Modified, }); - orig.changes + data.changes .set_modified_if_tracking(Change::new(slots, tick)); } pub(crate) fn changes_mut(&mut self) -> &mut Changes { // SAFETY: `value` is not accessed in this function - let orig = unsafe { self.orig.as_mut() }; - &mut orig.changes + &mut self.data.changes + } + + pub(crate) fn filter_map( + mut self, + f: impl FnOnce(&mut T) -> Option<&mut U>, + ) -> Option> { + let storage = NonNull::from(f(unsafe { self.storage.as_mut() })?); + + Some(CellMutGuard { + data: self.data, + storage, + }) } } -impl<'w, T> Deref for CellMutGuard<'w, T> { - type Target = [T]; +impl<'w, T: ?Sized> Deref for CellMutGuard<'w, T> { + type Target = T; fn deref(&self) -> &Self::Target { - &self.value + unsafe { self.storage.as_ref() } } } -impl<'w, T> DerefMut for CellMutGuard<'w, T> { +impl<'w, T: ?Sized> DerefMut for CellMutGuard<'w, T> { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.value + unsafe { self.storage.as_mut() } } } -/// Type safe abstraction over a borrowed cell data -pub(crate) struct CellGuard<'a, T> { - value: AtomicRef<'a, [T]>, - orig: NonNull, +impl<'a, T: Debug + ?Sized> Debug for CellMutGuard<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + (*self).fmt(f) + } } -unsafe impl<'a, T> Send for CellGuard<'a, T> where AtomicRef<'a, T>: Send {} -unsafe impl<'a, T> Sync for CellGuard<'a, T> where AtomicRef<'a, T>: Sync {} +/// Type safe abstraction over a borrowed cell data +pub(crate) struct CellGuard<'a, T: ?Sized> { + data: AtomicRef<'a, CellData>, + storage: NonNull, +} -impl<'a, T: ComponentValue> CellGuard<'a, T> { - pub(super) fn new(value: AtomicRef<'a, CellData>) -> Self { - // Store the original pointer. This will be used when dropped - let orig = NonNull::from(&*value); +unsafe impl<'a, T: ComponentValue> Send for CellGuard<'a, T> where AtomicRef<'a, T>: Send {} +unsafe impl<'a, T: ComponentValue> Sync for CellGuard<'a, T> where AtomicRef<'a, T>: Sync {} - let value = AtomicRef::map(value, |v| v.storage.downcast_ref::()); +impl<'a, T: ComponentValue + Sized> CellGuard<'a, [T]> { + pub(super) fn new(mut value: AtomicRef<'a, CellData>) -> Self { + let storage: NonNull<[T]> = NonNull::from(value.storage.downcast_ref::()); - Self { value, orig } + Self { + data: value, + storage, + } } +} +impl<'a, T: ?Sized> CellGuard<'a, T> { #[inline] - pub fn into_inner(self) -> AtomicRef<'a, [T]> { - self.value + pub fn into_slice_ref(self) -> AtomicRef<'a, T> { + AtomicRef::map(self.data, |_| unsafe { self.storage.as_ref() }) + } + + pub(crate) fn filter_map( + mut self, + f: impl FnOnce(&T) -> Option<&U>, + ) -> Option> { + let storage = NonNull::from(f(unsafe { self.storage.as_ref() })?); + + Some(CellGuard { + data: self.data, + storage, + }) } #[inline] pub(crate) fn changes(&self) -> &Changes { - // SAFETY: `value` is not accessed in this function - unsafe { &self.orig.as_ref().changes } + &self.data.changes } } -impl<'w, T> Deref for CellGuard<'w, T> { - type Target = [T]; +impl<'a, T: Debug + ?Sized> Debug for CellGuard<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + (*self).fmt(f) + } +} + +impl<'w, T: ?Sized> Deref for CellGuard<'w, T> { + type Target = T; fn deref(&self) -> &Self::Target { - &self.value + unsafe { self.storage.as_ref() } } } @@ -112,9 +149,7 @@ impl<'w, T> Deref for CellGuard<'w, T> { /// /// A modification invent is only generated *if* if this is mutably dereferenced. pub struct RefMut<'a, T> { - value: AtomicRefMut<'a, T>, - // From the refcell - orig: *mut CellData, + guard: CellMutGuard<'a, T>, // All entities in the archetype ids: &'a [Entity], @@ -125,20 +160,16 @@ pub struct RefMut<'a, T> { impl<'a, T: ComponentValue> RefMut<'a, T> { pub(super) fn new( - mut value: AtomicRefMut<'a, CellData>, + guard: CellMutGuard<'a, [T]>, ids: &'a [Entity], slot: Slot, tick: u32, ) -> Option { // Store the original pointer. This will be used when dropped - let orig = &mut *value as *mut CellData; - - let value = - AtomicRefMut::filter_map(value, |v| v.storage.downcast_mut::().get_mut(slot))?; + let guard = guard.filter_map(|v| v.get_mut(slot))?; Some(Self { - value, - orig, + guard, ids, slot, modified: false, @@ -149,7 +180,7 @@ impl<'a, T: ComponentValue> RefMut<'a, T> { impl<'a, T: Debug> Debug for RefMut<'a, T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - self.value.fmt(f) + self.guard.fmt(f) } } @@ -158,7 +189,7 @@ impl<'a, T> Deref for RefMut<'a, T> { #[inline] fn deref(&self) -> &Self::Target { - &self.value + &*self.guard } } @@ -166,7 +197,7 @@ impl<'a, T> DerefMut for RefMut<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.modified = true; - &mut self.value + &mut *self.guard } } @@ -175,9 +206,7 @@ impl<'a, T> Drop for RefMut<'a, T> { fn drop(&mut self) { if self.modified { // SAFETY: `value` is not accessed beyond this point - let orig = unsafe { &mut *self.orig }; - - orig.set_modified( + self.guard.data.set_modified( &self.ids[self.slot..=self.slot], Slice::single(self.slot), self.tick, diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 3f09cb6c..2ae03ea7 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -253,22 +253,22 @@ impl Cell { } #[inline] - pub fn borrow(&self) -> CellGuard { + pub fn borrow(&self) -> CellGuard<[T]> { CellGuard::new(self.data.borrow()) } #[inline] - pub fn borrow_mut(&self) -> CellMutGuard { + pub fn borrow_mut(&self) -> CellMutGuard<[T]> { CellMutGuard::new(self.data.borrow_mut()) } #[inline] - pub fn try_borrow(&self) -> Result, BorrowError> { + pub fn try_borrow(&self) -> Result, BorrowError> { Ok(CellGuard::new(self.data.try_borrow()?)) } #[inline] - pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { + pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { Ok(CellMutGuard::new(self.data.try_borrow_mut()?)) } @@ -279,7 +279,7 @@ impl Cell { slot: Slot, tick: u32, ) -> Option> { - RefMut::new(self.data.borrow_mut(), entities, slot, tick) + RefMut::new(self.borrow_mut(), entities, slot, tick) } #[inline] @@ -403,7 +403,7 @@ impl Archetype { pub(crate) fn borrow( &self, component: ComponentKey, - ) -> Option> { + ) -> Option> { Some(self.cell(component)?.borrow()) } @@ -417,7 +417,7 @@ impl Archetype { pub(crate) fn borrow_mut( &self, component: ComponentKey, - ) -> Option> { + ) -> Option> { let cell = self.cell(component)?; let data = cell.borrow_mut(); Some(data) diff --git a/src/fetch/component.rs b/src/fetch/component.rs index a3eb93d3..56435498 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -37,7 +37,7 @@ where fn prepare(&self, data: FetchPrepareData<'w>) -> Option { let borrow = data.arch.borrow(self.key())?; Some(ReadComponent { - borrow: borrow.into_inner(), + borrow: borrow.into_slice_ref(), }) } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 9d69ca96..2673a755 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -77,7 +77,7 @@ impl<'q, T: ComponentValue> FetchItem<'q> for Mutable { #[doc(hidden)] pub struct WriteComponent<'a, T> { - guard: CellMutGuard<'a, T>, + guard: CellMutGuard<'a, [T]>, arch: &'a Archetype, tick: u32, } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index e6f77947..15861cba 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -30,7 +30,7 @@ where type Prepared = PreparedRelations<'w, T>; fn prepare(&self, data: FetchPrepareData<'w>) -> Option { - let borrows: SmallVec<[(Entity, CellGuard); 4]> = { + let borrows: SmallVec<[_; 4]> = { data.arch .relations_like(self.component.id()) .map(|(info, cell)| (info.object.unwrap(), cell.borrow())) @@ -72,7 +72,7 @@ impl<'q, T: ComponentValue> FetchItem<'q> for Relations { #[doc(hidden)] pub struct PreparedRelations<'a, T> { - borrows: SmallVec<[(Entity, CellGuard<'a, T>); 4]>, + borrows: SmallVec<[(Entity, CellGuard<'a, [T]>); 4]>, } impl<'q, 'w, T> PreparedFetch<'q> for PreparedRelations<'w, T> @@ -91,7 +91,7 @@ where /// Iterates the relation object and data for the yielded query item pub struct RelationsIter<'a, T> { - borrows: slice::Iter<'a, (Entity, CellGuard<'a, T>)>, + borrows: slice::Iter<'a, (Entity, CellGuard<'a, [T]>)>, slot: Slot, } diff --git a/src/filter/change.rs b/src/filter/change.rs index e1ea68db..0fcbceaf 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -148,7 +148,7 @@ impl ChangeCursor { #[doc(hidden)] pub struct PreparedChangeFilter<'w, T> { - data: CellGuard<'w, T>, + data: CellGuard<'w, [T]>, kind: ChangeKind, cursor: ChangeCursor, } From 44685fb2c8816f8774b004bb84922c3eeee44ae8 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Thu, 13 Jul 2023 23:48:03 +0200 Subject: [PATCH 26/52] chore: make set_with use new ComponentWriter --- src/archetype/guard.rs | 20 +++---- src/buffer.rs | 4 +- src/world.rs | 121 ++--------------------------------------- src/writer.rs | 35 ++++++++---- 4 files changed, 40 insertions(+), 140 deletions(-) diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 0adb2309..d04b4c6e 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -20,8 +20,8 @@ pub(crate) struct CellMutGuard<'a, T: ?Sized> { storage: NonNull, } -unsafe impl<'a, T: ComponentValue> Send for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Send {} -unsafe impl<'a, T: ComponentValue> Sync for CellMutGuard<'a, T> where AtomicRefMut<'a, T>: Sync {} +unsafe impl<'a, T: 'a + ?Sized> Send for CellMutGuard<'a, T> where for<'x> &'x mut T: Send {} +unsafe impl<'a, T: 'a + ?Sized> Sync for CellMutGuard<'a, T> where for<'x> &'x mut T: Sync {} impl<'a, T: ComponentValue + Sized> CellMutGuard<'a, [T]> { pub(super) fn new(mut value: AtomicRefMut<'a, CellData>) -> Self { @@ -83,7 +83,7 @@ impl<'w, T: ?Sized> DerefMut for CellMutGuard<'w, T> { impl<'a, T: Debug + ?Sized> Debug for CellMutGuard<'a, T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - (*self).fmt(f) + (**self).fmt(f) } } @@ -93,11 +93,11 @@ pub(crate) struct CellGuard<'a, T: ?Sized> { storage: NonNull, } -unsafe impl<'a, T: ComponentValue> Send for CellGuard<'a, T> where AtomicRef<'a, T>: Send {} -unsafe impl<'a, T: ComponentValue> Sync for CellGuard<'a, T> where AtomicRef<'a, T>: Sync {} +unsafe impl<'a, T: 'a + ?Sized> Send for CellGuard<'a, T> where for<'x> &'x T: Send {} +unsafe impl<'a, T: 'a + ?Sized> Sync for CellGuard<'a, T> where for<'x> &'x T: Sync {} impl<'a, T: ComponentValue + Sized> CellGuard<'a, [T]> { - pub(super) fn new(mut value: AtomicRef<'a, CellData>) -> Self { + pub(super) fn new(value: AtomicRef<'a, CellData>) -> Self { let storage: NonNull<[T]> = NonNull::from(value.storage.downcast_ref::()); Self { @@ -114,7 +114,7 @@ impl<'a, T: ?Sized> CellGuard<'a, T> { } pub(crate) fn filter_map( - mut self, + self, f: impl FnOnce(&T) -> Option<&U>, ) -> Option> { let storage = NonNull::from(f(unsafe { self.storage.as_ref() })?); @@ -133,7 +133,7 @@ impl<'a, T: ?Sized> CellGuard<'a, T> { impl<'a, T: Debug + ?Sized> Debug for CellGuard<'a, T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - (*self).fmt(f) + (**self).fmt(f) } } @@ -189,7 +189,7 @@ impl<'a, T> Deref for RefMut<'a, T> { #[inline] fn deref(&self) -> &Self::Target { - &*self.guard + &self.guard } } @@ -197,7 +197,7 @@ impl<'a, T> DerefMut for RefMut<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.modified = true; - &mut *self.guard + &mut self.guard } } diff --git a/src/buffer.rs b/src/buffer.rs index 07dd52da..16c33bcc 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -347,10 +347,10 @@ impl ComponentBuffer { /// # Safety /// If the passed closure returns *false* the element is considered moved and shall be handled by /// the caller. - pub(crate) unsafe fn retain(&mut self, mut f: impl FnMut(ComponentInfo, *mut ()) -> bool) { + pub(crate) unsafe fn retain(&mut self, mut f: impl FnMut(ComponentInfo, *mut u8) -> bool) { self.entries.retain(|_, (info, offset)| { let ptr = unsafe { self.storage.at_mut(*offset) }; - f(*info, ptr as *mut ()) + f(*info, ptr) }) } } diff --git a/src/world.rs b/src/world.rs index 5d76fa8a..60f20a06 100644 --- a/src/world.rs +++ b/src/world.rs @@ -27,9 +27,8 @@ use crate::{ filter::{ArchetypeFilter, StaticFilter}, format::{EntitiesFormatter, HierarchyFormatter, WorldFormatter}, is_static, - metadata::exclusive, relation::Relation, - writer::{self, ComponentUpdater, MigrateEntity}, + writer::{self, ComponentWriter, MigrateEntity}, ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; @@ -303,115 +302,7 @@ impl World { /// Add the components stored in a component buffer to an entity pub fn set_with(&mut self, id: Entity, buffer: &mut ComponentBuffer) -> Result<()> { - let id: Entity = id; - let change_tick = self.advance_change_tick(); - - for &info in buffer.components() { - self.init_component(info); - } - - let EntityLocation { - arch_id: arch, - slot, - } = self.init_location(id)?; - - let mut new_data = Vec::new(); - let mut new_components = Vec::new(); - - let src_id = arch; - - let mut exclusive_relations = Vec::new(); - - for (info, ptr) in buffer.drain() { - let src = self.archetypes.get_mut(arch); - - if let Some(()) = src.mutate_in_place(slot, info.key, change_tick, |old| { - // Drop old and copy the new value in - unsafe { - info.drop(old); - ptr::copy_nonoverlapping(ptr, old, info.size()); - } - }) { - } else { - // Component does not exist yet, so defer a move - - // Data will have a lifetime of `components`. - - let key = info.key; - - // Exclusive relation - if key.object.is_some() && self.has(key.id, exclusive()) { - if exclusive_relations.contains(&key.id) { - // Drop immediately - unsafe { info.drop(ptr) } - continue; - } - - exclusive_relations.push(key.id); - } - - new_components.push(info); - new_data.push((info, ptr)); - } - } - - if !new_data.is_empty() { - debug_assert_eq!(new_data.len(), new_components.len()); - let src = self.archetypes.get_mut(arch); - new_components.reserve(src.cells().len()); - - // Add the existing components, making sure new exclusive relations are favored - new_components.extend( - src.components() - .filter(|v| !exclusive_relations.contains(&v.key.id)), - ); - - new_components.sort_unstable(); - - // Make sure everything is in its order - { - let v = new_components.iter().sorted().cloned().collect_vec(); - assert_eq!( - new_components, v, - "set_with not in order new={new_components:#?} sorted={v:#?}" - ); - } - - let components = new_components; - - let (dst_id, _) = self.archetypes.find(components); - - // Borrow disjoint - let (src, dst) = self.archetypes.get_disjoint(src_id, dst_id).unwrap(); - - // dst.push is called immediately - unsafe { - let (dst_slot, swapped) = src.move_to(dst, slot, |c, ptr| c.drop(ptr), change_tick); - - // Insert the missing components - for &(component, data) in &new_data { - dst.push(component.key, data, change_tick); - } - - assert_eq!(dst.entity(dst_slot), Some(id)); - - if let Some((swapped, slot)) = swapped { - // The last entity in src was moved into the slot occupied by id - self.entities - .init(swapped.kind()) - .get_mut(swapped) - .unwrap() - .slot = slot; - } - - self.archetypes.prune_arch(src_id); - - *self.location_mut(id).expect("Entity is not valid") = EntityLocation { - slot: dst_slot, - arch_id: dst_id, - }; - } - } + self.set_impl(id, writer::Buffered::new(buffer))?; Ok(()) } @@ -693,11 +584,7 @@ impl World { } #[inline] - pub(crate) fn set_impl( - &mut self, - id: Entity, - updater: U, - ) -> Result { + fn set_impl(&mut self, id: Entity, updater: U) -> Result { // We know things will change either way let change_tick = self.advance_change_tick(); @@ -705,7 +592,7 @@ impl World { let src = self.archetypes.get_mut(src_loc.arch_id); - if let Some(writer) = updater.update(src, id, src_loc.slot, change_tick) { + if let Some(writer) = updater.write(src, id, src_loc.slot, change_tick) { // Move to a new archetype let (dst_loc, swapped) = writer.migrate(self, src_loc.arch_id, src_loc.slot, change_tick); diff --git a/src/writer.rs b/src/writer.rs index 9ced4228..4862e723 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -10,11 +10,15 @@ use crate::{ ArchetypeId, Component, ComponentInfo, ComponentValue, Entity, World, }; -pub(crate) trait ComponentUpdater { +/// Describes a modification to the components of an entity within the context of an archetype +pub(crate) trait ComponentWriter { /// If returned, will be used to migrate the entity to a new archetype type Writer: MigrateEntity; - fn update( + /// Performs write operations against the target entity and archetype. + /// + /// A migration to another archetype may be induced by returning an entity migrator + fn write( self, archetype: &mut Archetype, id: Entity, @@ -41,10 +45,10 @@ pub(crate) struct Replace<'a, T: ComponentValue> { pub(crate) output: &'a mut Option, } -impl<'a, T: ComponentValue> ComponentUpdater for Replace<'a, T> { +impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { type Writer = ReplaceWriter; - fn update( + fn write( self, arch: &mut Archetype, id: Entity, @@ -156,10 +160,16 @@ pub(crate) struct Buffered<'a> { pub(crate) buffer: &'a mut ComponentBuffer, } -impl<'a> ComponentUpdater for Buffered<'a> { +impl<'a> Buffered<'a> { + pub(crate) fn new(buffer: &'a mut ComponentBuffer) -> Self { + Self { buffer } + } +} + +impl<'a> ComponentWriter for Buffered<'a> { type Writer = BufferedMigrate<'a>; - fn update( + fn write( self, arch: &mut Archetype, id: Entity, @@ -170,12 +180,14 @@ impl<'a> ComponentUpdater for Buffered<'a> { unsafe { self.buffer.retain(|info, src| { let key = info.key; + // The component exists in the current archetype + // This implies that is it also satisfies any exclusive properties if let Some(cell) = arch.cell_mut(key) { let data = cell.data.get_mut(); let dst = data.storage.at_mut(slot).unwrap(); info.drop(dst); - ptr::copy_nonoverlapping(dst as *mut (), src, info.size()); + ptr::copy_nonoverlapping(src, dst, info.size()); data.set_modified(&[id], Slice::single(slot), tick); false @@ -183,10 +195,11 @@ impl<'a> ComponentUpdater for Buffered<'a> { // Component does not exist yet, so defer a move // Exclusive relation - if key.object.is_some() - && info.meta_ref().has(exclusive()) - && !exclusive_relations.contains(&key.id) - { + if key.object.is_some() && info.meta_ref().has(exclusive()) { + if exclusive_relations.contains(&key.id) { + panic!("Multiple exclusive relations"); + } + exclusive_relations.push(key.id); } From 60bcd1518e6c5e13d1e38e1c5032798e33a57b86 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 16 Jul 2023 21:39:01 +0200 Subject: [PATCH 27/52] test: entity builder relations --- tests/entity_builder.rs | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/entity_builder.rs diff --git a/tests/entity_builder.rs b/tests/entity_builder.rs new file mode 100644 index 00000000..1d72891e --- /dev/null +++ b/tests/entity_builder.rs @@ -0,0 +1,51 @@ +extern crate alloc; +use alloc::string::String; +use flax::{component, Entity, Error, Exclusive, World}; +use std::sync::Arc; + +component! { + a: f32, + b: String, + + relation(id): Arc<()> => [ Exclusive ], +} +#[test] +fn entity_builder() { + let mut world = World::new(); + + let id1 = Entity::builder() + .set(a(), 1.0) + .set(b(), "hello".into()) + .spawn(&mut world); + + let mut id2 = Entity::builder(); + id2.set(a(), 2.0).set(b(), "hello".into()); + id2.remove(b()); + + let id2 = id2.spawn(&mut world); + + assert_eq!(world.get(id2, a()).as_deref(), Ok(&2.0)); + assert_eq!( + world.get(id2, b()).as_deref(), + Err(&Error::MissingComponent(id2, b().info())) + ); + + let value = Arc::new(()); + + let mut id3 = Entity::builder(); + id3.set(a(), 2.0); + id3.set(b(), "world".into()); + id3.set(relation(id1), value.clone()); + + assert_eq!(Arc::strong_count(&value), 2); + + id3.set(relation(id1), value.clone()); + + assert_eq!(Arc::strong_count(&value), 2); + + let id3 = id3.spawn(&mut world); + assert_eq!(Arc::strong_count(&value), 2); + + world.despawn(id3).unwrap(); + assert_eq!(Arc::strong_count(&value), 1); +} From ce7cdece6480adf8b028639e7b85a1625402083e Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 16 Jul 2023 21:45:36 +0200 Subject: [PATCH 28/52] test: replace existing relation on entity using builder --- tests/entity_builder.rs | 51 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/tests/entity_builder.rs b/tests/entity_builder.rs index 1d72891e..d783f3ec 100644 --- a/tests/entity_builder.rs +++ b/tests/entity_builder.rs @@ -4,27 +4,28 @@ use flax::{component, Entity, Error, Exclusive, World}; use std::sync::Arc; component! { - a: f32, + a: i32, b: String, relation(id): Arc<()> => [ Exclusive ], } + #[test] fn entity_builder() { let mut world = World::new(); let id1 = Entity::builder() - .set(a(), 1.0) + .set(a(), 1) .set(b(), "hello".into()) .spawn(&mut world); let mut id2 = Entity::builder(); - id2.set(a(), 2.0).set(b(), "hello".into()); + id2.set(a(), 2).set(b(), "hello".into()); id2.remove(b()); let id2 = id2.spawn(&mut world); - assert_eq!(world.get(id2, a()).as_deref(), Ok(&2.0)); + assert_eq!(world.get(id2, a()).as_deref(), Ok(&2)); assert_eq!( world.get(id2, b()).as_deref(), Err(&Error::MissingComponent(id2, b().info())) @@ -33,7 +34,7 @@ fn entity_builder() { let value = Arc::new(()); let mut id3 = Entity::builder(); - id3.set(a(), 2.0); + id3.set(a(), 2); id3.set(b(), "world".into()); id3.set(relation(id1), value.clone()); @@ -49,3 +50,43 @@ fn entity_builder() { world.despawn(id3).unwrap(); assert_eq!(Arc::strong_count(&value), 1); } + +#[test] +fn test_append() { + let mut world = World::new(); + + let id1 = Entity::builder() + .set(a(), 1) + .set(b(), "hello".into()) + .spawn(&mut world); + + let id2 = Entity::builder() + .set(a(), 1) + .set(b(), "hello".into()) + .spawn(&mut world); + + let id3 = world.spawn(); + + let mut builder = Entity::builder(); + + let value = Arc::new(()); + builder.set(a(), 5).set(relation(id2), value.clone()); + + builder.append_to(&mut world, id3).unwrap(); + + assert_eq!(Arc::strong_count(&value), 2); + assert!(world.has(id3, relation(id2))); + assert!(!world.has(id3, relation(id1))); + + let mut builder = Entity::builder(); + + builder.set(relation(id1), value.clone()); + + assert_eq!(Arc::strong_count(&value), 3); + + builder.append_to(&mut world, id3).unwrap(); + // The old relation is dropped + assert_eq!(Arc::strong_count(&value), 2); + assert!(!world.has(id3, relation(id2))); + assert!(world.has(id3, relation(id1))); +} From df2eb2d96891703cb2cab37b685772a306edd465 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Thu, 20 Jul 2023 00:30:19 +0200 Subject: [PATCH 29/52] wip: invalid archetype --- recipes.json | 2 +- src/archetype/mod.rs | 11 ++- src/archetypes.rs | 13 +++ src/commands.rs | 2 +- src/query/searcher.rs | 1 + src/world.rs | 93 +++------------------ src/writer.rs | 174 ++++++++++++++++++++++++++++++++++------ tests/entity_builder.rs | 60 +++++++++++++- 8 files changed, 241 insertions(+), 115 deletions(-) diff --git a/recipes.json b/recipes.json index 9cb105dd..ebad6e30 100644 --- a/recipes.json +++ b/recipes.json @@ -29,7 +29,7 @@ ] }, "test": { - "cmd": "cargo nextest run --all-features", + "cmd": "cargo nextest run -j 1 --all-features", "kind": "term" }, "test-miri": { diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 2ae03ea7..8967e456 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -382,7 +382,12 @@ impl Archetype { } pub(crate) fn add_incoming(&mut self, component: ComponentKey, dst_id: ArchetypeId) { - self.incoming.insert(component, dst_id); + debug_assert!(self.has(component), "Archetype has the incoming component"); + let existing = self.incoming.insert(component, dst_id); + debug_assert!( + existing.is_none() || existing == Some(dst_id), + "Insert incoming for {component:?} => {dst_id}. Existing: {existing:?}" + ) } pub(crate) fn add_outgoing(&mut self, component: ComponentKey, dst_id: ArchetypeId) { @@ -978,9 +983,11 @@ impl Archetype { } pub(crate) fn remove_link(&mut self, component: ComponentKey) { + eprintln!("Removing link for {:?}", component); let linked = self.outgoing.remove(&component); - self.children.remove(&component); assert!(linked.is_some()); + + self.children.remove(&component); } /// Borrow the change list mutably diff --git a/src/archetypes.rs b/src/archetypes.rs index e087617f..68d2b5c4 100644 --- a/src/archetypes.rs +++ b/src/archetypes.rs @@ -1,4 +1,5 @@ use alloc::{sync::Arc, vec::Vec}; +use itertools::Itertools; use crate::{ archetype::Archetype, @@ -60,10 +61,21 @@ impl Archetypes { } let arch = self.inner.despawn(arch_id).unwrap(); + eprintln!( + "Despawned archetype: {} components: {:?}, incoming: {:?}", + arch_id, + arch.components().collect_vec(), + arch.incoming + ); for (&key, &dst_id) in &arch.incoming { let dst = self.get_mut(dst_id); + eprintln!("Removing incoming link from {key}: {dst_id}"); dst.remove_link(key); + eprintln!( + "Links: children: {:?} outgoing: {:?}", + dst.children, dst.outgoing + ); self.prune_arch(dst_id); } @@ -119,6 +131,7 @@ impl Archetypes { let new_id = self.inner.spawn(new); let (cur, new) = self.inner.get_disjoint(cursor, new_id).unwrap(); + eprintln!("Spawning child {new_id} from {cursor} for {head:?}"); cur.add_child(head.key, new_id); new.add_incoming(head.key, cursor); diff --git a/src/commands.rs b/src/commands.rs index 6b92601a..c32f138a 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -211,7 +211,7 @@ impl CommandBuffer { Command::Set { id, info, offset } => unsafe { let value = self.inserts.take_dyn(offset); world - .set_dyn(id, info, value, |v| info.drop(v.cast())) + .set_dyn(id, info, value) .map_err(|v| v.into_anyhow()) .with_context(|| format!("Failed to set component {}", info.name()))?; }, diff --git a/src/query/searcher.rs b/src/query/searcher.rs index 66266dbd..b3cb8c39 100644 --- a/src/query/searcher.rs +++ b/src/query/searcher.rs @@ -43,6 +43,7 @@ pub(crate) fn traverse_archetypes<'a>( result(cur, arch); for &arch_id in arch.children.values() { + eprintln!("Traversing child {} from {}", arch_id, cur); traverse_archetypes(archetypes, arch_id, required, result); } } diff --git a/src/world.rs b/src/world.rs index 60f20a06..fd433364 100644 --- a/src/world.rs +++ b/src/world.rs @@ -494,91 +494,15 @@ impl World { id: Entity, info: ComponentInfo, value: *mut u8, - on_drop: impl FnOnce(*mut u8), ) -> Result { - // We know things will change either way - let change_tick = self.advance_change_tick(); - - let EntityLocation { - arch_id: src_id, - slot, - } = self.init_location(id)?; - - let src = self.archetypes.get_mut(src_id); - - // Fast track if the component already exists - if let Some(()) = src.mutate_in_place(slot, info.key(), change_tick, |old| { - // Make the caller responsible for drop or store - (on_drop(old)); - - unsafe { - ptr::copy_nonoverlapping(value, old, info.size()); - } - }) { - return Ok(EntityLocation { - arch_id: src_id, - slot, - }); - } - - // Exclusive relations may cause the dst archetype to be a sibling rather than a child - // of src. Adding a strong link breaks the tree in there cases - - // Pick up the entity and move it to the destination archetype - let dst_id = if let Some(&dst) = src.outgoing.get(&info.key()) { - dst - } else { - let pivot = src.components().take_while(|v| v.key < info.key()).count(); - - // Split the components - // A B C [new] D E F - let left = src.components().take(pivot); - let right = src.components().skip(pivot); - - let components = left.chain(once(info)).chain(right).collect_vec(); - - // Initialize component - self.init_component(info); - - // assert in order - let (dst_id, _) = self.archetypes.find(components); - - dst_id - }; - - assert_ne!(src_id, dst_id); - - // Borrow disjoint - let (src, dst) = self.archetypes.get_disjoint(src_id, dst_id).unwrap(); - - let (dst_slot, swapped) = - unsafe { src.move_to(dst, slot, |c, ptr| c.drop(ptr), change_tick) }; - - // Add a quick edge to refer to later - src.add_outgoing(info.key(), dst_id); - dst.add_incoming(info.key(), src_id); - - // Insert the missing component - unsafe { - dst.push(info.key, value, change_tick); - } - - debug_assert_eq!(dst.entity(dst_slot), Some(id)); - - if let Some((swapped, slot)) = swapped { - // The last entity in src was moved into the slot occupied by id - let swapped_ns = self.entities.init(swapped.kind()); - swapped_ns.get_mut(swapped).expect("Invalid entity id").slot = slot; - } - self.archetypes.prune_arch(src_id); - - let ns = self.entities.init(id.kind()); - let loc = EntityLocation { - slot: dst_slot, - arch_id: dst_id, - }; - - *ns.get_mut(id).expect("Entity is not valid") = loc; + let loc = self.set_impl( + id, + writer::ReplaceDyn { + info, + value, + _marker: core::marker::PhantomData, + }, + )?; Ok(loc) } @@ -592,6 +516,7 @@ impl World { let src = self.archetypes.get_mut(src_loc.arch_id); + eprintln!("loc: {src_loc:?}"); if let Some(writer) = updater.write(src, id, src_loc.slot, change_tick) { // Move to a new archetype let (dst_loc, swapped) = diff --git a/src/writer.rs b/src/writer.rs index 4862e723..0d233192 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,4 +1,4 @@ -use core::{mem, ptr}; +use core::{marker::PhantomData, mem, ptr}; use itertools::{Either, Itertools}; @@ -55,6 +55,7 @@ impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { slot: Slot, tick: u32, ) -> Option { + let info = self.component.info(); let key = self.component.key(); if let Some(cell) = arch.cell_mut(key) { @@ -78,20 +79,13 @@ impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { }) } else { // Oh no! The archetype is missing the component - // - // Generate a list of component infos which fully satisfy the requirements for the - // desired archetype to move to - let pivot = arch.components().take_while(|v| v.key < key).count(); - // Split the components - // A B C [new] D E F - let left = arch.components().take(pivot); - let right = arch.components().skip(pivot); - - let components = left - .chain([self.component.info()]) - .chain(right) - .collect_vec(); + eprintln!( + "Missing component: {:?} found:{:?}", + info, + arch.components().collect_vec() + ); + let components = find_archetype(arch, [info], &[info.key.id]); Some(ReplaceWriter { dst: Either::Right(components), @@ -131,6 +125,12 @@ unsafe impl MigrateEntity for ReplaceWriter { // Add a quick edge to refer to later let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + + eprintln!( + "Adding edge: {:?} -> {:?} {:?}", + src_id, dst_id, self.component + ); + src.add_outgoing(key, dst_id); dst.add_incoming(key, src_id); (src, dst, dst_id) @@ -156,6 +156,123 @@ unsafe impl MigrateEntity for ReplaceWriter { } } +pub(crate) struct ReplaceDyn<'a> { + pub(crate) info: ComponentInfo, + pub(crate) value: *mut u8, + pub(crate) _marker: PhantomData<&'a mut ()>, +} + +impl<'a> ComponentWriter for ReplaceDyn<'a> { + type Writer = ReplaceWriterDyn<'a>; + + fn write( + self, + arch: &mut Archetype, + id: Entity, + slot: Slot, + tick: u32, + ) -> Option { + let key = self.info.key(); + + if let Some(cell) = arch.cell_mut(key) { + let data = cell.data.get_mut(); + + let storage = &mut data.storage; + unsafe { + let dst = storage.at_mut(slot).unwrap(); + ptr::copy_nonoverlapping(self.value, dst, self.info.size()); + self.info.drop(dst); + } + + data.set_modified(&[id], Slice::single(slot), tick); + + None + } else if let Some(&dst) = arch.outgoing.get(&key) { + eprintln!("Outgoing edge: {:?}", self.info); + + Some(ReplaceWriterDyn { + dst: Either::Left(dst), + info: self.info, + value: self.value, + _marker: self._marker, + }) + } else { + // Oh no! The archetype is missing the component + + eprintln!( + "Missing component: {:?} found:{:?}", + self.info, + arch.components().collect_vec() + ); + let components = find_archetype(arch, [self.info], &[self.info.key.id]); + eprintln!("Result: {components:?}"); + + Some(ReplaceWriterDyn { + dst: Either::Right(components), + info: self.info, + value: self.value, + _marker: self._marker, + }) + } + } +} + +pub(crate) struct ReplaceWriterDyn<'a> { + dst: Either>, + info: ComponentInfo, + value: *mut u8, + _marker: PhantomData<&'a mut ()>, +} + +unsafe impl<'a> MigrateEntity for ReplaceWriterDyn<'a> { + fn migrate( + self, + world: &mut World, + src_id: ArchetypeId, + src_slot: Slot, + tick: u32, + ) -> (EntityLocation, Option<(Entity, Slot)>) { + let key = self.info.key(); + + let (src, dst, dst_id) = match &self.dst { + &Either::Left(dst_id) => { + let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + (src, dst, dst_id) + } + Either::Right(components) => { + // Initialize component + world.init_component(self.info); + + let (dst_id, _) = world.archetypes.find(components.iter().copied()); + + // Add a quick edge to refer to later + let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + eprintln!("Adding edge: {:?} -> {:?} {:?}", src_id, dst_id, self.info); + src.add_outgoing(key, dst_id); + dst.add_incoming(key, src_id); + + (src, dst, dst_id) + } + }; + + let (dst_slot, swapped) = unsafe { src.move_to(dst, src_slot, |c, ptr| c.drop(ptr), tick) }; + + // Insert the missing component + unsafe { + let value = self.value; + dst.push(key, value, tick); + } + + ( + EntityLocation { + slot: dst_slot, + arch_id: dst_id, + }, + swapped, + ) + } +} + pub(crate) struct Buffered<'a> { pub(crate) buffer: &'a mut ComponentBuffer, } @@ -213,16 +330,12 @@ impl<'a> ComponentWriter for Buffered<'a> { None } else { // Add the existing components, making sure new exclusive relations are favored - let components = self - .buffer - .components() - .copied() - .chain( - arch.components() - .filter(|v| !exclusive_relations.contains(&v.key.id)), - ) - .sorted_unstable() - .collect_vec(); + + let components = find_archetype( + arch, + self.buffer.components().copied(), + &exclusive_relations, + ); Some(BufferedMigrate { components, @@ -274,3 +387,16 @@ unsafe impl<'a> MigrateEntity for BufferedMigrate<'a> { ) } } + +fn find_archetype( + arch: &Archetype, + new_components: impl IntoIterator, + // Subset of `new_components` + exclusive: &[Entity], +) -> Vec { + new_components + .into_iter() + .chain(arch.components().filter(|v| !exclusive.contains(&v.key.id))) + .sorted_unstable() + .collect_vec() +} diff --git a/tests/entity_builder.rs b/tests/entity_builder.rs index d783f3ec..b18164e4 100644 --- a/tests/entity_builder.rs +++ b/tests/entity_builder.rs @@ -1,6 +1,6 @@ extern crate alloc; use alloc::string::String; -use flax::{component, Entity, Error, Exclusive, World}; +use flax::{component, CommandBuffer, Entity, Error, Exclusive, World}; use std::sync::Arc; component! { @@ -34,9 +34,9 @@ fn entity_builder() { let value = Arc::new(()); let mut id3 = Entity::builder(); - id3.set(a(), 2); + id3.set(a(), 3); id3.set(b(), "world".into()); - id3.set(relation(id1), value.clone()); + id3.set(relation(id2), value.clone()); assert_eq!(Arc::strong_count(&value), 2); @@ -47,10 +47,64 @@ fn entity_builder() { let id3 = id3.spawn(&mut world); assert_eq!(Arc::strong_count(&value), 2); + assert_eq!(world.get(id3, a()).as_deref(), Ok(&3)); + assert_eq!(world.get(id3, relation(id1)).as_deref(), Ok(&value)); + assert_eq!( + world.get(id3, relation(id2)).as_deref(), + Err(&Error::MissingComponent(id3, relation(id2).info())) + ); + world.despawn(id3).unwrap(); assert_eq!(Arc::strong_count(&value), 1); } +#[test] +fn entity_builder_cmd() { + let mut world = World::new(); + + let id1 = Entity::builder() + .set(a(), 1) + .set(b(), "hello".into()) + .spawn(&mut world); + + let mut id2 = Entity::builder(); + id2.set(a(), 2).set(b(), "hello".into()); + id2.remove(b()); + + let id2 = id2.spawn(&mut world); + + assert_eq!(world.get(id2, a()).as_deref(), Ok(&2)); + assert_eq!( + world.get(id2, b()).as_deref(), + Err(&Error::MissingComponent(id2, b().info())) + ); + + let value = Arc::new(()); + + let id3 = world.spawn(); + let mut cmd = CommandBuffer::new(); + cmd.set(id3, a(), 4); + cmd.set(id3, b(), "world".into()); + cmd.set(id3, relation(id2), value.clone()); + + assert_eq!(Arc::strong_count(&value), 2); + + cmd.set(id3, relation(id1), value.clone()); + + cmd.apply(&mut world).unwrap(); + + assert_eq!(world.get(id3, a()).as_deref(), Ok(&4)); + assert_eq!(world.get(id3, relation(id1)).as_deref(), Ok(&value)); + assert_eq!( + world.get(id3, relation(id2)).as_deref(), + Err(&Error::MissingComponent(id3, relation(id2).info())) + ); + + assert_eq!(Arc::strong_count(&value), 2); + + world.despawn(id3).unwrap(); + assert_eq!(Arc::strong_count(&value), 1); +} #[test] fn test_append() { let mut world = World::new(); From 8c4cf0e5f77b972c34c68c26be07b8b1d56c60e0 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 22 Jul 2023 01:21:48 +0200 Subject: [PATCH 30/52] fix: invalid archetype --- src/archetype/mod.rs | 2 ++ src/archetypes.rs | 6 +++- src/writer.rs | 77 ++++++++++++++++++++++++++++++-------------- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 8967e456..1d82795e 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -383,7 +383,9 @@ impl Archetype { pub(crate) fn add_incoming(&mut self, component: ComponentKey, dst_id: ArchetypeId) { debug_assert!(self.has(component), "Archetype has the incoming component"); + let existing = self.incoming.insert(component, dst_id); + debug_assert!( existing.is_none() || existing == Some(dst_id), "Insert incoming for {component:?} => {dst_id}. Existing: {existing:?}" diff --git a/src/archetypes.rs b/src/archetypes.rs index 68d2b5c4..d598513b 100644 --- a/src/archetypes.rs +++ b/src/archetypes.rs @@ -56,7 +56,11 @@ impl Archetypes { /// Prunes a leaf and its ancestors from empty archetypes pub(crate) fn prune_arch(&mut self, arch_id: ArchetypeId) -> bool { let arch = self.get(arch_id); - if arch_id == self.root || !arch.is_empty() || !arch.outgoing.is_empty() { + if arch_id == self.root + || arch_id == self.reserved + || !arch.is_empty() + || !arch.outgoing.is_empty() + { return false; } diff --git a/src/writer.rs b/src/writer.rs index 0d233192..13785d11 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,6 +1,7 @@ -use core::{marker::PhantomData, mem, ptr}; +use core::{marker::PhantomData, mem, ptr, slice}; use itertools::{Either, Itertools}; +use serde::ser::SerializeTupleStruct; use crate::{ archetype::{Archetype, Slice, Slot}, @@ -85,10 +86,15 @@ impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { info, arch.components().collect_vec() ); - let components = find_archetype(arch, [info], &[info.key.id]); + + let exclusive = if info.meta_ref().has(exclusive()) { + slice::from_ref(&info.key.id) + } else { + &[] + }; Some(ReplaceWriter { - dst: Either::Right(components), + dst: Either::Right(find_archetype(arch, [info], exclusive)), component: self.component, value: self.value, }) @@ -97,7 +103,7 @@ impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { } pub(crate) struct ReplaceWriter { - dst: Either>, + dst: Either, bool)>, component: Component, value: T, } @@ -117,22 +123,23 @@ unsafe impl MigrateEntity for ReplaceWriter { let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); (src, dst, dst_id) } - Either::Right(components) => { + Either::Right((components, superset)) => { // Initialize component world.init_component(self.component.info()); let (dst_id, _) = world.archetypes.find(components.iter().copied()); // Add a quick edge to refer to later + let reserved_id = world.archetypes.reserved; let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); - eprintln!( - "Adding edge: {:?} -> {:?} {:?}", - src_id, dst_id, self.component - ); + if *superset && src_id != reserved_id { + src.add_outgoing(key, dst_id); + dst.add_incoming(key, src_id); + } else { + eprintln!("Not a superset") + } - src.add_outgoing(key, dst_id); - dst.add_incoming(key, src_id); (src, dst, dst_id) } }; @@ -180,8 +187,10 @@ impl<'a> ComponentWriter for ReplaceDyn<'a> { let storage = &mut data.storage; unsafe { let dst = storage.at_mut(slot).unwrap(); - ptr::copy_nonoverlapping(self.value, dst, self.info.size()); + self.info.drop(dst); + + ptr::copy_nonoverlapping(self.value, dst, self.info.size()); } data.set_modified(&[id], Slice::single(slot), tick); @@ -204,11 +213,15 @@ impl<'a> ComponentWriter for ReplaceDyn<'a> { self.info, arch.components().collect_vec() ); - let components = find_archetype(arch, [self.info], &[self.info.key.id]); - eprintln!("Result: {components:?}"); + + let exclusive = if self.info.meta_ref().has(exclusive()) { + slice::from_ref(&self.info.key.id) + } else { + &[] + }; Some(ReplaceWriterDyn { - dst: Either::Right(components), + dst: Either::Right(find_archetype(arch, [self.info], exclusive)), info: self.info, value: self.value, _marker: self._marker, @@ -218,7 +231,7 @@ impl<'a> ComponentWriter for ReplaceDyn<'a> { } pub(crate) struct ReplaceWriterDyn<'a> { - dst: Either>, + dst: Either, bool)>, info: ComponentInfo, value: *mut u8, _marker: PhantomData<&'a mut ()>, @@ -239,17 +252,21 @@ unsafe impl<'a> MigrateEntity for ReplaceWriterDyn<'a> { let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); (src, dst, dst_id) } - Either::Right(components) => { + Either::Right((components, superset)) => { // Initialize component world.init_component(self.info); let (dst_id, _) = world.archetypes.find(components.iter().copied()); // Add a quick edge to refer to later + let reserved_id = world.archetypes.reserved; let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); - eprintln!("Adding edge: {:?} -> {:?} {:?}", src_id, dst_id, self.info); - src.add_outgoing(key, dst_id); - dst.add_incoming(key, src_id); + + if *superset && src_id != reserved_id { + eprintln!("Adding edge: {:?} -> {:?} {:?}", src_id, dst_id, self.info); + src.add_outgoing(key, dst_id); + dst.add_incoming(key, src_id); + } (src, dst, dst_id) } @@ -331,7 +348,7 @@ impl<'a> ComponentWriter for Buffered<'a> { } else { // Add the existing components, making sure new exclusive relations are favored - let components = find_archetype( + let (components, _) = find_archetype( arch, self.buffer.components().copied(), &exclusive_relations, @@ -393,10 +410,20 @@ fn find_archetype( new_components: impl IntoIterator, // Subset of `new_components` exclusive: &[Entity], -) -> Vec { - new_components +) -> (Vec, bool) { + let mut superset = true; + let res = new_components .into_iter() - .chain(arch.components().filter(|v| !exclusive.contains(&v.key.id))) + .chain(arch.components().filter(|v| { + if exclusive.contains(&v.key.id) { + superset = false; + false + } else { + true + } + })) .sorted_unstable() - .collect_vec() + .collect_vec(); + + dbg!(res, superset) } From 0c960985a6aa15f277b88196210169a0955d6ae6 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 22 Jul 2023 18:15:34 +0200 Subject: [PATCH 31/52] refactor: simplify writer traits --- recipes.json | 2 +- src/archetypes.rs | 2 +- src/world.rs | 90 ++++------ src/writer.rs | 422 ++++++++++++++++++---------------------------- 4 files changed, 198 insertions(+), 318 deletions(-) diff --git a/recipes.json b/recipes.json index ebad6e30..f309d77f 100644 --- a/recipes.json +++ b/recipes.json @@ -33,7 +33,7 @@ "kind": "term" }, "test-miri": { - "cmd": "cargo miri nextest run --no-default-features --features std,serde,flume,derive" + "cmd": "cargo miri nextest run -j 8 --no-default-features --features std,serde,flume,derive" }, "doc": { "cmd": "cargo doc --all-features --open" diff --git a/src/archetypes.rs b/src/archetypes.rs index d598513b..e3442738 100644 --- a/src/archetypes.rs +++ b/src/archetypes.rs @@ -95,7 +95,7 @@ impl Archetypes { /// `components` must be sorted. /// /// Ensures the `exclusive` property of any relations are satisfied - pub(crate) fn find( + pub(crate) fn find_create( &mut self, components: impl IntoIterator, ) -> (ArchetypeId, &mut Archetype) { diff --git a/src/world.rs b/src/world.rs index fd433364..f8ce489a 100644 --- a/src/world.rs +++ b/src/world.rs @@ -2,9 +2,7 @@ use alloc::{borrow::ToOwned, collections::BTreeMap, sync::Arc, vec::Vec}; use core::{ fmt, fmt::Formatter, - iter::once, mem::{self, MaybeUninit}, - ptr, sync::atomic::{AtomicBool, AtomicU32, Ordering, Ordering::Relaxed}, }; use once_cell::unsync::OnceCell; @@ -14,7 +12,7 @@ use atomic_refcell::{AtomicRef, BorrowError, BorrowMutError}; use itertools::Itertools; use crate::{ - archetype::{Archetype, ArchetypeInfo}, + archetype::{Archetype, ArchetypeInfo, Slot}, archetypes::Archetypes, buffer::ComponentBuffer, component::dummy, @@ -28,7 +26,7 @@ use crate::{ format::{EntitiesFormatter, HierarchyFormatter, WorldFormatter}, is_static, relation::Relation, - writer::{self, ComponentWriter, MigrateEntity}, + writer::{self, EntityWriter, Replace, ReplaceDyn, SingleComponentWriter}, ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; @@ -56,6 +54,23 @@ impl EntityStores { } } +pub(crate) fn update_entity_loc( + world: &mut World, + id: Entity, + loc: EntityLocation, + swapped: Option<(Entity, Slot)>, +) { + if let Some((swapped, slot)) = swapped { + // The last entity in src was moved into the slot occupied by id + let swapped_ns = world.entities.init(swapped.kind()); + swapped_ns.get_mut(swapped).expect("Invalid entity id").slot = slot; + } + + let ns = world.entities.init(id.kind()); + + *ns.get_mut(id).expect("Entity is not valid") = loc; +} + /// Holds the entities and components of the ECS. pub struct World { entities: EntityStores, @@ -126,7 +141,7 @@ impl World { let change_tick = self.advance_change_tick(); - let (arch_id, arch) = self.archetypes.find(batch.components()); + let (arch_id, arch) = self.archetypes.find_create(batch.components()); let base = arch.len(); let store = self.entities.init(EntityKind::empty()); @@ -199,7 +214,7 @@ impl World { self.init_component(component); } - let (arch_id, _) = self.archetypes.find(buffer.components().copied()); + let (arch_id, _) = self.archetypes.find_create(buffer.components().copied()); let (loc, arch) = self.spawn_at_inner(id, arch_id)?; for (info, src) in buffer.drain() { @@ -218,7 +233,7 @@ impl World { } let change_tick = self.advance_change_tick(); - let (arch_id, _) = self.archetypes.find(buffer.components().copied()); + let (arch_id, _) = self.archetypes.find_create(buffer.components().copied()); let (id, _, arch) = self.spawn_inner(arch_id, EntityKind::empty()); @@ -274,7 +289,7 @@ impl World { let dst_components: SmallVec<[ComponentInfo; 8]> = src.components().filter(|v| f(v.key())).collect(); - let (dst_id, _) = self.archetypes.find(dst_components); + let (dst_id, _) = self.archetypes.find_create(dst_components); let (src, dst) = self.archetypes.get_disjoint(loc.arch_id, dst_id).unwrap(); @@ -445,7 +460,7 @@ impl World { !(key.id == id || key.object == Some(id)) }); - let (dst_id, dst) = self.archetypes.find(components); + let (dst_id, dst) = self.archetypes.find_create(components); for (id, slot) in src.move_all(dst, change_tick) { *self.location_mut(id).expect("Entity id was not valid") = EntityLocation { @@ -495,53 +510,20 @@ impl World { info: ComponentInfo, value: *mut u8, ) -> Result { - let loc = self.set_impl( - id, - writer::ReplaceDyn { - info, - value, - _marker: core::marker::PhantomData, - }, - )?; + let loc = self.set_impl(id, SingleComponentWriter::new(info, ReplaceDyn { value }))?; Ok(loc) } #[inline] - fn set_impl(&mut self, id: Entity, updater: U) -> Result { + fn set_impl(&mut self, id: Entity, writer: U) -> Result { // We know things will change either way let change_tick = self.advance_change_tick(); let src_loc = self.init_location(id)?; - let src = self.archetypes.get_mut(src_loc.arch_id); - eprintln!("loc: {src_loc:?}"); - if let Some(writer) = updater.write(src, id, src_loc.slot, change_tick) { - // Move to a new archetype - let (dst_loc, swapped) = - writer.migrate(self, src_loc.arch_id, src_loc.slot, change_tick); - - debug_assert_eq!( - self.archetypes.get(dst_loc.arch_id).entity(dst_loc.slot), - Some(id) - ); - - if let Some((swapped, slot)) = swapped { - // The last entity in src was moved into the slot occupied by id - let swapped_ns = self.entities.init(swapped.kind()); - swapped_ns.get_mut(swapped).expect("Invalid entity id").slot = slot; - } - self.archetypes.prune_arch(src_loc.arch_id); - - let ns = self.entities.init(id.kind()); - - *ns.get_mut(id).expect("Entity is not valid") = dst_loc; - - Ok(dst_loc) - } else { - Ok(src_loc) - } + Ok(writer.write(self, id, src_loc, change_tick)) } /// TODO benchmark with fully generic function @@ -556,11 +538,7 @@ impl World { let loc = self.set_impl( id, - writer::Replace { - component, - value, - output: &mut output, - }, + SingleComponentWriter::new(component.info(), Replace::new(value, &mut output)), )?; Ok((output, loc)) @@ -599,7 +577,7 @@ impl World { .filter(|v| v.key != component.key()) .collect_vec(); - let (dst_id, _) = self.archetypes.find(components); + let (dst_id, _) = self.archetypes.find_create(components); dst_id } @@ -850,7 +828,7 @@ impl World { let change_tick = self.advance_change_tick(); - let (arch_id, arch) = self.archetypes.find(batch.components()); + let (arch_id, arch) = self.archetypes.find_create(batch.components()); let base = arch.len(); for (idx, &id) in ids.iter().enumerate() { @@ -1347,14 +1325,18 @@ mod tests { let mut world = World::new(); // () -> (a) -> (ab) -> (abc) - let (_, archetype) = world.archetypes.find([a().info(), b().info(), c().info()]); + let (_, archetype) = world + .archetypes + .find_create([a().info(), b().info(), c().info()]); assert!(!archetype.has(d().key())); assert!(archetype.has(a().key())); assert!(archetype.has(b().key())); // () -> (a) -> (ab) -> (abc) // -> (abd) - let (_, archetype) = world.archetypes.find([a().info(), b().info(), d().info()]); + let (_, archetype) = world + .archetypes + .find_create([a().info(), b().info(), d().info()]); assert!(archetype.has(d().key())); assert!(!archetype.has(c().key())); } diff --git a/src/writer.rs b/src/writer.rs index 13785d11..2368a7c4 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,292 +1,207 @@ -use core::{marker::PhantomData, mem, ptr, slice}; +use core::{mem, ptr, slice}; -use itertools::{Either, Itertools}; -use serde::ser::SerializeTupleStruct; +use itertools::Itertools; use crate::{ - archetype::{Archetype, Slice, Slot}, + archetype::{Cell, Slice, Slot}, buffer::ComponentBuffer, entity::EntityLocation, metadata::exclusive, - ArchetypeId, Component, ComponentInfo, ComponentValue, Entity, World, + world::update_entity_loc, + ArchetypeId, ComponentInfo, ComponentValue, Entity, World, }; /// Describes a modification to the components of an entity within the context of an archetype pub(crate) trait ComponentWriter { - /// If returned, will be used to migrate the entity to a new archetype - type Writer: MigrateEntity; - - /// Performs write operations against the target entity and archetype. + /// Performs write operations against the target entity + fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32); + /// # Safety /// - /// A migration to another archetype may be induced by returning an entity migrator - fn write( - self, - archetype: &mut Archetype, - id: Entity, - slot: Slot, - tick: u32, - ) -> Option; + /// The cell **must** be extended with valid component data for the new entity + unsafe fn push(self, cell: &mut Cell, id: Entity, tick: u32); } /// # Safety -/// *All* components of the new slot must be initialized -pub(crate) unsafe trait MigrateEntity { - fn migrate( - self, - world: &mut World, - src_id: ArchetypeId, - src_slot: Slot, - tick: u32, - ) -> (EntityLocation, Option<(Entity, Slot)>); +/// +/// The entity must be fully initialized and all bookkepping updated +pub unsafe trait EntityWriter { + fn write(self, world: &mut World, id: Entity, loc: EntityLocation, tick: u32) + -> EntityLocation; } -pub(crate) struct Replace<'a, T: ComponentValue> { - pub(crate) component: Component, - pub(crate) value: T, - pub(crate) output: &'a mut Option, +pub(crate) struct SingleComponentWriter { + info: ComponentInfo, + writer: W, } -impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { - type Writer = ReplaceWriter; +impl SingleComponentWriter { + pub(crate) fn new(info: ComponentInfo, writer: W) -> Self { + Self { info, writer } + } +} +unsafe impl EntityWriter for SingleComponentWriter { fn write( self, - arch: &mut Archetype, + world: &mut World, id: Entity, - slot: Slot, + src_loc: EntityLocation, tick: u32, - ) -> Option { - let info = self.component.info(); - let key = self.component.key(); - - if let Some(cell) = arch.cell_mut(key) { - let data = cell.data.get_mut(); - - let storage = data.storage.downcast_mut::(); - let old = mem::replace(&mut storage[slot], self.value); - - data.set_modified(&[id], Slice::single(slot), tick); + ) -> EntityLocation { + let key = self.info.key(); - *self.output = Some(old); + let arch = world.archetypes.get_mut(src_loc.arch_id); - None - } else if let Some(&dst) = arch.outgoing.get(&key) { - eprintln!("Outgoing edge: {:?}", self.component); + if let Some(cell) = arch.cell_mut(key) { + self.writer.update(cell, src_loc.slot, id, tick); + return src_loc; + } + let (src, dst, dst_id) = if let Some(&dst_id) = arch.outgoing.get(&key) { + eprintln!("Outgoing edge: {:?}", self.info); - Some(ReplaceWriter { - dst: Either::Left(dst), - component: self.component, - value: self.value, - }) + let (src, dst) = world + .archetypes + .get_disjoint(src_loc.arch_id, dst_id) + .unwrap(); + (src, dst, dst_id) } else { // Oh no! The archetype is missing the component eprintln!( "Missing component: {:?} found:{:?}", - info, + self.info, arch.components().collect_vec() ); - let exclusive = if info.meta_ref().has(exclusive()) { - slice::from_ref(&info.key.id) + let exclusive = if self.info.meta_ref().has(exclusive()) { + slice::from_ref(&self.info.key.id) } else { &[] }; - Some(ReplaceWriter { - dst: Either::Right(find_archetype(arch, [info], exclusive)), - component: self.component, - value: self.value, - }) - } - } -} + let (components, superset) = + find_archetype_components(arch.components(), [self.info], exclusive); -pub(crate) struct ReplaceWriter { - dst: Either, bool)>, - component: Component, - value: T, -} + world.init_component(self.info); + let (dst_id, _) = world.archetypes.find_create(components.iter().copied()); -unsafe impl MigrateEntity for ReplaceWriter { - fn migrate( - self, - world: &mut World, - src_id: ArchetypeId, - src_slot: Slot, - tick: u32, - ) -> (EntityLocation, Option<(Entity, Slot)>) { - let key = self.component.key(); + // Add a quick edge to refer to later + let reserved_id = world.archetypes.reserved; + let (src, dst) = world + .archetypes + .get_disjoint(src_loc.arch_id, dst_id) + .unwrap(); - let (src, dst, dst_id) = match &self.dst { - &Either::Left(dst_id) => { - let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); - (src, dst, dst_id) + if superset && src_loc.arch_id != reserved_id { + src.add_outgoing(key, dst_id); + dst.add_incoming(key, src_loc.arch_id); + } else { + eprintln!("Not a superset") } - Either::Right((components, superset)) => { - // Initialize component - world.init_component(self.component.info()); - - let (dst_id, _) = world.archetypes.find(components.iter().copied()); - - // Add a quick edge to refer to later - let reserved_id = world.archetypes.reserved; - let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); - - if *superset && src_id != reserved_id { - src.add_outgoing(key, dst_id); - dst.add_incoming(key, src_id); - } else { - eprintln!("Not a superset") - } - (src, dst, dst_id) - } + (src, dst, dst_id) }; - let (dst_slot, swapped) = unsafe { src.move_to(dst, src_slot, |c, ptr| c.drop(ptr), tick) }; + let (dst_slot, swapped) = + unsafe { src.move_to(dst, src_loc.slot, |c, ptr| c.drop(ptr), tick) }; // Insert the missing component unsafe { - let mut value = self.value; - dst.push(key, &mut value as *mut T as *mut u8, tick); - mem::forget(value); + let cell = dst + .cell_mut(key) + .expect("Missing component in new archetype"); + + cell.data.get_mut().storage.reserve(1); + self.writer.push(cell, id, tick); } - ( - EntityLocation { - slot: dst_slot, - arch_id: dst_id, - }, - swapped, - ) - } -} + let dst_loc = EntityLocation { + arch_id: dst_id, + slot: dst_slot, + }; -pub(crate) struct ReplaceDyn<'a> { - pub(crate) info: ComponentInfo, - pub(crate) value: *mut u8, - pub(crate) _marker: PhantomData<&'a mut ()>, -} + update_entity_loc(world, id, dst_loc, swapped); -impl<'a> ComponentWriter for ReplaceDyn<'a> { - type Writer = ReplaceWriterDyn<'a>; + dst_loc + } +} - fn write( +/// # Safety +/// *All* components of the new slot must be initialized +pub(crate) unsafe trait MigrateEntity { + fn migrate( self, - arch: &mut Archetype, - id: Entity, - slot: Slot, + world: &mut World, + src_id: ArchetypeId, + src_slot: Slot, tick: u32, - ) -> Option { - let key = self.info.key(); + ) -> (EntityLocation, Option<(Entity, Slot)>); +} - if let Some(cell) = arch.cell_mut(key) { - let data = cell.data.get_mut(); +pub(crate) struct Replace<'a, T: ComponentValue> { + pub(crate) value: T, + pub(crate) output: &'a mut Option, +} - let storage = &mut data.storage; - unsafe { - let dst = storage.at_mut(slot).unwrap(); +impl<'a, T: ComponentValue> Replace<'a, T> { + pub(crate) fn new(value: T, output: &'a mut Option) -> Self { + Self { value, output } + } +} - self.info.drop(dst); +impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { + fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32) { + let data = cell.data.get_mut(); - ptr::copy_nonoverlapping(self.value, dst, self.info.size()); - } + let storage = data.storage.downcast_mut::(); + let old = mem::replace(&mut storage[slot], self.value); - data.set_modified(&[id], Slice::single(slot), tick); + data.set_modified(&[id], Slice::single(slot), tick); - None - } else if let Some(&dst) = arch.outgoing.get(&key) { - eprintln!("Outgoing edge: {:?}", self.info); + *self.output = Some(old); + } - Some(ReplaceWriterDyn { - dst: Either::Left(dst), - info: self.info, - value: self.value, - _marker: self._marker, - }) - } else { - // Oh no! The archetype is missing the component + unsafe fn push(mut self, cell: &mut Cell, id: Entity, tick: u32) { + let data = cell.data.get_mut(); - eprintln!( - "Missing component: {:?} found:{:?}", - self.info, - arch.components().collect_vec() - ); + let slot = data.storage.len(); - let exclusive = if self.info.meta_ref().has(exclusive()) { - slice::from_ref(&self.info.key.id) - } else { - &[] - }; + data.storage.extend(&mut self.value as *mut T as *mut u8, 1); - Some(ReplaceWriterDyn { - dst: Either::Right(find_archetype(arch, [self.info], exclusive)), - info: self.info, - value: self.value, - _marker: self._marker, - }) - } + mem::forget(self.value); + + data.set_added(&[id], Slice::single(slot), tick); } } -pub(crate) struct ReplaceWriterDyn<'a> { - dst: Either, bool)>, - info: ComponentInfo, - value: *mut u8, - _marker: PhantomData<&'a mut ()>, +pub(crate) struct ReplaceDyn { + pub(crate) value: *mut u8, } -unsafe impl<'a> MigrateEntity for ReplaceWriterDyn<'a> { - fn migrate( - self, - world: &mut World, - src_id: ArchetypeId, - src_slot: Slot, - tick: u32, - ) -> (EntityLocation, Option<(Entity, Slot)>) { - let key = self.info.key(); +impl ComponentWriter for ReplaceDyn { + fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32) { + let info = cell.info(); - let (src, dst, dst_id) = match &self.dst { - &Either::Left(dst_id) => { - let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); - (src, dst, dst_id) - } - Either::Right((components, superset)) => { - // Initialize component - world.init_component(self.info); + let data = cell.data.get_mut(); - let (dst_id, _) = world.archetypes.find(components.iter().copied()); + unsafe { + let dst = data.storage.at_mut(slot).unwrap(); - // Add a quick edge to refer to later - let reserved_id = world.archetypes.reserved; - let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); + info.drop(dst); - if *superset && src_id != reserved_id { - eprintln!("Adding edge: {:?} -> {:?} {:?}", src_id, dst_id, self.info); - src.add_outgoing(key, dst_id); - dst.add_incoming(key, src_id); - } + ptr::copy_nonoverlapping(self.value, dst, info.size()); + } - (src, dst, dst_id) - } - }; + data.set_modified(&[id], Slice::single(slot), tick); + } - let (dst_slot, swapped) = unsafe { src.move_to(dst, src_slot, |c, ptr| c.drop(ptr), tick) }; + unsafe fn push(self, cell: &mut Cell, id: Entity, tick: u32) { + let data = cell.data.get_mut(); - // Insert the missing component - unsafe { - let value = self.value; - dst.push(key, value, tick); - } + let slot = data.storage.len(); + data.storage.extend(self.value, 1); - ( - EntityLocation { - slot: dst_slot, - arch_id: dst_id, - }, - swapped, - ) + data.set_added(&[id], Slice::single(slot), tick); } } @@ -300,17 +215,17 @@ impl<'a> Buffered<'a> { } } -impl<'a> ComponentWriter for Buffered<'a> { - type Writer = BufferedMigrate<'a>; - +unsafe impl<'a> EntityWriter for Buffered<'a> { fn write( self, - arch: &mut Archetype, + world: &mut World, id: Entity, - slot: Slot, + src_loc: EntityLocation, tick: u32, - ) -> Option { + ) -> EntityLocation { let mut exclusive_relations = Vec::new(); + + let arch = world.archetypes.get_mut(src_loc.arch_id); unsafe { self.buffer.retain(|info, src| { let key = info.key; @@ -319,11 +234,11 @@ impl<'a> ComponentWriter for Buffered<'a> { if let Some(cell) = arch.cell_mut(key) { let data = cell.data.get_mut(); - let dst = data.storage.at_mut(slot).unwrap(); + let dst = data.storage.at_mut(src_loc.slot).unwrap(); info.drop(dst); ptr::copy_nonoverlapping(src, dst, info.size()); - data.set_modified(&[id], Slice::single(slot), tick); + data.set_modified(&[id], Slice::single(src_loc.slot), tick); false } else { // Component does not exist yet, so defer a move @@ -344,69 +259,52 @@ impl<'a> ComponentWriter for Buffered<'a> { if self.buffer.is_empty() { eprintln!("Archetype fully matched"); - None - } else { - // Add the existing components, making sure new exclusive relations are favored - - let (components, _) = find_archetype( - arch, - self.buffer.components().copied(), - &exclusive_relations, - ); - - Some(BufferedMigrate { - components, - buffer: self.buffer, - }) + return src_loc; } - } -} -pub(crate) struct BufferedMigrate<'a> { - components: Vec, - buffer: &'a mut ComponentBuffer, -} + // Add the existing components, making sure new exclusive relations are favored + let (components, _) = find_archetype_components( + arch.components(), + self.buffer.components().copied(), + &exclusive_relations, + ); -unsafe impl<'a> MigrateEntity for BufferedMigrate<'a> { - fn migrate( - self, - world: &mut World, - src_id: ArchetypeId, - src_slot: Slot, - tick: u32, - ) -> (EntityLocation, Option<(Entity, Slot)>) { for &info in self.buffer.components() { eprintln!("Initializing component {:?}", info); world.init_component(info); } - let (dst_id, _) = world.archetypes.find(self.components.iter().copied()); + let (dst_id, _) = world.archetypes.find_create(components); + + let (src, dst) = world + .archetypes + .get_disjoint(src_loc.arch_id, dst_id) + .unwrap(); - let (src, dst) = world.archetypes.get_disjoint(src_id, dst_id).unwrap(); - let (dst_slot, swapped) = unsafe { src.move_to(dst, src_slot, |c, ptr| c.drop(ptr), tick) }; + let (dst_slot, swapped) = + unsafe { src.move_to(dst, src_loc.slot, |c, ptr| c.drop(ptr), tick) }; // Insert the missing components for (info, src) in self.buffer.drain() { unsafe { - // src moves into herer dst.push(info.key, src, tick); } } - eprintln!("Buffer retained {} items", self.buffer.len()); + let dst_loc = EntityLocation { + arch_id: dst_id, + slot: dst_slot, + }; + + update_entity_loc(world, id, dst_loc, swapped); + world.archetypes.prune_arch(src_loc.arch_id); - ( - EntityLocation { - slot: dst_slot, - arch_id: dst_id, - }, - swapped, - ) + dst_loc } } -fn find_archetype( - arch: &Archetype, +fn find_archetype_components( + current_components: impl IntoIterator, new_components: impl IntoIterator, // Subset of `new_components` exclusive: &[Entity], @@ -414,7 +312,7 @@ fn find_archetype( let mut superset = true; let res = new_components .into_iter() - .chain(arch.components().filter(|v| { + .chain(current_components.into_iter().filter(|v| { if exclusive.contains(&v.key.id) { superset = false; false From e4c93fa7eece48f6b26ef6c7371f3362a61e5e49 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 23 Jul 2023 15:45:06 +0200 Subject: [PATCH 32/52] refactor: remove set_inner --- src/entity_ref.rs | 19 ++++++++++--- src/entry.rs | 21 +++++++++++--- src/world.rs | 72 ++++++++++++++++++++++------------------------- 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/src/entity_ref.rs b/src/entity_ref.rs index b0505b07..a0c20963 100644 --- a/src/entity_ref.rs +++ b/src/entity_ref.rs @@ -12,7 +12,9 @@ use crate::{ entry::{Entry, OccupiedEntry, VacantEntry}, error::Result, format::EntityFormatter, - name, Component, ComponentKey, ComponentValue, Entity, Error, RelationExt, World, + name, + writer::{Replace, SingleComponentWriter}, + Component, ComponentKey, ComponentValue, Entity, Error, RelationExt, World, }; use crate::{RelationIter, RelationIterMut}; @@ -106,9 +108,18 @@ impl<'a> EntityRefMut<'a> { /// Set a component for the entity pub fn set(&mut self, component: Component, value: T) -> Option { - let (old, loc) = self.world.set_inner(self.id, component, value).unwrap(); - self.loc = OnceCell::with_value(loc); - old + let mut output = None; + + self.loc = OnceCell::with_value( + self.world + .set_with_writer( + self.id, + SingleComponentWriter::new(component.info(), Replace::new(value, &mut output)), + ) + .unwrap(), + ); + + output } /// Remove a component diff --git a/src/entry.rs b/src/entry.rs index 167f81e4..4ec04b6b 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,6 +1,10 @@ use core::mem; -use crate::{archetype::RefMut, Component, ComponentValue, Entity, World}; +use crate::{ + archetype::RefMut, + writer::{Replace, SingleComponentWriter}, + Component, ComponentValue, Entity, World, +}; /// Entry like api for an entity's component pub enum Entry<'a, T: ComponentValue> { @@ -20,11 +24,20 @@ pub struct VacantEntry<'a, T: ComponentValue> { impl<'a, T: ComponentValue> VacantEntry<'a, T> { /// Insert a value into the entry, returning a mutable reference to it pub fn insert(self, value: T) -> RefMut<'a, T> { - let (old, loc) = self + let loc = self .world - .set_inner(self.id, self.component, value) + .set_with_writer( + self.id, + SingleComponentWriter::new( + self.component.info(), + Replace { + value, + output: &mut None, + }, + ), + ) .expect("Entry is valid"); - assert!(old.is_none()); + self.world.get_mut_at(loc, self.component).unwrap() } } diff --git a/src/world.rs b/src/world.rs index f8ce489a..44d7a7ab 100644 --- a/src/world.rs +++ b/src/world.rs @@ -315,13 +315,6 @@ impl World { loc } - /// Add the components stored in a component buffer to an entity - pub fn set_with(&mut self, id: Entity, buffer: &mut ComponentBuffer) -> Result<()> { - self.set_impl(id, writer::Buffered::new(buffer))?; - - Ok(()) - } - /// Set metadata for a given component if they do not already exist pub(crate) fn init_component(&mut self, info: ComponentInfo) { assert!( @@ -471,18 +464,6 @@ impl World { } } - /// Set the value of a component. - /// If the component does not exist it will be added. - #[inline] - pub fn set( - &mut self, - id: Entity, - component: Component, - value: T, - ) -> Result> { - self.set_inner(id, component, value).map(|v| v.0) - } - /// Updates a component in place pub fn update( &self, @@ -503,6 +484,32 @@ impl World { .ok_or(Error::MissingComponent(id, component.info())) } + /// Set the value of a component. + /// If the component does not exist it will be added. + #[inline] + pub fn set( + &mut self, + id: Entity, + component: Component, + value: T, + ) -> Result> { + let mut output = None; + + self.set_with_writer( + id, + SingleComponentWriter::new(component.info(), Replace::new(value, &mut output)), + )?; + + Ok(output) + } + + /// Add the components stored in a component buffer to an entity + pub fn set_with(&mut self, id: Entity, buffer: &mut ComponentBuffer) -> Result<()> { + self.set_with_writer(id, writer::Buffered::new(buffer))?; + + Ok(()) + } + #[inline] pub(crate) fn set_dyn( &mut self, @@ -510,13 +517,18 @@ impl World { info: ComponentInfo, value: *mut u8, ) -> Result { - let loc = self.set_impl(id, SingleComponentWriter::new(info, ReplaceDyn { value }))?; + let loc = + self.set_with_writer(id, SingleComponentWriter::new(info, ReplaceDyn { value }))?; Ok(loc) } #[inline] - fn set_impl(&mut self, id: Entity, writer: U) -> Result { + pub(crate) fn set_with_writer( + &mut self, + id: Entity, + writer: U, + ) -> Result { // We know things will change either way let change_tick = self.advance_change_tick(); @@ -526,24 +538,6 @@ impl World { Ok(writer.write(self, id, src_loc, change_tick)) } - /// TODO benchmark with fully generic function - #[inline] - pub(crate) fn set_inner( - &mut self, - id: Entity, - component: Component, - value: T, - ) -> Result<(Option, EntityLocation)> { - let mut output = None; - - let loc = self.set_impl( - id, - SingleComponentWriter::new(component.info(), Replace::new(value, &mut output)), - )?; - - Ok((output, loc)) - } - #[inline] pub(crate) fn remove_dyn(&mut self, id: Entity, component: ComponentInfo) -> Result<()> { unsafe { From 56d4efa6515bce811a8139ffd789e572179c58a3 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 23 Jul 2023 16:01:23 +0200 Subject: [PATCH 33/52] feat: EntityRefMut::set_dedup --- src/entity_ref.rs | 58 +++++++++++++++++++++++++++++++++++++++-------- src/writer.rs | 36 +++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/entity_ref.rs b/src/entity_ref.rs index a0c20963..857e1294 100644 --- a/src/entity_ref.rs +++ b/src/entity_ref.rs @@ -13,7 +13,7 @@ use crate::{ error::Result, format::EntityFormatter, name, - writer::{Replace, SingleComponentWriter}, + writer::{EntityWriter, Replace, SingleComponentWriter, WriteDedup}, Component, ComponentKey, ComponentValue, Entity, Error, RelationExt, World, }; use crate::{RelationIter, RelationIterMut}; @@ -110,18 +110,28 @@ impl<'a> EntityRefMut<'a> { pub fn set(&mut self, component: Component, value: T) -> Option { let mut output = None; - self.loc = OnceCell::with_value( - self.world - .set_with_writer( - self.id, - SingleComponentWriter::new(component.info(), Replace::new(value, &mut output)), - ) - .unwrap(), - ); + self.set_with_writer(SingleComponentWriter::new( + component.info(), + Replace::new(value, &mut output), + )); output } + /// Set a component for the entity. + /// + /// Does not trigger a modification event if the value is the same + pub fn set_dedup(&mut self, component: Component, value: T) { + self.set_with_writer(SingleComponentWriter::new( + component.info(), + WriteDedup::new(value), + )); + } + + /// Set a component for the entity + pub(crate) fn set_with_writer(&mut self, writer: W) { + self.loc = OnceCell::with_value(self.world.set_with_writer(self.id, writer).unwrap()); + } /// Remove a component pub fn remove(&mut self, component: Component) -> Result { let mut res: MaybeUninit = MaybeUninit::uninit(); @@ -372,7 +382,7 @@ impl Display for EntityRefMut<'_> { #[cfg(test)] mod test { - use crate::{component, components::name, is_static, EntityBuilder}; + use crate::{component, components::name, is_static, EntityBuilder, FetchExt, Query}; use super::*; @@ -528,4 +538,32 @@ mod test { assert_eq!(entity.get(a()).as_deref(), Ok(&"FooBar".to_string())); assert!(entity.get(b()).is_err()); } + + #[test] + fn set_dedup() { + use alloc::string::{String, ToString}; + component! { + a: String, + b: String, + } + + let mut world = World::new(); + + let mut query = Query::new(a().modified().cloned()); + + let id = EntityBuilder::new() + .set(a(), "Foo".into()) + .spawn(&mut world); + + assert_eq!(query.collect_vec(&world), ["Foo"]); + + let mut entity = world.entity_mut(id).unwrap(); + entity.set_dedup(a(), "Foo".into()); + + assert_eq!(query.collect_vec(&world), [""; 0]); + let mut entity = world.entity_mut(id).unwrap(); + entity.set_dedup(a(), "Bar".into()); + + assert_eq!(query.collect_vec(&world), ["Bar"]); + } } diff --git a/src/writer.rs b/src/writer.rs index 2368a7c4..00f9dcea 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -174,6 +174,42 @@ impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { } } +pub(crate) struct WriteDedup { + pub(crate) value: T, +} + +impl WriteDedup { + pub(crate) fn new(value: T) -> Self { + Self { value } + } +} + +impl ComponentWriter for WriteDedup { + fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32) { + let data = cell.data.get_mut(); + + let storage = data.storage.downcast_mut::(); + let current = &mut storage[slot]; + if current != &self.value { + *current = self.value; + + data.set_modified(&[id], Slice::single(slot), tick); + } + } + + unsafe fn push(mut self, cell: &mut Cell, id: Entity, tick: u32) { + let data = cell.data.get_mut(); + + let slot = data.storage.len(); + + data.storage.extend(&mut self.value as *mut T as *mut u8, 1); + + mem::forget(self.value); + + data.set_added(&[id], Slice::single(slot), tick); + } +} + pub(crate) struct ReplaceDyn { pub(crate) value: *mut u8, } From d42bfc83618abed83c663079aa41927b16625f46 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 23 Jul 2023 20:29:10 +0200 Subject: [PATCH 34/52] feat: update_dedup --- src/archetype/mod.rs | 23 +++--- src/archetype/storage.rs | 1 + src/entity_ref.rs | 88 +++++++++++++++++---- src/entry.rs | 10 +-- src/world.rs | 45 ++++++++--- src/writer.rs | 167 ++++++++++++++++++++++++++++----------- 6 files changed, 238 insertions(+), 96 deletions(-) diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 1d82795e..1a46cf12 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -10,6 +10,7 @@ use itertools::Itertools; use crate::{ events::{EventData, EventKind, EventSubscriber}, + writer::ComponentUpdater, Component, ComponentInfo, ComponentKey, ComponentValue, Entity, }; @@ -525,30 +526,24 @@ impl Archetype { /// Get a component from the entity at `slot` #[inline] - pub fn update( + pub(crate) fn update( &self, slot: Slot, component: Component, - change_tick: u32, - f: impl FnOnce(&mut T) -> U, - ) -> Option { + writer: U, + tick: u32, + ) -> Option { let cell = self.cells.get(&component.key())?; let mut data = cell.data.borrow_mut(); - // Safety - // Component - let value = unsafe { &mut *(data.storage.at_mut(slot)? as *mut T) }; - let value = (f)(value); + let res = unsafe { writer.update(&mut data, slot, self.entities[slot], tick) }; - // TODO: fix deliberate bug - data.set_modified(&self.entities[slot..slot], Slice::single(slot), change_tick); - - Some(value) + Some(res) } /// Get a component from the entity at `slot`. - pub fn get( + pub(crate) fn get( &self, slot: Slot, component: Component, @@ -558,7 +553,7 @@ impl Archetype { } /// Get a component from the entity at `slot`. - pub fn try_get( + pub(crate) fn try_get( &self, slot: Slot, component: Component, diff --git a/src/archetype/storage.rs b/src/archetype/storage.rs index a42e7875..122634a9 100644 --- a/src/archetype/storage.rs +++ b/src/archetype/storage.rs @@ -250,6 +250,7 @@ impl Storage { self.cap } + #[inline] pub(crate) fn info(&self) -> ComponentInfo { self.info } diff --git a/src/entity_ref.rs b/src/entity_ref.rs index 857e1294..0485f3ff 100644 --- a/src/entity_ref.rs +++ b/src/entity_ref.rs @@ -13,7 +13,7 @@ use crate::{ error::Result, format::EntityFormatter, name, - writer::{EntityWriter, Replace, SingleComponentWriter, WriteDedup}, + writer::{EntityWriter, FnWriter, Replace, SingleComponentWriter, WriteDedup}, Component, ComponentKey, ComponentValue, Entity, Error, RelationExt, World, }; use crate::{RelationIter, RelationIterMut}; @@ -65,7 +65,22 @@ impl<'a> EntityRefMut<'a> { ) -> Option { let loc = self.loc(); let arch = self.world.archetypes.get(loc.arch_id); - arch.update(loc.slot, component, self.world.advance_change_tick(), f) + let tick = self.world.advance_change_tick(); + + arch.update(loc.slot, component, FnWriter::new(f), tick) + } + + /// Updates a component in place + pub fn update_dedup( + &self, + component: Component, + value: T, + ) -> Option<()> { + let loc = self.loc(); + let arch = self.world.archetypes.get(loc.arch_id); + let tick = self.world.advance_change_tick(); + + arch.update(loc.slot, component, WriteDedup::new(value), tick) } /// Attempt concurrently access a component mutably using and fail if the component is already borrowed @@ -108,14 +123,11 @@ impl<'a> EntityRefMut<'a> { /// Set a component for the entity pub fn set(&mut self, component: Component, value: T) -> Option { - let mut output = None; - self.set_with_writer(SingleComponentWriter::new( component.info(), - Replace::new(value, &mut output), - )); - - output + Replace::new(value), + )) + .left() } /// Set a component for the entity. @@ -129,9 +141,12 @@ impl<'a> EntityRefMut<'a> { } /// Set a component for the entity - pub(crate) fn set_with_writer(&mut self, writer: W) { - self.loc = OnceCell::with_value(self.world.set_with_writer(self.id, writer).unwrap()); + pub(crate) fn set_with_writer(&mut self, writer: W) -> W::Output { + let (loc, res) = self.world.set_with_writer(self.id, writer).unwrap(); + self.loc = OnceCell::with_value(loc); + res } + /// Remove a component pub fn remove(&mut self, component: Component) -> Result { let mut res: MaybeUninit = MaybeUninit::uninit(); @@ -279,8 +294,22 @@ impl<'a> EntityRef<'a> { component: Component, f: impl FnOnce(&mut T) -> U, ) -> Option { + let change_tick = self.world.advance_change_tick(); + + self.arch + .update(self.slot, component, FnWriter::new(f), change_tick) + } + + /// Updates a component in place + pub fn update_dedup( + &self, + component: Component, + value: T, + ) -> Option<()> { + let tick = self.world.advance_change_tick(); + self.arch - .update(self.slot, component, self.world.advance_change_tick(), f) + .update(self.slot, component, WriteDedup::new(value), tick) } /// Attempt concurrently access a component mutably using and fail if the component is already borrowed @@ -509,8 +538,12 @@ mod test { let entity = world.entity(id).unwrap(); + let mut query = Query::new(a().modified().cloned()); + assert_eq!(query.collect_vec(&world), ["Foo"]); assert_eq!(entity.update(a(), |v| v.push_str("Bar")), Some(())); + assert_eq!(query.collect_vec(&world), ["FooBar"]); assert_eq!(entity.update(b(), |v| v.push('_')), None); + assert!(query.collect_vec(&world).is_empty()); assert_eq!(entity.get(a()).as_deref(), Ok(&"FooBar".to_string())); assert!(entity.get(b()).is_err()); @@ -541,10 +574,9 @@ mod test { #[test] fn set_dedup() { - use alloc::string::{String, ToString}; + use alloc::string::String; component! { a: String, - b: String, } let mut world = World::new(); @@ -560,10 +592,38 @@ mod test { let mut entity = world.entity_mut(id).unwrap(); entity.set_dedup(a(), "Foo".into()); - assert_eq!(query.collect_vec(&world), [""; 0]); + assert!(query.collect_vec(&world).is_empty()); let mut entity = world.entity_mut(id).unwrap(); entity.set_dedup(a(), "Bar".into()); assert_eq!(query.collect_vec(&world), ["Bar"]); } + + #[test] + fn update_dedup() { + use alloc::string::String; + component! { + a: String, + } + + let mut world = World::new(); + + let mut query = Query::new(a().modified().cloned()); + + let id = EntityBuilder::new() + .set(a(), "Foo".into()) + .spawn(&mut world); + + assert_eq!(query.collect_vec(&world), ["Foo"]); + + let entity = world.entity_mut(id).unwrap(); + entity.update_dedup(a(), "Foo".into()); + + assert!(query.collect_vec(&world).is_empty()); + + let entity = world.entity_mut(id).unwrap(); + entity.update_dedup(a(), "Bar".into()); + + assert_eq!(query.collect_vec(&world), ["Bar"]); + } } diff --git a/src/entry.rs b/src/entry.rs index 4ec04b6b..9d2f9a3f 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -24,17 +24,11 @@ pub struct VacantEntry<'a, T: ComponentValue> { impl<'a, T: ComponentValue> VacantEntry<'a, T> { /// Insert a value into the entry, returning a mutable reference to it pub fn insert(self, value: T) -> RefMut<'a, T> { - let loc = self + let (loc, value) = self .world .set_with_writer( self.id, - SingleComponentWriter::new( - self.component.info(), - Replace { - value, - output: &mut None, - }, - ), + SingleComponentWriter::new(self.component.info(), Replace { value }), ) .expect("Entry is valid"); diff --git a/src/world.rs b/src/world.rs index 44d7a7ab..1fcad818 100644 --- a/src/world.rs +++ b/src/world.rs @@ -26,7 +26,9 @@ use crate::{ format::{EntitiesFormatter, HierarchyFormatter, WorldFormatter}, is_static, relation::Relation, - writer::{self, EntityWriter, Replace, ReplaceDyn, SingleComponentWriter}, + writer::{ + self, EntityWriter, FnWriter, Replace, ReplaceDyn, SingleComponentWriter, WriteDedup, + }, ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; @@ -480,7 +482,27 @@ impl World { self.archetypes .get(src_id) - .update(slot, component, change_tick, f) + .update(slot, component, FnWriter::new(f), change_tick) + .ok_or(Error::MissingComponent(id, component.info())) + } + + /// Updates a component in place + pub fn update_dedup( + &self, + id: Entity, + component: Component, + value: T, + ) -> Result<()> { + let tick = self.advance_change_tick(); + + let EntityLocation { + arch_id: src_id, + slot, + } = self.location(id)?; + + self.archetypes + .get(src_id) + .update(slot, component, WriteDedup::new(value), tick) .ok_or(Error::MissingComponent(id, component.info())) } @@ -493,14 +515,13 @@ impl World { component: Component, value: T, ) -> Result> { - let mut output = None; - - self.set_with_writer( - id, - SingleComponentWriter::new(component.info(), Replace::new(value, &mut output)), - )?; - - Ok(output) + Ok(self + .set_with_writer( + id, + SingleComponentWriter::new(component.info(), Replace::new(value)), + )? + .1 + .left()) } /// Add the components stored in a component buffer to an entity @@ -517,7 +538,7 @@ impl World { info: ComponentInfo, value: *mut u8, ) -> Result { - let loc = + let (loc, _) = self.set_with_writer(id, SingleComponentWriter::new(info, ReplaceDyn { value }))?; Ok(loc) @@ -528,7 +549,7 @@ impl World { &mut self, id: Entity, writer: U, - ) -> Result { + ) -> Result<(EntityLocation, U::Output)> { // We know things will change either way let change_tick = self.advance_change_tick(); diff --git a/src/writer.rs b/src/writer.rs index 00f9dcea..178805a6 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,9 +1,9 @@ use core::{mem, ptr, slice}; -use itertools::Itertools; +use itertools::{Either, Itertools}; use crate::{ - archetype::{Cell, Slice, Slot}, + archetype::{CellData, Slice, Slot}, buffer::ComponentBuffer, entity::EntityLocation, metadata::exclusive, @@ -12,21 +12,68 @@ use crate::{ }; /// Describes a modification to the components of an entity within the context of an archetype -pub(crate) trait ComponentWriter { +pub(crate) trait ComponentUpdater { + type Updated; /// Performs write operations against the target entity - fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32); /// # Safety /// - /// The cell **must** be extended with valid component data for the new entity - unsafe fn push(self, cell: &mut Cell, id: Entity, tick: u32); + /// The provided `data` must be of the same type as the cell data and what will be + /// written using `self` + unsafe fn update(self, data: &mut CellData, slot: Slot, id: Entity, tick: u32) + -> Self::Updated; +} + +pub(crate) trait ComponentPusher { + type Pushed; + /// # Safety + /// + /// The cell **must** be extended with valid component data for the new entity. + /// + /// The type of `data` must match that of `self` + unsafe fn push(self, data: &mut CellData, id: Entity, tick: u32) -> Self::Pushed; +} + +pub(crate) struct FnWriter { + func: F, + _marker: core::marker::PhantomData, +} + +impl FnWriter { + pub(crate) fn new(func: F) -> Self { + Self { + func, + _marker: core::marker::PhantomData, + } + } +} + +impl ComponentUpdater for FnWriter +where + F: FnOnce(&mut T) -> U, +{ + type Updated = U; + + unsafe fn update(self, data: &mut CellData, slot: Slot, id: Entity, tick: u32) -> U { + let value = &mut *(data.storage.at_mut(slot).unwrap() as *mut T); + let res = (self.func)(value); + + data.set_modified(&[id], Slice::single(slot), tick); + res + } } /// # Safety /// /// The entity must be fully initialized and all bookkepping updated pub unsafe trait EntityWriter { - fn write(self, world: &mut World, id: Entity, loc: EntityLocation, tick: u32) - -> EntityLocation; + type Output; + fn write( + self, + world: &mut World, + id: Entity, + loc: EntityLocation, + tick: u32, + ) -> (EntityLocation, Self::Output); } pub(crate) struct SingleComponentWriter { @@ -40,22 +87,29 @@ impl SingleComponentWriter { } } -unsafe impl EntityWriter for SingleComponentWriter { +unsafe impl EntityWriter for SingleComponentWriter { + type Output = Either; + fn write( self, world: &mut World, id: Entity, src_loc: EntityLocation, tick: u32, - ) -> EntityLocation { + ) -> (EntityLocation, Self::Output) { let key = self.info.key(); let arch = world.archetypes.get_mut(src_loc.arch_id); if let Some(cell) = arch.cell_mut(key) { - self.writer.update(cell, src_loc.slot, id, tick); - return src_loc; + let res = unsafe { + self.writer + .update(cell.data.get_mut(), src_loc.slot, id, tick) + }; + + return (src_loc, Either::Left(res)); } + let (src, dst, dst_id) = if let Some(&dst_id) = arch.outgoing.get(&key) { eprintln!("Outgoing edge: {:?}", self.info); @@ -106,14 +160,15 @@ unsafe impl EntityWriter for SingleComponentWriter { unsafe { src.move_to(dst, src_loc.slot, |c, ptr| c.drop(ptr), tick) }; // Insert the missing component - unsafe { + let pushed = unsafe { let cell = dst .cell_mut(key) .expect("Missing component in new archetype"); - cell.data.get_mut().storage.reserve(1); - self.writer.push(cell, id, tick); - } + let data = cell.data.get_mut(); + + self.writer.push(data, id, tick) + }; let dst_loc = EntityLocation { arch_id: dst_id, @@ -122,7 +177,7 @@ unsafe impl EntityWriter for SingleComponentWriter { update_entity_loc(world, id, dst_loc, swapped); - dst_loc + (dst_loc, Either::Right(pushed)) } } @@ -138,32 +193,33 @@ pub(crate) unsafe trait MigrateEntity { ) -> (EntityLocation, Option<(Entity, Slot)>); } -pub(crate) struct Replace<'a, T: ComponentValue> { +pub(crate) struct Replace { pub(crate) value: T, - pub(crate) output: &'a mut Option, } -impl<'a, T: ComponentValue> Replace<'a, T> { - pub(crate) fn new(value: T, output: &'a mut Option) -> Self { - Self { value, output } +impl Replace { + pub(crate) fn new(value: T) -> Self { + Self { value } } } -impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { - fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32) { - let data = cell.data.get_mut(); +impl ComponentUpdater for Replace { + type Updated = T; + unsafe fn update(self, data: &mut CellData, slot: Slot, id: Entity, tick: u32) -> T { let storage = data.storage.downcast_mut::(); let old = mem::replace(&mut storage[slot], self.value); data.set_modified(&[id], Slice::single(slot), tick); - *self.output = Some(old); + old } +} - unsafe fn push(mut self, cell: &mut Cell, id: Entity, tick: u32) { - let data = cell.data.get_mut(); +impl ComponentPusher for Replace { + type Pushed = (); + unsafe fn push(mut self, data: &mut CellData, id: Entity, tick: u32) { let slot = data.storage.len(); data.storage.extend(&mut self.value as *mut T as *mut u8, 1); @@ -174,6 +230,16 @@ impl<'a, T: ComponentValue> ComponentWriter for Replace<'a, T> { } } +pub(crate) struct Insert { + pub(crate) value: T, +} + +impl Insert { + pub(crate) fn new(value: T) -> Self { + Self { value } + } +} + pub(crate) struct WriteDedup { pub(crate) value: T, } @@ -184,10 +250,10 @@ impl WriteDedup { } } -impl ComponentWriter for WriteDedup { - fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32) { - let data = cell.data.get_mut(); +impl ComponentUpdater for WriteDedup { + type Updated = (); + unsafe fn update(self, data: &mut CellData, slot: Slot, id: Entity, tick: u32) { let storage = data.storage.downcast_mut::(); let current = &mut storage[slot]; if current != &self.value { @@ -196,10 +262,12 @@ impl ComponentWriter for WriteDedup { data.set_modified(&[id], Slice::single(slot), tick); } } +} - unsafe fn push(mut self, cell: &mut Cell, id: Entity, tick: u32) { - let data = cell.data.get_mut(); +impl ComponentPusher for WriteDedup { + type Pushed = (); + unsafe fn push(mut self, data: &mut CellData, id: Entity, tick: u32) { let slot = data.storage.len(); data.storage.extend(&mut self.value as *mut T as *mut u8, 1); @@ -214,12 +282,11 @@ pub(crate) struct ReplaceDyn { pub(crate) value: *mut u8, } -impl ComponentWriter for ReplaceDyn { - fn update(self, cell: &mut Cell, slot: Slot, id: Entity, tick: u32) { - let info = cell.info(); - - let data = cell.data.get_mut(); +impl ComponentUpdater for ReplaceDyn { + type Updated = (); + unsafe fn update(self, data: &mut CellData, slot: Slot, id: Entity, tick: u32) { + let info = data.storage.info(); unsafe { let dst = data.storage.at_mut(slot).unwrap(); @@ -230,10 +297,12 @@ impl ComponentWriter for ReplaceDyn { data.set_modified(&[id], Slice::single(slot), tick); } +} - unsafe fn push(self, cell: &mut Cell, id: Entity, tick: u32) { - let data = cell.data.get_mut(); +impl ComponentPusher for ReplaceDyn { + type Pushed = (); + unsafe fn push(self, data: &mut CellData, id: Entity, tick: u32) { let slot = data.storage.len(); data.storage.extend(self.value, 1); @@ -241,24 +310,26 @@ impl ComponentWriter for ReplaceDyn { } } -pub(crate) struct Buffered<'a> { - pub(crate) buffer: &'a mut ComponentBuffer, +pub(crate) struct Buffered<'b> { + pub(crate) buffer: &'b mut ComponentBuffer, } -impl<'a> Buffered<'a> { - pub(crate) fn new(buffer: &'a mut ComponentBuffer) -> Self { +impl<'b> Buffered<'b> { + pub(crate) fn new(buffer: &'b mut ComponentBuffer) -> Self { Self { buffer } } } -unsafe impl<'a> EntityWriter for Buffered<'a> { +unsafe impl<'b> EntityWriter for Buffered<'b> { + type Output = (); + fn write( self, world: &mut World, id: Entity, src_loc: EntityLocation, tick: u32, - ) -> EntityLocation { + ) -> (EntityLocation, ()) { let mut exclusive_relations = Vec::new(); let arch = world.archetypes.get_mut(src_loc.arch_id); @@ -295,7 +366,7 @@ unsafe impl<'a> EntityWriter for Buffered<'a> { if self.buffer.is_empty() { eprintln!("Archetype fully matched"); - return src_loc; + return (src_loc, ()); } // Add the existing components, making sure new exclusive relations are favored @@ -335,7 +406,7 @@ unsafe impl<'a> EntityWriter for Buffered<'a> { update_entity_loc(world, id, dst_loc, swapped); world.archetypes.prune_arch(src_loc.arch_id); - dst_loc + (dst_loc, ()) } } From 084c8184869611da9ff0de22b7b101576f6dbc0f Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 23 Jul 2023 20:50:43 +0200 Subject: [PATCH 35/52] chore: cleanup --- src/archetype/guard.rs | 18 ------------------ src/archetype/mod.rs | 36 ++++++++---------------------------- src/archetypes.rs | 14 -------------- src/entry.rs | 2 +- src/query/searcher.rs | 1 - src/world.rs | 1 - src/writer.rs | 26 ++------------------------ 7 files changed, 11 insertions(+), 87 deletions(-) diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index d04b4c6e..dccd114c 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -48,12 +48,6 @@ impl<'a, T: ?Sized> CellMutGuard<'a, T> { .set_modified_if_tracking(Change::new(slots, tick)); } - pub(crate) fn changes_mut(&mut self) -> &mut Changes { - // SAFETY: `value` is not accessed in this function - - &mut self.data.changes - } - pub(crate) fn filter_map( mut self, f: impl FnOnce(&mut T) -> Option<&mut U>, @@ -113,18 +107,6 @@ impl<'a, T: ?Sized> CellGuard<'a, T> { AtomicRef::map(self.data, |_| unsafe { self.storage.as_ref() }) } - pub(crate) fn filter_map( - self, - f: impl FnOnce(&T) -> Option<&U>, - ) -> Option> { - let storage = NonNull::from(f(unsafe { self.storage.as_ref() })?); - - Some(CellGuard { - data: self.data, - storage, - }) - } - #[inline] pub(crate) fn changes(&self) -> &Changes { &self.data.changes diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 1a46cf12..ee3ea24d 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -120,20 +120,6 @@ impl CellData { self.changes.set_inserted(Change::new(slice, change_tick)); } - - /// **Note**: must be called *before* data is dropped - /// Sets the specified entities and slots as modified and invokes subscribers - /// **Note**: `ids` must be the slice of entities pointed to by `slice` - pub(crate) fn set_removed(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { - let component = self.key; - self.on_event(EventData { - ids, - key: component, - kind: EventKind::Added, - }); - - self.changes.set_inserted(Change::new(slice, change_tick)); - } } /// Stores a list of component values, changes, and subscribers @@ -263,15 +249,15 @@ impl Cell { CellMutGuard::new(self.data.borrow_mut()) } - #[inline] - pub fn try_borrow(&self) -> Result, BorrowError> { - Ok(CellGuard::new(self.data.try_borrow()?)) - } + // #[inline] + // pub fn try_borrow(&self) -> Result, BorrowError> { + // Ok(CellGuard::new(self.data.try_borrow()?)) + // } - #[inline] - pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { - Ok(CellMutGuard::new(self.data.try_borrow_mut()?)) - } + // #[inline] + // pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { + // Ok(CellMutGuard::new(self.data.try_borrow_mut()?)) + // } #[inline] pub fn get_mut<'a, T: ComponentValue>( @@ -282,11 +268,6 @@ impl Cell { ) -> Option> { RefMut::new(self.borrow_mut(), entities, slot, tick) } - - #[inline] - pub(crate) fn info(&self) -> ComponentInfo { - self.info - } } // #[derive(Debug)] @@ -980,7 +961,6 @@ impl Archetype { } pub(crate) fn remove_link(&mut self, component: ComponentKey) { - eprintln!("Removing link for {:?}", component); let linked = self.outgoing.remove(&component); assert!(linked.is_some()); diff --git a/src/archetypes.rs b/src/archetypes.rs index e3442738..f4878d36 100644 --- a/src/archetypes.rs +++ b/src/archetypes.rs @@ -1,5 +1,4 @@ use alloc::{sync::Arc, vec::Vec}; -use itertools::Itertools; use crate::{ archetype::Archetype, @@ -65,21 +64,9 @@ impl Archetypes { } let arch = self.inner.despawn(arch_id).unwrap(); - eprintln!( - "Despawned archetype: {} components: {:?}, incoming: {:?}", - arch_id, - arch.components().collect_vec(), - arch.incoming - ); - for (&key, &dst_id) in &arch.incoming { let dst = self.get_mut(dst_id); - eprintln!("Removing incoming link from {key}: {dst_id}"); dst.remove_link(key); - eprintln!( - "Links: children: {:?} outgoing: {:?}", - dst.children, dst.outgoing - ); self.prune_arch(dst_id); } @@ -135,7 +122,6 @@ impl Archetypes { let new_id = self.inner.spawn(new); let (cur, new) = self.inner.get_disjoint(cursor, new_id).unwrap(); - eprintln!("Spawning child {new_id} from {cursor} for {head:?}"); cur.add_child(head.key, new_id); new.add_incoming(head.key, cursor); diff --git a/src/entry.rs b/src/entry.rs index 9d2f9a3f..720962e7 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -24,7 +24,7 @@ pub struct VacantEntry<'a, T: ComponentValue> { impl<'a, T: ComponentValue> VacantEntry<'a, T> { /// Insert a value into the entry, returning a mutable reference to it pub fn insert(self, value: T) -> RefMut<'a, T> { - let (loc, value) = self + let (loc, _) = self .world .set_with_writer( self.id, diff --git a/src/query/searcher.rs b/src/query/searcher.rs index b3cb8c39..66266dbd 100644 --- a/src/query/searcher.rs +++ b/src/query/searcher.rs @@ -43,7 +43,6 @@ pub(crate) fn traverse_archetypes<'a>( result(cur, arch); for &arch_id in arch.children.values() { - eprintln!("Traversing child {} from {}", arch_id, cur); traverse_archetypes(archetypes, arch_id, required, result); } } diff --git a/src/world.rs b/src/world.rs index 1fcad818..a94e390e 100644 --- a/src/world.rs +++ b/src/world.rs @@ -555,7 +555,6 @@ impl World { let src_loc = self.init_location(id)?; - eprintln!("loc: {src_loc:?}"); Ok(writer.write(self, id, src_loc, change_tick)) } diff --git a/src/writer.rs b/src/writer.rs index 178805a6..af2b62a0 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,5 +1,6 @@ use core::{mem, ptr, slice}; +use alloc::vec::Vec; use itertools::{Either, Itertools}; use crate::{ @@ -111,8 +112,6 @@ unsafe impl EntityWriter for SingleCompon } let (src, dst, dst_id) = if let Some(&dst_id) = arch.outgoing.get(&key) { - eprintln!("Outgoing edge: {:?}", self.info); - let (src, dst) = world .archetypes .get_disjoint(src_loc.arch_id, dst_id) @@ -120,13 +119,6 @@ unsafe impl EntityWriter for SingleCompon (src, dst, dst_id) } else { // Oh no! The archetype is missing the component - - eprintln!( - "Missing component: {:?} found:{:?}", - self.info, - arch.components().collect_vec() - ); - let exclusive = if self.info.meta_ref().has(exclusive()) { slice::from_ref(&self.info.key.id) } else { @@ -149,8 +141,6 @@ unsafe impl EntityWriter for SingleCompon if superset && src_loc.arch_id != reserved_id { src.add_outgoing(key, dst_id); dst.add_incoming(key, src_loc.arch_id); - } else { - eprintln!("Not a superset") } (src, dst, dst_id) @@ -230,16 +220,6 @@ impl ComponentPusher for Replace { } } -pub(crate) struct Insert { - pub(crate) value: T, -} - -impl Insert { - pub(crate) fn new(value: T) -> Self { - Self { value } - } -} - pub(crate) struct WriteDedup { pub(crate) value: T, } @@ -365,7 +345,6 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { } if self.buffer.is_empty() { - eprintln!("Archetype fully matched"); return (src_loc, ()); } @@ -377,7 +356,6 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { ); for &info in self.buffer.components() { - eprintln!("Initializing component {:?}", info); world.init_component(info); } @@ -430,5 +408,5 @@ fn find_archetype_components( .sorted_unstable() .collect_vec(); - dbg!(res, superset) + (res, superset) } From b81cb96569c8160948ffc9c8dc9ccec14646a6fe Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 30 Jul 2023 13:24:38 +0200 Subject: [PATCH 36/52] feat: inserted transform --- flax-derive/src/lib.rs | 33 ++++++--- guide/src/query/change_detection.md | 8 +-- src/component.rs | 9 +-- src/fetch/ext.rs | 19 ++++- src/fetch/transform.rs | 105 +++++++++++++++++++++++++++- src/lib.rs | 2 +- 6 files changed, 148 insertions(+), 28 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 6f717417..cda936b3 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -59,7 +59,7 @@ fn derive_data_struct( let union_derive = derive_union(¶ms); - let transform_modified = derive_modified(¶ms); + let transforms_derive = derive_transform(¶ms); Ok(quote! { #fetch_derive @@ -68,7 +68,7 @@ fn derive_data_struct( #union_derive - #transform_modified + #transforms_derive }) } syn::Fields::Unnamed(_) => Err(Error::new( @@ -200,7 +200,7 @@ fn derive_union(params: &Params) -> TokenStream { } /// Implements the filtering of the struct fields using a set union -fn derive_modified(params: &Params) -> TokenStream { +fn derive_transform(params: &Params) -> TokenStream { let Params { crate_name, vis, @@ -236,9 +236,10 @@ fn derive_modified(params: &Params) -> TokenStream { let prepared = derive_prepared_struct(&transformed_params); let union = derive_union(&transformed_params); - let transform_modified = if attrs.transforms.contains(&TransformIdent::Modified) { - let trait_name = - quote! { #crate_name::fetch::TransformFetch<#crate_name::fetch::Modified> }; + let transforms = attrs.transforms.iter().map(|method| { + let method = method.to_tokens(crate_name); + + let trait_name = quote! { #crate_name::fetch::TransformFetch<#method> }; quote! { @@ -246,16 +247,14 @@ fn derive_modified(params: &Params) -> TokenStream { impl #trait_name for #fetch_name { type Output = #crate_name::filter::Union<#transformed_name<#(<#field_types as #trait_name>::Output,)*>>; - fn transform_fetch(self, method: #crate_name::fetch::Modified) -> Self::Output { + fn transform_fetch(self, method: #method) -> Self::Output { #crate_name::filter::Union(#transformed_name { #(#field_names: <#field_types as #trait_name>::transform_fetch(self.#field_names, method),)* }) } } } - } else { - quote! {} - }; + }).collect_vec(); quote! { #input @@ -266,7 +265,7 @@ fn derive_modified(params: &Params) -> TokenStream { #union - #transform_modified + #(#transforms)* } } @@ -487,6 +486,16 @@ impl<'a> Params<'a> { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] enum TransformIdent { Modified, + Inserted, +} + +impl TransformIdent { + fn to_tokens(&self, crate_name: &Ident) -> TokenStream { + match self { + Self::Modified => quote!(#crate_name::fetch::transform::Modified), + Self::Inserted => quote!(#crate_name::fetch::transform::Inserted), + } + } } impl Parse for TransformIdent { @@ -494,6 +503,8 @@ impl Parse for TransformIdent { let ident = input.parse::()?; if ident == "Modified" { Ok(Self::Modified) + } else if ident == "Inserted" { + Ok(Self::Inserted) } else { Err(Error::new( ident.span(), diff --git a/guide/src/query/change_detection.md b/guide/src/query/change_detection.md index b7a5c79b..e1363f22 100644 --- a/guide/src/query/change_detection.md +++ b/guide/src/query/change_detection.md @@ -2,7 +2,7 @@ Flax tracks when a component is added, mutably accessed, or removed. -Queries allow filtering on change events since the query last run. +A query allows filtering the entities based on a change event since it last ran. - [`modified`](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) filter mutated or new components - [`inserted`](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) only new components @@ -16,17 +16,13 @@ for each entity. **Note**: Tuple queries combine using `and`, which means a query with multiple `modified` or other change filtered components will only yield if **all** the annotated components changed since the last query ran. -Prefer using `.filter(Or(a().modified, b().modified()))` when dealing with multiple -change filters, or splitting up the query. - ```rust {{ #include ../../../examples/guide/change_detection.rs:health_changes }} ``` # Combining filters -Change filters can be combined with other filters, which leads to queries which -do even less work than that particular group member. +Change filters can be combined with other filters, which leads to queries needing to perform even even less work. The following example creates a query which removes despawns entities when their health becomes `0`. Noteworthy in particular, is that this system can run in diff --git a/src/component.rs b/src/component.rs index 10501081..a0c1e8c2 100644 --- a/src/component.rs +++ b/src/component.rs @@ -261,13 +261,8 @@ impl Component { } /// Construct a fine grained change detection filter. - pub fn modified(self) -> ChangeFilter { - ChangeFilter::new(self, ChangeKind::Modified) - } - - /// Construct a fine grained insert detection filter. - pub fn inserted(self) -> ChangeFilter { - ChangeFilter::new(self, ChangeKind::Inserted) + pub(crate) fn into_change_filter(self, kind: ChangeKind) -> ChangeFilter { + ChangeFilter::new(self, kind) } /// Construct a fine grained component remove detection filter. diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index c2a86955..884e25e6 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -9,6 +9,7 @@ use super::{ copied::Copied, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, + transform::Inserted, Map, Modified, Satisfied, Source, TransformFetch, }; @@ -135,7 +136,8 @@ pub trait FetchExt: Sized { Source::new(self, FromRelation::new(relation)) } - /// Transform the fetch into a fetch where each constituent part tracks and yields for changes. + /// Transform the fetch into a fetch where each constituent part tracks and yields for + /// modification events. /// /// This is different from E.g; `(a().modified(), b().modified())` as it implies only when /// *both* `a` and `b` are modified in the same iteration, which is seldom useful. @@ -150,6 +152,21 @@ pub trait FetchExt: Sized { self.transform_fetch(Modified) } + /// Transform the fetch into a fetch where each constituent part tracks and yields for insert + /// events. + /// + /// This is different from E.g; `(a().modified(), b().modified())` as it implies only when + /// *both* `a` and `b` are modified in the same iteration, which is seldom useful. + /// + /// This means will yield *any* of `a` *or* `b` are modified. + /// + /// Works with `opt`, `copy`, etc constituents. + fn inserted(self) -> >::Output + where + Self: TransformFetch, + { + self.transform_fetch(Inserted) + } /// Map each item of the query to another type using the provided function. fn map(self, func: F) -> Map where diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index f63cfc2e..4642f61a 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -1,4 +1,6 @@ -use crate::{filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch}; +use crate::{ + archetype::ChangeKind, filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch, +}; /// Allows transforming a fetch into another. /// @@ -16,14 +18,24 @@ pub trait TransformFetch: for<'w> Fetch<'w> { impl TransformFetch for Component { type Output = ChangeFilter; fn transform_fetch(self, _: Modified) -> Self::Output { - self.modified() + self.into_change_filter(ChangeKind::Modified) } } +impl TransformFetch for Component { + type Output = ChangeFilter; + fn transform_fetch(self, _: Inserted) -> Self::Output { + self.into_change_filter(ChangeKind::Inserted) + } +} /// Marker for a fetch which has been transformed to filter modified items. #[derive(Debug, Clone, Copy)] pub struct Modified; +/// Marker for a fetch which has been transformed to filter inserted items. +#[derive(Debug, Clone, Copy)] +pub struct Inserted; + macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { @@ -32,6 +44,13 @@ macro_rules! tuple_impl { Union(($(self.$idx.transform_fetch(method),)*)) } } + + impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { + type Output = Union<($($ty::Output,)*)>; + fn transform_fetch(self, method: Inserted) -> Self::Output { + Union(($(self.$idx.transform_fetch(method),)*)) + } + } }; } @@ -209,4 +228,86 @@ mod tests { assert_eq!(query.collect_vec(&world), [(id3, (-1, ":P".to_string()))]); } + + #[test] + #[cfg(feature = "derive")] + fn query_inserted_struct() { + use crate::{fetch::Cloned, Component, Fetch}; + + component! { + a: i32, + b: String, + other: (), + } + + #[derive(Fetch)] + #[fetch(item_derives = [Debug], transforms = [Modified, Inserted])] + struct MyFetch { + a: Component, + b: Cloned>, + } + + let mut world = World::new(); + + let id1 = Entity::builder() + .set(a(), 0) + .set(b(), "Hello".into()) + .spawn(&mut world); + + let id2 = Entity::builder() + .set(a(), 1) + .set(b(), "World".into()) + .spawn(&mut world); + + let id3 = Entity::builder() + // .set(a(), 0) + .set(b(), "There".into()) + .spawn(&mut world); + + // Force to a different archetype + let id4 = Entity::builder() + .set(a(), 2) + .set(b(), "!".into()) + .tag(other()) + .spawn(&mut world); + + let query = MyFetch { + a: a(), + b: b().cloned(), + } + .inserted() + .map(|v| (*v.a, v.b)); + + let mut query = Query::new((entity_ids(), query)); + + assert_eq!( + query.collect_vec(&world), + [ + (id1, (0, "Hello".to_string())), + (id2, (1, "World".to_string())), + (id4, (2, "!".to_string())) + ] + ); + + assert_eq!(query.collect_vec(&world), []); + + assert_eq!(query.collect_vec(&world), []); + + world.remove(id2, a()).unwrap(); + + assert_eq!(query.collect_vec(&world), []); + + world.set(id2, a(), 5).unwrap(); + + assert_eq!(query.collect_vec(&world), [(id2, (5, "World".to_string()))]); + + // Adding the required component to id3 will cause it to be picked up by the query + let mut cmd = CommandBuffer::new(); + cmd.set(id3, a(), -1).apply(&mut world).unwrap(); + + assert_eq!( + query.collect_vec(&world), + [(id3, (-1, "There".to_string()))] + ); + } } diff --git a/src/lib.rs b/src/lib.rs index 8963f4ae..488d4da2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! Flax is a performant and easy to use Entity Component System. //! -//! The world is organized by simple identifiers known as an [Entity](https://docs.rs/flax/latest/flax/entity/struct.Entity.html), which can have any number of components attached to them. +//! The world is organized by simple identifiers known as an [`Entity`](https://docs.rs/flax/latest/flax/entity/struct.Entity.html), which can have any number of components attached to them. //! //! Systems operate on the world's entities and provide the application logic. //! From 73302d6ac77221ce1b57ef638458dd0f3570cbbf Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 30 Jul 2023 13:41:36 +0200 Subject: [PATCH 37/52] fix: rename inserted to added --- README.md | 2 +- examples/guide/change_detection.rs | 9 ++++++--- flax-derive/src/lib.rs | 8 ++++---- guide/src/diving_deeper/query.md | 2 +- guide/src/fundamentals/query.md | 4 ++-- guide/src/query/change_detection.md | 11 +++++------ src/archetype/changes.rs | 14 +++++++------- src/archetype/mod.rs | 2 +- src/fetch/ext.rs | 8 ++++---- src/fetch/transform.rs | 20 ++++++++++---------- src/filter/change.rs | 2 +- src/filter/cmp.rs | 18 +++++++++++++++++- src/filter/mod.rs | 2 +- src/world.rs | 2 +- tests/filter.rs | 2 +- 15 files changed, 62 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 981e8c91..5ab3e31c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Flax is a performant and easy to use Entity Component System. -The world is organized by simple identifiers known as an [Entity](https://docs.rs/flax/latest/flax/entity/struct.Entity.html), which can have any number of components attached to them. +The world is organized by simple identifiers known as an [`Entity`](https://docs.rs/flax/latest/flax/entity/struct.Entity.html), which can have any number of components attached to them. Systems operate on the world's entities and provide the application logic. diff --git a/examples/guide/change_detection.rs b/examples/guide/change_detection.rs index 814f40c8..30dfc222 100644 --- a/examples/guide/change_detection.rs +++ b/examples/guide/change_detection.rs @@ -91,18 +91,19 @@ fn main() { // ANCHOR: cleanup_system - let query = Query::new((entity_ids(), player().satisfied())).filter(health().le(0.0)); + let query = Query::new((name().opt(), entity_ids(), player().satisfied())) + .filter(health().le(0.0).modified()); let cleanup = System::builder() .with_name("cleanup") .with(query) .write::() .build(|mut q: QueryBorrow<_, _>, cmd: &mut CommandBuffer| { - for (id, is_player) in &mut q { + for (name, id, is_player) in &mut q { if is_player { tracing::info!("Player died"); } - tracing::info!(is_player, "Despawning {id}"); + tracing::info!(name, is_player, "Despawning {id}"); cmd.despawn(id); } }); @@ -115,6 +116,7 @@ fn main() { .with_system(damage_random) .with_system(update_poison) .with_system(health_changes) + .flush() .with_system(cleanup) .flush(); @@ -122,6 +124,7 @@ fn main() { schedule .execute_par(&mut world) .expect("Failed to run schedule"); + sleep(Duration::from_millis(1000)); } diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index cda936b3..2f8dfe80 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -486,14 +486,14 @@ impl<'a> Params<'a> { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] enum TransformIdent { Modified, - Inserted, + Added, } impl TransformIdent { fn to_tokens(&self, crate_name: &Ident) -> TokenStream { match self { Self::Modified => quote!(#crate_name::fetch::transform::Modified), - Self::Inserted => quote!(#crate_name::fetch::transform::Inserted), + Self::Added => quote!(#crate_name::fetch::transform::Added), } } } @@ -503,8 +503,8 @@ impl Parse for TransformIdent { let ident = input.parse::()?; if ident == "Modified" { Ok(Self::Modified) - } else if ident == "Inserted" { - Ok(Self::Inserted) + } else if ident == "Added" { + Ok(Self::Added) } else { Err(Error::new( ident.span(), diff --git a/guide/src/diving_deeper/query.md b/guide/src/diving_deeper/query.md index daf108c9..f6ac07bb 100644 --- a/guide/src/diving_deeper/query.md +++ b/guide/src/diving_deeper/query.md @@ -40,7 +40,7 @@ This combinator is useful when writing systems which may need to operate on enti Every time a component is modified, either through [`World::get_mut`](https://docs.rs/flax/latest/flax/struct.World#method.get_mut), or a query, a `Modified` event is added to the affected entities. -Similarly, `set` when the component did not previously exist, and new entities will create an `Inserted` event. +Similarly, `set` when the component did not previously exist, and new entities will create an `Added` event. `Removal` events are created by [`World::remove`](https://docs.rs/flax/latest/flax/struct.World#method.remove). diff --git a/guide/src/fundamentals/query.md b/guide/src/fundamentals/query.md index c22ee7af..6f315b4d 100644 --- a/guide/src/fundamentals/query.md +++ b/guide/src/fundamentals/query.md @@ -75,8 +75,8 @@ instead. ### Change detection -- [modified](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) yields components which have been updated **or** inserted. -- [inserted](https://docs.rs/flax/latest/flax/struct.Component.html#method.inserted) yields new components. +- [modified](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) yields components which have been updated **or** added. +- [inserted](https://docs.rs/flax/latest/flax/struct.Component.html#method.added) yields new components. - [removed](https://docs.rs/flax/latest/flax/struct.Component.html#method.removed) yields each entity for which the component was recently removed. All change detection is per query and based on when the query last executed. diff --git a/guide/src/query/change_detection.md b/guide/src/query/change_detection.md index e1363f22..4eaa2a2b 100644 --- a/guide/src/query/change_detection.md +++ b/guide/src/query/change_detection.md @@ -4,18 +4,18 @@ Flax tracks when a component is added, mutably accessed, or removed. A query allows filtering the entities based on a change event since it last ran. -- [`modified`](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) filter mutated or new components -- [`inserted`](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) only new components -- [`removed`](https://docs.rs/flax/latest/flax/struct.Component.html#method.modified) filter recently removed components. +- [`modified`](https://docs.rs/flax/latest/flax/trait.FetchExt.html#method.modified) filter mutated or new components +- [`added`](https://docs.rs/flax/latest/flax/trait.FetchExt.html#method.added) only new components +- [`removed`](https://docs.rs/flax/latest/flax/trait.FetchExt.html#method.removed) filter recently removed components. The modified filter is best used for queries which calculate or update a value based on one or more components, or in other ways react to a changed value. +A change filter can be added to a single component, or to a tuple of components. Applying a `.modified()` transform on a tuple will create a query which yields if *any* of the constituents were modified. + The following example creates a system which prints the updated health values for each entity. -**Note**: Tuple queries combine using `and`, which means a query with multiple `modified` or other change filtered components will only yield if **all** the annotated components changed since the last query ran. - ```rust {{ #include ../../../examples/guide/change_detection.rs:health_changes }} ``` @@ -33,7 +33,6 @@ mutable access. {{ #include ../../../examples/guide/change_detection.rs:cleanup_system }} ``` - # Bringing it all together In order for the health monitoring and cleanup systems to be effective, there diff --git a/src/archetype/changes.rs b/src/archetype/changes.rs index 959a81a1..49bed5a9 100644 --- a/src/archetype/changes.rs +++ b/src/archetype/changes.rs @@ -327,8 +327,8 @@ impl DerefMut for ChangeList { pub(crate) enum ChangeKind { /// Component was modified Modified = 0, - /// Component was inserted - Inserted = 1, + /// Component was added + Added = 1, /// Component was removed Removed = 2, } @@ -337,7 +337,7 @@ impl Display for ChangeKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { ChangeKind::Modified => f.write_str("modified"), - ChangeKind::Inserted => f.write_str("inserted"), + ChangeKind::Added => f.write_str("inserted"), ChangeKind::Removed => f.write_str("removed"), } } @@ -414,8 +414,8 @@ impl Changes { } #[inline] - pub(crate) fn set_inserted(&mut self, change: Change) -> &mut Self { - self.map[ChangeKind::Inserted as usize].set(change); + pub(crate) fn set_added(&mut self, change: Change) -> &mut Self { + self.map[ChangeKind::Added as usize].set(change); self.map[ChangeKind::Modified as usize].set(change); self } @@ -449,7 +449,7 @@ impl Changes { mut on_removed: impl FnMut(ChangeKind, Change), ) { self.map[0].swap_remove_with(slot, dst, |v| on_removed(ChangeKind::Modified, v)); - self.map[1].swap_remove_with(slot, dst, |v| on_removed(ChangeKind::Inserted, v)); + self.map[1].swap_remove_with(slot, dst, |v| on_removed(ChangeKind::Added, v)); self.map[2].swap_remove_with(slot, dst, |v| on_removed(ChangeKind::Removed, v)); } @@ -460,7 +460,7 @@ impl Changes { mut f: impl FnMut(ChangeKind, &mut ChangeList, &mut ChangeList), ) { f(ChangeKind::Modified, &mut self.map[0], &mut other.map[0]); - f(ChangeKind::Inserted, &mut self.map[1], &mut other.map[1]); + f(ChangeKind::Added, &mut self.map[1], &mut other.map[1]); f(ChangeKind::Removed, &mut self.map[2], &mut other.map[2]); } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index ee3ea24d..7ce90f6f 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -118,7 +118,7 @@ impl CellData { kind: EventKind::Added, }); - self.changes.set_inserted(Change::new(slice, change_tick)); + self.changes.set_added(Change::new(slice, change_tick)); } } diff --git a/src/fetch/ext.rs b/src/fetch/ext.rs index 884e25e6..0aa87507 100644 --- a/src/fetch/ext.rs +++ b/src/fetch/ext.rs @@ -9,7 +9,7 @@ use super::{ copied::Copied, opt::{Opt, OptOr}, source::{FetchSource, FromRelation}, - transform::Inserted, + transform::Added, Map, Modified, Satisfied, Source, TransformFetch, }; @@ -161,11 +161,11 @@ pub trait FetchExt: Sized { /// This means will yield *any* of `a` *or* `b` are modified. /// /// Works with `opt`, `copy`, etc constituents. - fn inserted(self) -> >::Output + fn added(self) -> >::Output where - Self: TransformFetch, + Self: TransformFetch, { - self.transform_fetch(Inserted) + self.transform_fetch(Added) } /// Map each item of the query to another type using the provided function. fn map(self, func: F) -> Map diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index 4642f61a..c7fe4b52 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -6,11 +6,11 @@ use crate::{ /// /// For example transforming a tuple or struct fetch into a modified filtering fetch. /// The generic signifies a marker to use for transforming -pub trait TransformFetch: for<'w> Fetch<'w> { +pub trait TransformFetch { /// The transformed type. /// /// May of may not have the same `Item` - type Output: for<'w> Fetch<'w>; + type Output; /// Transform the fetch using the provided method fn transform_fetch(self, method: Method) -> Self::Output; } @@ -22,10 +22,10 @@ impl TransformFetch for Component { } } -impl TransformFetch for Component { +impl TransformFetch for Component { type Output = ChangeFilter; - fn transform_fetch(self, _: Inserted) -> Self::Output { - self.into_change_filter(ChangeKind::Inserted) + fn transform_fetch(self, _: Added) -> Self::Output { + self.into_change_filter(ChangeKind::Added) } } /// Marker for a fetch which has been transformed to filter modified items. @@ -34,7 +34,7 @@ pub struct Modified; /// Marker for a fetch which has been transformed to filter inserted items. #[derive(Debug, Clone, Copy)] -pub struct Inserted; +pub struct Added; macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { @@ -45,9 +45,9 @@ macro_rules! tuple_impl { } } - impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { + impl<$($ty: TransformFetch,)*> TransformFetch for ($($ty,)*) { type Output = Union<($($ty::Output,)*)>; - fn transform_fetch(self, method: Inserted) -> Self::Output { + fn transform_fetch(self, method: Added) -> Self::Output { Union(($(self.$idx.transform_fetch(method),)*)) } } @@ -241,7 +241,7 @@ mod tests { } #[derive(Fetch)] - #[fetch(item_derives = [Debug], transforms = [Modified, Inserted])] + #[fetch(item_derives = [Debug], transforms = [Modified, Added])] struct MyFetch { a: Component, b: Cloned>, @@ -275,7 +275,7 @@ mod tests { a: a(), b: b().cloned(), } - .inserted() + .added() .map(|v| (*v.a, v.b)); let mut query = Query::new((entity_ids(), query)); diff --git a/src/filter/change.rs b/src/filter/change.rs index 0fcbceaf..ce5d5580 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -13,7 +13,7 @@ use crate::{ static EMPTY_CHANGELIST: ChangeList = ChangeList::new(); #[derive(Clone)] -/// Filter which only yields modified or inserted components +/// Filter which only yields for change events pub struct ChangeFilter { component: Component, kind: ChangeKind, diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index 4f8ab5b6..4213134e 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -16,7 +16,9 @@ use alloc::vec::Vec; use crate::{ archetype::{Slice, Slot}, - fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, ReadOnlyFetch}, + fetch::{ + FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, ReadOnlyFetch, TransformFetch, + }, system::Access, Fetch, FetchItem, }; @@ -211,6 +213,20 @@ where } } +impl TransformFetch for Cmp +where + F: TransformFetch, +{ + type Output = Cmp; + + fn transform_fetch(self, method: K) -> Self::Output { + Cmp { + fetch: self.fetch.transform_fetch(method), + method: self.method, + } + } +} + #[cfg(test)] mod test { use alloc::string::ToString; diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 7bc12577..cb5ad407 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -698,7 +698,7 @@ mod tests { .changes_mut(a().key()) .unwrap() .set_modified(Change::new(Slice::new(9, 80), 2)) - .set_inserted(Change::new(Slice::new(65, 83), 4)) + .set_added(Change::new(Slice::new(65, 83), 4)) .get(ChangeKind::Modified) .as_changed_set(1); diff --git a/src/world.rs b/src/world.rs index a94e390e..736b2ddf 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1097,7 +1097,7 @@ impl World { /// /// `other` will be left empty /// - /// **Note**: The data from `other` will all be marked as `inserted` + /// **Note**: The data from `other` will all be marked as *added* /// as change events do not carry over. pub fn merge_with(&mut self, other: &mut World) -> MigratedEntities { let mut archetypes = mem::replace(&mut other.archetypes, Archetypes::new()); diff --git a/tests/filter.rs b/tests/filter.rs index 14294887..f987fc61 100644 --- a/tests/filter.rs +++ b/tests/filter.rs @@ -68,7 +68,7 @@ fn filters() { // Construct a new interted query - let mut query = Query::new(a().cloned()).filter(a().inserted()); + let mut query = Query::new(a().cloned()).filter(a().added()); let items = query .borrow(&world) From d77418eb17b4936a9d1129ab397555c0724c02f3 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 30 Jul 2023 14:14:26 +0200 Subject: [PATCH 38/52] feat: make entity errors more specific --- src/entity/builder.rs | 7 ++- src/entity_ref.rs | 99 +++++++++++++++++++++++++++++++---------- src/error.rs | 41 ++++++++++++++--- src/fetch/transform.rs | 2 +- src/lib.rs | 2 +- src/query/entity.rs | 9 ++-- src/query/mod.rs | 7 ++- src/query/planar.rs | 6 ++- src/world.rs | 48 +++++++++++++++----- tests/components.rs | 6 ++- tests/entity.rs | 10 ++++- tests/entity_builder.rs | 22 ++++++--- 12 files changed, 201 insertions(+), 58 deletions(-) diff --git a/src/entity/builder.rs b/src/entity/builder.rs index 8955dcb9..6aee782d 100644 --- a/src/entity/builder.rs +++ b/src/entity/builder.rs @@ -207,7 +207,7 @@ impl From<&mut EntityBuilder> for EntityBuilder { #[cfg(test)] mod test { - use crate::*; + use crate::{error::MissingComponent, *}; #[test] fn builder() { @@ -242,7 +242,10 @@ mod test { assert_eq!(world.get(id, health()).as_deref(), Ok(&50.0)); assert_eq!( world.get(id, is_enemy()).as_deref(), - Err(&Error::MissingComponent(id, is_enemy().info())) + Err(&Error::MissingComponent(MissingComponent { + id, + info: is_enemy().info() + })) ); } } diff --git a/src/entity_ref.rs b/src/entity_ref.rs index 0485f3ff..1c561567 100644 --- a/src/entity_ref.rs +++ b/src/entity_ref.rs @@ -10,11 +10,11 @@ use crate::{ archetype::{Archetype, RefMut, Slot}, entity::EntityLocation, entry::{Entry, OccupiedEntry, VacantEntry}, - error::Result, + error::MissingComponent, format::EntityFormatter, name, writer::{EntityWriter, FnWriter, Replace, SingleComponentWriter, WriteDedup}, - Component, ComponentKey, ComponentValue, Entity, Error, RelationExt, World, + Component, ComponentKey, ComponentValue, Entity, RelationExt, World, }; use crate::{RelationIter, RelationIterMut}; @@ -30,21 +30,36 @@ pub struct EntityRefMut<'a> { impl<'a> EntityRefMut<'a> { /// Access a component - pub fn get(&self, component: Component) -> Result> { + pub fn get( + &self, + component: Component, + ) -> Result, MissingComponent> { self.world .get_at(self.loc(), component) - .ok_or_else(|| Error::MissingComponent(self.id, component.info())) + .ok_or_else(|| MissingComponent { + id: self.id, + info: component.info(), + }) } /// Access a component mutably - pub fn get_mut(&self, component: Component) -> Result> { + pub fn get_mut( + &self, + component: Component, + ) -> Result, MissingComponent> { self.world .get_mut_at(self.loc(), component) - .ok_or_else(|| Error::MissingComponent(self.id, component.info())) + .ok_or_else(|| MissingComponent { + id: self.id, + info: component.info(), + }) } /// Shorthand to copy and not use a borrowing references - pub fn get_copy(&self, component: Component) -> Result { + pub fn get_copy( + &self, + component: Component, + ) -> Result { self.get(component).map(|v| *v) } @@ -62,12 +77,16 @@ impl<'a> EntityRefMut<'a> { &self, component: Component, f: impl FnOnce(&mut T) -> U, - ) -> Option { + ) -> Result { let loc = self.loc(); let arch = self.world.archetypes.get(loc.arch_id); let tick = self.world.advance_change_tick(); arch.update(loc.slot, component, FnWriter::new(f), tick) + .ok_or(MissingComponent { + id: self.id, + info: component.info(), + }) } /// Updates a component in place @@ -75,12 +94,16 @@ impl<'a> EntityRefMut<'a> { &self, component: Component, value: T, - ) -> Option<()> { + ) -> Result<(), MissingComponent> { let loc = self.loc(); let arch = self.world.archetypes.get(loc.arch_id); let tick = self.world.advance_change_tick(); arch.update(loc.slot, component, WriteDedup::new(value), tick) + .ok_or(MissingComponent { + id: self.id, + info: component.info(), + }) } /// Attempt concurrently access a component mutably using and fail if the component is already borrowed @@ -148,12 +171,18 @@ impl<'a> EntityRefMut<'a> { } /// Remove a component - pub fn remove(&mut self, component: Component) -> Result { + pub fn remove( + &mut self, + component: Component, + ) -> Result { let mut res: MaybeUninit = MaybeUninit::uninit(); let (old, loc) = unsafe { - let loc = self.world.remove_inner(self.id, component.info(), |ptr| { - res.write(ptr.cast::().read()); - })?; + let loc = self + .world + .remove_inner(self.id, component.info(), |ptr| { + res.write(ptr.cast::().read()); + }) + .map_err(|v| v.try_into_missing_component().unwrap())?; (res.assume_init(), loc) }; @@ -264,21 +293,36 @@ pub struct EntityRef<'a> { impl<'a> EntityRef<'a> { /// Access a component - pub fn get(&self, component: Component) -> Result> { + pub fn get( + &self, + component: Component, + ) -> Result, MissingComponent> { self.arch .get(self.slot, component) - .ok_or_else(|| Error::MissingComponent(self.id, component.info())) + .ok_or_else(|| MissingComponent { + id: self.id, + info: component.info(), + }) } /// Access a component mutably - pub fn get_mut(&self, component: Component) -> Result> { + pub fn get_mut( + &self, + component: Component, + ) -> Result, MissingComponent> { self.arch .get_mut(self.slot, component, self.world.advance_change_tick()) - .ok_or_else(|| Error::MissingComponent(self.id, component.info())) + .ok_or_else(|| MissingComponent { + id: self.id, + info: component.info(), + }) } /// Shorthand to copy and not use a borrowing references - pub fn get_copy(&self, component: Component) -> Result { + pub fn get_copy( + &self, + component: Component, + ) -> Result { self.get(component).map(|v| *v) } @@ -439,7 +483,10 @@ mod test { assert_eq!( res.as_deref(), - Err(&Error::MissingComponent(id, is_static().info())) + Err(&MissingComponent { + id, + info: is_static().info() + }) ) } @@ -565,8 +612,14 @@ mod test { let entity = world.entity_mut(id).unwrap(); - assert_eq!(entity.update(a(), |v| v.push_str("Bar")), Some(())); - assert_eq!(entity.update(b(), |v| v.push('_')), None); + assert_eq!(entity.update(a(), |v| v.push_str("Bar")), Ok(())); + assert_eq!( + entity.update(b(), |v| v.push('_')), + Err(MissingComponent { + id, + info: b().info() + }) + ); assert_eq!(entity.get(a()).as_deref(), Ok(&"FooBar".to_string())); assert!(entity.get(b()).is_err()); @@ -617,12 +670,12 @@ mod test { assert_eq!(query.collect_vec(&world), ["Foo"]); let entity = world.entity_mut(id).unwrap(); - entity.update_dedup(a(), "Foo".into()); + let _ = entity.update_dedup(a(), "Foo".into()); assert!(query.collect_vec(&world).is_empty()); let entity = world.entity_mut(id).unwrap(); - entity.update_dedup(a(), "Bar".into()); + let _ = entity.update_dedup(a(), "Bar".into()); assert_eq!(query.collect_vec(&world), ["Bar"]); } diff --git a/src/error.rs b/src/error.rs index c8bbfa26..7d72c145 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,7 +9,7 @@ pub enum Error { /// The requested entity did not exist NoSuchEntity(Entity), /// The entity did not have the specified component - MissingComponent(Entity, ComponentInfo), + MissingComponent(MissingComponent), /// A query for a specific entity failed due to an unsatisfied filter DoesNotMatch(Entity), /// The entity did not match the filter predicate @@ -21,7 +21,7 @@ pub enum Error { } impl Error { - /// Convert the error into an anyhow report, regardlees of [std::error::Error] or not. + /// Convert the error into an anyhow report, regardles of [std::error::Error] or not. pub(crate) fn into_anyhow(self) -> anyhow::Error { #[cfg(not(feature = "std"))] return anyhow::Error::msg(self); @@ -29,6 +29,29 @@ impl Error { #[cfg(feature = "std")] return anyhow::Error::new(self); } + + pub(crate) fn try_into_missing_component(self) -> std::result::Result { + if let Self::MissingComponent(v) = self { + Ok(v) + } else { + Err(self) + } + } +} + +impl From for Error { + fn from(value: MissingComponent) -> Self { + Self::MissingComponent(value) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +/// Missing component +pub struct MissingComponent { + /// The entity which did not have the component + pub id: Entity, + /// The missing component + pub info: ComponentInfo, } /// Result alias for [crate::error::Result] @@ -41,9 +64,7 @@ impl Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Error::NoSuchEntity(id) => write!(f, "Entity {id} does not exist"), - Error::MissingComponent(id, name) => { - write!(f, "Entity {id} does not have the component {name:?}") - } + Error::MissingComponent(inner) => Display::fmt(inner, f), Error::DoesNotMatch(id) => { write!(f, "Entity {id} did not match the query") } @@ -60,3 +81,13 @@ impl Display for Error { } } } + +impl Display for MissingComponent { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Entity {} does not have the component {:?}", + self.id, self.info + ) + } +} diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index c7fe4b52..18c8a39a 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -1,5 +1,5 @@ use crate::{ - archetype::ChangeKind, filter::ChangeFilter, filter::Union, Component, ComponentValue, Fetch, + archetype::ChangeKind, filter::ChangeFilter, filter::Union, Component, ComponentValue, }; /// Allows transforming a fetch into another. diff --git a/src/lib.rs b/src/lib.rs index 488d4da2..386fd626 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! Flax is a performant and easy to use Entity Component System. +//! Flax is a performant and ergonomic Entity Component System. //! //! The world is organized by simple identifiers known as an [`Entity`](https://docs.rs/flax/latest/flax/entity/struct.Entity.html), which can have any number of components attached to them. //! diff --git a/src/query/entity.rs b/src/query/entity.rs index 4e9df741..e28eb4cf 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use crate::{ archetype::Slice, entity::EntityLocation, - error::Result, + error::{MissingComponent, Result}, fetch::{FetchAccessData, PreparedFetch}, filter::{All, Filtered}, system::{Access, AccessKind}, @@ -32,7 +32,7 @@ fn state<'w, 'a, Q: Fetch<'w>, F: Fetch<'w>>( let Some(mut p) = state.prepare_fetch(loc.arch_id, arch) else { return match find_missing_components(state.fetch, loc.arch_id, state.world).next() { - Some(missing) => Err(Error::MissingComponent(id, missing)), + Some(missing) => Err(Error::MissingComponent(MissingComponent{id,info: missing})), None => Err(Error::DoesNotMatch(id)), } }; @@ -156,7 +156,10 @@ mod test { world.remove(id, name()).unwrap(); assert_eq!( query.borrow(&world).get(), - Err(Error::MissingComponent(id, name().info())) + Err(Error::MissingComponent(MissingComponent { + id, + info: name().info() + })) ); world.set(id, name(), "Bar".into()).unwrap(); { diff --git a/src/query/mod.rs b/src/query/mod.rs index 6522f84f..142998b5 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -322,7 +322,7 @@ where mod test { use pretty_assertions::assert_eq; - use crate::{filter::Or, name, Entity, Error, FetchExt, Query}; + use crate::{error::MissingComponent, filter::Or, name, Entity, Error, FetchExt, Query}; use super::*; @@ -396,7 +396,10 @@ mod test { assert_eq!( borrow.get(id4), - Err(Error::MissingComponent(id4, b().info())) + Err(Error::MissingComponent(MissingComponent { + id: id4, + info: b().info() + })) ); } diff --git a/src/query/planar.rs b/src/query/planar.rs index a49db0af..250652b4 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -5,7 +5,7 @@ use smallvec::SmallVec; use crate::{ archetype::Slice, entity::EntityLocation, - error::Result, + error::{MissingComponent, Result}, fetch::{FetchAccessData, PreparedFetch}, filter::{All, Filtered}, system::{Access, AccessKind}, @@ -276,7 +276,9 @@ where let idx = self.prepare_archetype(arch_id).ok_or_else(|| { match find_missing_components(self.state.fetch, arch_id, self.state.world).next() { - Some(missing) => Error::MissingComponent(id, missing), + Some(missing) => { + Error::MissingComponent(MissingComponent { id, info: missing }) + } None => Error::DoesNotMatch(id), } })?; diff --git a/src/world.rs b/src/world.rs index 736b2ddf..a611e277 100644 --- a/src/world.rs +++ b/src/world.rs @@ -20,7 +20,7 @@ use crate::{ entity::{entity_ids, Entity, EntityIndex, EntityKind, EntityLocation, EntityStore}, entity_ref::{EntityRef, EntityRefMut}, entry::{Entry, OccupiedEntry, VacantEntry}, - error::Result, + error::{MissingComponent, Result}, events::EventSubscriber, filter::{ArchetypeFilter, StaticFilter}, format::{EntitiesFormatter, HierarchyFormatter, WorldFormatter}, @@ -483,7 +483,10 @@ impl World { self.archetypes .get(src_id) .update(slot, component, FnWriter::new(f), change_tick) - .ok_or(Error::MissingComponent(id, component.info())) + .ok_or(Error::MissingComponent(MissingComponent { + id, + info: component.info(), + })) } /// Updates a component in place @@ -503,7 +506,10 @@ impl World { self.archetypes .get(src_id) .update(slot, component, WriteDedup::new(value), tick) - .ok_or(Error::MissingComponent(id, component.info())) + .ok_or(Error::MissingComponent(MissingComponent { + id, + info: component.info(), + })) } /// Set the value of a component. @@ -580,7 +586,10 @@ impl World { let src = self.archetypes.get(src_id); if !src.has(component.key()) { - return Err(Error::MissingComponent(id, component)); + return Err(Error::MissingComponent(MissingComponent { + id, + info: component, + })); } let dst_id = match src.incoming(component.key()) { @@ -662,8 +671,12 @@ impl World { ) -> Result> { let loc = self.location(id)?; - self.get_at(loc, component) - .ok_or_else(|| Error::MissingComponent(id, component.info())) + self.get_at(loc, component).ok_or_else(|| { + Error::MissingComponent(MissingComponent { + id, + info: component.info(), + }) + }) } #[inline] @@ -697,8 +710,12 @@ impl World { ) -> Result> { let loc = self.location(id)?; - self.get_mut_at(loc, component) - .ok_or_else(|| Error::MissingComponent(id, component.info())) + self.get_mut_at(loc, component).ok_or_else(|| { + Error::MissingComponent(MissingComponent { + id, + info: component.info(), + }) + }) } /// Randomly access an entity's component. @@ -1366,7 +1383,10 @@ mod tests { assert_eq!(world.get(id, a()).as_deref(), Ok(&65)); assert_eq!( world.get(id, b()).as_deref(), - Err(&Error::MissingComponent(id, b().info())) + Err(&Error::MissingComponent(MissingComponent { + id, + info: b().info() + })) ); assert!(!world.has(id, c())); @@ -1380,7 +1400,10 @@ mod tests { assert_eq!(world.get(id, a()).as_deref(), Ok(&65)); assert_eq!( world.get(id, b()).as_deref(), - Err(&Error::MissingComponent(id, b().info())) + Err(&Error::MissingComponent(MissingComponent { + id, + info: b().info() + })) ); assert!(!world.has(id, c())); @@ -1451,7 +1474,10 @@ mod tests { assert_eq!(world.get(id, c()).as_deref(), Ok(&"Foo".into())); assert_eq!( world.get(id, e()).as_deref(), - Err(&Error::MissingComponent(id, e().info())) + Err(&Error::MissingComponent(MissingComponent { + id, + info: e().info() + })) ); world.despawn(id).unwrap(); diff --git a/tests/components.rs b/tests/components.rs index 5b842413..bf5d4278 100644 --- a/tests/components.rs +++ b/tests/components.rs @@ -1,5 +1,6 @@ use flax::{ buffer::ComponentBuffer, + error::MissingComponent, metadata::Metadata, vtable::{ComponentVTable, LazyComponentBuffer}, *, @@ -32,6 +33,9 @@ fn custom_component() { assert_eq!( world.get(id, position).as_deref(), - Err(&Error::MissingComponent(id, position.info())), + Err(&Error::MissingComponent(MissingComponent { + id, + info: position.info() + })), ); } diff --git a/tests/entity.rs b/tests/entity.rs index d07f597e..8c3eebd2 100644 --- a/tests/entity.rs +++ b/tests/entity.rs @@ -70,7 +70,10 @@ fn entity_ref() { #[test] #[cfg(feature = "flume")] fn entity_hierarchy() { - use flax::events::{Event, EventSubscriber}; + use flax::{ + error::MissingComponent, + events::{Event, EventSubscriber}, + }; use itertools::Itertools; use pretty_assertions::assert_eq; @@ -133,7 +136,10 @@ fn entity_hierarchy() { assert_eq!(entity.get(name()).as_deref(), Ok(&"root".to_string())); assert_eq!( entity.get(a()).as_deref(), - Err(&flax::Error::MissingComponent(id, a().info())) + Err(&MissingComponent { + id, + info: a().info() + }) ); assert_eq!(rx.drain().collect_vec(), []); diff --git a/tests/entity_builder.rs b/tests/entity_builder.rs index b18164e4..2cb8d791 100644 --- a/tests/entity_builder.rs +++ b/tests/entity_builder.rs @@ -1,6 +1,6 @@ extern crate alloc; use alloc::string::String; -use flax::{component, CommandBuffer, Entity, Error, Exclusive, World}; +use flax::{component, error::MissingComponent, CommandBuffer, Entity, Error, Exclusive, World}; use std::sync::Arc; component! { @@ -28,7 +28,10 @@ fn entity_builder() { assert_eq!(world.get(id2, a()).as_deref(), Ok(&2)); assert_eq!( world.get(id2, b()).as_deref(), - Err(&Error::MissingComponent(id2, b().info())) + Err(&Error::MissingComponent(MissingComponent { + id: id2, + info: b().info() + })) ); let value = Arc::new(()); @@ -51,7 +54,10 @@ fn entity_builder() { assert_eq!(world.get(id3, relation(id1)).as_deref(), Ok(&value)); assert_eq!( world.get(id3, relation(id2)).as_deref(), - Err(&Error::MissingComponent(id3, relation(id2).info())) + Err(&Error::MissingComponent(MissingComponent { + id: id3, + info: relation(id2).info() + })) ); world.despawn(id3).unwrap(); @@ -76,7 +82,10 @@ fn entity_builder_cmd() { assert_eq!(world.get(id2, a()).as_deref(), Ok(&2)); assert_eq!( world.get(id2, b()).as_deref(), - Err(&Error::MissingComponent(id2, b().info())) + Err(&Error::MissingComponent(MissingComponent { + id: id2, + info: b().info() + })) ); let value = Arc::new(()); @@ -97,7 +106,10 @@ fn entity_builder_cmd() { assert_eq!(world.get(id3, relation(id1)).as_deref(), Ok(&value)); assert_eq!( world.get(id3, relation(id2)).as_deref(), - Err(&Error::MissingComponent(id3, relation(id2).info())) + Err(&Error::MissingComponent(MissingComponent { + id: id3, + info: relation(id2).info() + })) ); assert_eq!(Arc::strong_count(&value), 2); From 251a28be213c6e865b457d1798f944e1e35abf71 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 30 Jul 2023 14:14:42 +0200 Subject: [PATCH 39/52] chore: sync readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ab3e31c..f94f61af 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ -Flax is a performant and easy to use Entity Component System. +Flax is a performant and ergonomic Entity Component System. The world is organized by simple identifiers known as an [`Entity`](https://docs.rs/flax/latest/flax/entity/struct.Entity.html), which can have any number of components attached to them. From 77c09e8c6593868f612a6edaa7a1bb4587af45c8 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 30 Jul 2023 15:01:56 +0200 Subject: [PATCH 40/52] chore: ComponentInfo => ComponentDesc When used as an argument, `info` gives the wrong semantic meaning. description makes it more clear what it *describes* --- examples/guide/dynamic_components.rs | 8 +-- src/archetype/batch.rs | 14 ++-- src/archetype/mod.rs | 74 +++++++++------------ src/archetype/storage.rs | 72 ++++++++++----------- src/archetypes.rs | 4 +- src/buffer.rs | 72 ++++++++++----------- src/commands.rs | 28 ++++---- src/component.rs | 32 ++++----- src/components.rs | 4 +- src/entity/builder.rs | 8 +-- src/entity_ref.rs | 22 +++---- src/entry.rs | 2 +- src/error.rs | 6 +- src/events.rs | 16 ++--- src/fetch/component_mut.rs | 12 ---- src/fetch/relations.rs | 2 +- src/filter/mod.rs | 2 +- src/format.rs | 8 +-- src/lib.rs | 2 +- src/macros.rs | 26 ++++---- src/metadata/debuggable.rs | 4 +- src/metadata/mod.rs | 8 +-- src/metadata/relation.rs | 2 +- src/query/difference.rs | 4 +- src/query/entity.rs | 4 +- src/query/mod.rs | 2 +- src/query/planar.rs | 2 +- src/serialize/de.rs | 26 ++++---- src/system/mod.rs | 4 +- src/vtable.rs | 14 ++-- src/world.rs | 97 ++++++++++++++-------------- src/writer.rs | 48 +++++++------- tests/components.rs | 6 +- tests/entity.rs | 2 +- tests/entity_builder.rs | 8 +-- 35 files changed, 310 insertions(+), 335 deletions(-) diff --git a/examples/guide/dynamic_components.rs b/examples/guide/dynamic_components.rs index 2f2714e6..de91e779 100644 --- a/examples/guide/dynamic_components.rs +++ b/examples/guide/dynamic_components.rs @@ -10,9 +10,9 @@ fn main() -> anyhow::Result<()> { let mut world = World::new(); - let position: Component = world.spawn_component("position", |info| { + let position: Component = world.spawn_component("position", |desc| { let mut buf = ComponentBuffer::new(); - >::attach(info, &mut buf); + >::attach(desc, &mut buf); buf }); @@ -39,9 +39,9 @@ fn main() -> anyhow::Result<()> { distance: f32, } - let child_of = world.spawn_relation::("child_of", |info| { + let child_of = world.spawn_relation::("child_of", |desc| { let mut buf = ComponentBuffer::new(); - >::attach(info, &mut buf); + >::attach(desc, &mut buf); buf }); diff --git a/src/archetype/batch.rs b/src/archetype/batch.rs index d0d9587c..0f36c77a 100644 --- a/src/archetype/batch.rs +++ b/src/archetype/batch.rs @@ -2,7 +2,7 @@ use core::mem; use alloc::{collections::BTreeMap, vec::Vec}; -use crate::{error::Result, Component, ComponentInfo, ComponentKey, ComponentValue, Entity, Error}; +use crate::{error::Result, Component, ComponentDesc, ComponentKey, ComponentValue, Entity, Error}; use super::Storage; @@ -23,8 +23,8 @@ impl BatchSpawn { } /// Returns the components in the batch - pub fn components(&self) -> impl Iterator + '_ { - self.storage.values().map(|v| v.info()) + pub fn components(&self) -> impl Iterator + '_ { + self.storage.values().map(|v| v.desc()) } /// Returns the number of entities in the batch @@ -45,8 +45,8 @@ impl BatchSpawn { component: Component, iter: impl IntoIterator, ) -> Result<&mut Self> { - let info = component.info(); - let mut storage = Storage::with_capacity(info, self.len); + let desc = component.desc(); + let mut storage = Storage::with_capacity(desc, self.len); for item in iter.into_iter().take(self.len) { // Type gurangeed by the component @@ -61,11 +61,11 @@ impl BatchSpawn { /// Inserts a storage directly pub(crate) fn append(&mut self, storage: Storage) -> Result<()> { - let info = storage.info(); + let desc = storage.desc(); if storage.len() != self.len { Err(Error::IncompleteBatch) } else { - self.storage.insert(info.key(), storage); + self.storage.insert(desc.key(), storage); Ok(()) } } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 7ce90f6f..0cbcc813 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -11,7 +11,7 @@ use itertools::Itertools; use crate::{ events::{EventData, EventKind, EventSubscriber}, writer::ComponentUpdater, - Component, ComponentInfo, ComponentKey, ComponentValue, Entity, + Component, ComponentDesc, ComponentKey, ComponentValue, Entity, }; /// Unique archetype id @@ -61,7 +61,7 @@ impl StorageInfo { #[derive(Default, Clone)] pub struct ArchetypeInfo { storage: Vec, - components: Vec, + components: Vec, entities: usize, } @@ -81,7 +81,7 @@ impl ArchetypeInfo { } /// Returns the components in the archetype - pub fn components(&self) -> &[ComponentInfo] { + pub fn components(&self) -> &[ComponentDesc] { self.components.as_ref() } } @@ -125,19 +125,19 @@ impl CellData { /// Stores a list of component values, changes, and subscribers pub(crate) struct Cell { pub(crate) data: AtomicRefCell, - info: ComponentInfo, + desc: ComponentDesc, } impl Cell { - pub(crate) fn new(info: ComponentInfo) -> Self { + pub(crate) fn new(desc: ComponentDesc) -> Self { Self { data: AtomicRefCell::new(CellData { - storage: Storage::new(info), + storage: Storage::new(desc), changes: Changes::new(), subscribers: Vec::new(), - key: info.key, + key: desc.key, }), - info, + desc, } } @@ -182,12 +182,12 @@ impl Cell { } /// Move a slot out of the cell by swapping with the last - fn take(&mut self, slot: Slot, mut on_move: impl FnMut(ComponentInfo, *mut u8)) { + fn take(&mut self, slot: Slot, mut on_move: impl FnMut(ComponentDesc, *mut u8)) { let data = self.data.get_mut(); let last = data.storage.len() - 1; - data.storage.swap_remove(slot, |p| on_move(self.info, p)); + data.storage.swap_remove(slot, |p| on_move(self.desc, p)); data.changes.swap_remove(slot, last, |_, _| {}); } @@ -195,26 +195,16 @@ impl Cell { fn clear(&mut self) { let data = self.data.get_mut(); - // if !storage.is_empty() { - // // Notify removed - // for v in self.subscribers.iter() { - // v.on_change(self.info, ChangeKind::Removed) - // } - // } - data.storage.clear(); data.changes.clear(); - - // Notify subscribers } /// Drain the values in the cell. pub(crate) fn drain(&mut self) -> Storage { let data = self.data.get_mut(); - let storage = mem::replace(&mut data.storage, Storage::new(self.info)); + let storage = mem::replace(&mut data.storage, Storage::new(self.desc)); data.changes.clear(); - // Notify subscribers storage } @@ -316,14 +306,14 @@ impl Archetype { /// Assumes `components` are sorted by id. pub(crate) fn new(components: I) -> Self where - I: IntoIterator, + I: IntoIterator, { let cells = components .into_iter() - .map(|info| { - let key = info.key(); + .map(|desc| { + let key = desc.key(); - (key, Cell::new(info)) + (key, Cell::new(desc)) }) .collect(); @@ -427,14 +417,14 @@ impl Archetype { } /// Returns human friendly debug info - pub fn info(&self) -> ArchetypeInfo { + pub fn desc(&self) -> ArchetypeInfo { let (components, storage) = self .cells .values() .map(|v| { let data = v.data.borrow(); ( - v.info, + v.desc, StorageInfo { cap: data.storage.capacity(), len: data.storage.len(), @@ -558,9 +548,9 @@ impl Archetype { buffer: &mut crate::buffer::ComponentBuffer, ) -> Slot { let slot = self.allocate(id); - for (info, src) in buffer.drain() { + for (desc, src) in buffer.drain() { unsafe { - let data = self.cells.get_mut(&info.key).unwrap().data.get_mut(); + let data = self.cells.get_mut(&desc.key).unwrap().data.get_mut(); data.storage.extend(src, 1); } @@ -638,7 +628,7 @@ impl Archetype { /// must point to a currently uninitialized region in the archetype. pub(crate) unsafe fn extend(&mut self, src: &mut Storage, tick: u32) -> Option<()> { let len = self.len(); - let cell = self.cells.get_mut(&src.info().key())?; + let cell = self.cells.get_mut(&src.desc().key())?; let data = cell.data.get_mut(); let slots = Slice::new(data.storage.len(), data.storage.len() + src.len()); @@ -665,7 +655,7 @@ impl Archetype { &mut self, dst: &mut Self, slot: Slot, - mut on_drop: impl FnMut(ComponentInfo, *mut u8), + mut on_drop: impl FnMut(ComponentDesc, *mut u8), tick: u32, ) -> (Slot, Option<(Entity, Slot)>) { let id = self.entity(slot).expect("Invalid entity"); @@ -720,7 +710,7 @@ impl Archetype { pub unsafe fn take( &mut self, slot: Slot, - mut on_move: impl FnMut(ComponentInfo, *mut u8), + mut on_move: impl FnMut(ComponentDesc, *mut u8), ) -> Option<(Entity, Slot)> { let id = self.entity(slot).expect("Invalid entity"); @@ -756,7 +746,7 @@ impl Archetype { /// the `on_take` function. pub(crate) unsafe fn pop_last( &mut self, - on_take: impl FnMut(ComponentInfo, *mut u8), + on_take: impl FnMut(ComponentDesc, *mut u8), ) -> Option { let last = self.last(); if let Some(last) = last { @@ -882,13 +872,13 @@ impl Archetype { } /// Get a reference to the archetype's components. - pub(crate) fn components(&self) -> impl Iterator + '_ { - self.cells.values().map(|v| v.info) + pub(crate) fn components(&self) -> impl Iterator + '_ { + self.cells.values().map(|v| v.desc) } #[allow(dead_code)] pub(crate) fn component_names(&self) -> impl Iterator { - self.cells.values().map(|v| v.info.name()) + self.cells.values().map(|v| v.desc.name()) } /// Returns a iterator which attempts to borrows each storage in the archetype @@ -929,8 +919,8 @@ impl Archetype { &mut self.entities } - pub(crate) fn component(&self, key: ComponentKey) -> Option { - self.cell(key).map(|v| v.info) + pub(crate) fn component(&self, key: ComponentKey) -> Option { + self.cell(key).map(|v| v.desc) } /// Add a new subscriber. The subscriber must be interested in this archetype @@ -938,7 +928,7 @@ impl Archetype { // For component changes for cell in self.cells.values_mut() { let data = cell.data.get_mut(); - if s.matches_component(cell.info) { + if s.matches_component(cell.desc) { data.subscribers.push(s.clone()); } @@ -1005,9 +995,9 @@ mod tests { #[test] pub fn test_archetype() { let mut arch = Archetype::new([ - ComponentInfo::of(a()), - ComponentInfo::of(b()), - ComponentInfo::of(c()), + ComponentDesc::of(a()), + ComponentDesc::of(b()), + ComponentDesc::of(c()), ]); let shared = Arc::new("abc".to_string()); diff --git a/src/archetype/storage.rs b/src/archetype/storage.rs index 122634a9..1cf329dd 100644 --- a/src/archetype/storage.rs +++ b/src/archetype/storage.rs @@ -4,7 +4,7 @@ use alloc::{ alloc::alloc, alloc::dealloc, alloc::handle_alloc_error, alloc::realloc, alloc::Layout, }; -use crate::{ComponentInfo, ComponentKey, ComponentValue}; +use crate::{ComponentDesc, ComponentKey, ComponentValue}; use super::Slot; @@ -15,38 +15,38 @@ pub struct Storage { /// The number of items len: usize, cap: usize, - info: ComponentInfo, + desc: ComponentDesc, } impl core::fmt::Debug for Storage { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Storage") .field("len", &self.len) - .field("info", &self.info) + .field("desc", &self.desc) .finish() } } impl Storage { /// Allocates space for storage of `len` components. - pub fn new(info: ComponentInfo) -> Self { - Self::with_capacity(info, 0) + pub fn new(desc: ComponentDesc) -> Self { + Self::with_capacity(desc, 0) } - pub fn with_capacity(info: ComponentInfo, cap: usize) -> Self { + pub fn with_capacity(desc: ComponentDesc, cap: usize) -> Self { if cap == 0 { - let data = (info.vtable.dangling)(); + let data = (desc.vtable.dangling)(); - assert_eq!(data.as_ptr() as usize % info.layout().align(), 0); + assert_eq!(data.as_ptr() as usize % desc.layout().align(), 0); return Self { data, cap: 0, len: 0, - info, + desc, }; } - let layout = Layout::from_size_align(info.size() * cap, info.align()).unwrap(); + let layout = Layout::from_size_align(desc.size() * cap, desc.align()).unwrap(); unsafe { let data = alloc(layout); @@ -54,12 +54,12 @@ impl Storage { Some(v) => v, None => handle_alloc_error(layout), }; - assert_eq!(data.as_ptr() as usize % info.layout().align(), 0); + assert_eq!(data.as_ptr() as usize % desc.layout().align(), 0); Self { data, cap, len: 0, - info, + desc, } } } @@ -77,13 +77,13 @@ impl Storage { // tracing::debug!( // "Reserving size: {old_cap}[{}] + {additional} => {new_cap} for: {:?}", // self.len(), - // self.info().name() + // self.desc().name() // ); let old_layout = - Layout::from_size_align(self.info.size() * old_cap, self.info.align()).unwrap(); + Layout::from_size_align(self.desc.size() * old_cap, self.desc.align()).unwrap(); let new_layout = - Layout::from_size_align(self.info.size() * new_cap, self.info.align()).unwrap(); + Layout::from_size_align(self.desc.size() * new_cap, self.desc.align()).unwrap(); // Handle zst if new_layout.size() == 0 { @@ -118,13 +118,13 @@ impl Storage { unsafe { let ptr = self.as_ptr(); - let dst = ptr.add(slot * self.info.size()); + let dst = ptr.add(slot * self.desc.size()); on_move(dst); - let src = ptr.add((self.len - 1) * self.info.size()); + let src = ptr.add((self.len - 1) * self.desc.size()); - core::ptr::copy(src, dst, self.info.size()) + core::ptr::copy(src, dst, self.desc.size()) } self.len -= 1; } @@ -139,7 +139,7 @@ impl Storage { if slot >= self.len { None } else { - Some(self.data.as_ptr().add(self.info.size() * slot)) + Some(self.data.as_ptr().add(self.desc.size() * slot)) } } @@ -149,8 +149,8 @@ impl Storage { core::ptr::copy_nonoverlapping( src, - self.as_ptr().add(self.len * self.info.size()), - len * self.info.size(), + self.as_ptr().add(self.len * self.desc.size()), + len * self.desc.size(), ); self.len += len @@ -162,8 +162,8 @@ impl Storage { /// Other must be of the same type as self pub(crate) unsafe fn append(&mut self, other: &mut Self) { assert_eq!( - self.info.type_id(), - other.info.type_id(), + self.desc.type_id(), + other.desc.type_id(), "Mismatched types" ); @@ -178,8 +178,8 @@ impl Storage { core::ptr::copy_nonoverlapping( other.as_ptr(), - self.as_ptr().add(self.len * self.info.size()), - other.len * self.info.size(), + self.as_ptr().add(self.len * self.desc.size()), + other.len * self.desc.size(), ); self.len += other.len; @@ -188,7 +188,7 @@ impl Storage { #[inline(always)] pub fn downcast_mut(&mut self) -> &mut [T] { - if !self.info.is::() { + if !self.desc.is::() { panic!("Mismatched types"); } @@ -197,7 +197,7 @@ impl Storage { #[inline(always)] pub fn downcast_ref(&self) -> &[T] { - if !self.info.is::() { + if !self.desc.is::() { panic!("Mismatched types"); } @@ -209,7 +209,7 @@ impl Storage { for slot in 0..self.len { unsafe { let value = self.at_mut(slot).unwrap(); - self.info.drop(value); + self.desc.drop(value); } } @@ -243,7 +243,7 @@ impl Storage { /// This is safe as the underlying vtable is not changed, as long as the id /// points to a component of the same kind. pub(crate) unsafe fn set_id(&mut self, id: ComponentKey) { - self.info.key = id + self.desc.key = id } pub(crate) fn capacity(&self) -> usize { @@ -251,8 +251,8 @@ impl Storage { } #[inline] - pub(crate) fn info(&self) -> ComponentInfo { - self.info + pub(crate) fn desc(&self) -> ComponentDesc { + self.desc } } @@ -261,13 +261,13 @@ impl Drop for Storage { self.clear(); // ZST - if self.cap == 0 || self.info.size() == 0 { + if self.cap == 0 || self.desc.size() == 0 { return; } let ptr = self.as_ptr(); let layout = - Layout::from_size_align(self.info.size() * self.cap, self.info.align()).unwrap(); + Layout::from_size_align(self.desc.size() * self.cap, self.desc.align()).unwrap(); unsafe { dealloc(ptr, layout); @@ -294,7 +294,7 @@ mod test { #[test] fn push() { - let mut storage = Storage::new(a().info()); + let mut storage = Storage::new(a().desc()); unsafe { storage.push(5); storage.push(7); @@ -304,7 +304,7 @@ mod test { assert_eq!(storage.downcast_ref::(), [7]); - let mut other = Storage::new(a().info()); + let mut other = Storage::new(a().desc()); other.push(8); other.push(9); other.push(10); @@ -317,7 +317,7 @@ mod test { #[test] fn drop() { let v = Arc::new("This is shared".to_string()); - let mut storage = Storage::new(b().info()); + let mut storage = Storage::new(b().desc()); unsafe { storage.push(v.clone()); storage.push(v.clone()); diff --git a/src/archetypes.rs b/src/archetypes.rs index f4878d36..d8fd22ce 100644 --- a/src/archetypes.rs +++ b/src/archetypes.rs @@ -5,7 +5,7 @@ use crate::{ entity::{EntityKind, EntityStore, EntityStoreIter, EntityStoreIterMut}, events::EventSubscriber, metadata::exclusive, - ArchetypeId, ComponentInfo, Entity, + ArchetypeId, ComponentDesc, Entity, }; // fn is_sorted(v: &[T]) -> bool { @@ -84,7 +84,7 @@ impl Archetypes { /// Ensures the `exclusive` property of any relations are satisfied pub(crate) fn find_create( &mut self, - components: impl IntoIterator, + components: impl IntoIterator, ) -> (ArchetypeId, &mut Archetype) { let mut cursor = self.root; diff --git a/src/buffer.rs b/src/buffer.rs index 16c33bcc..1f7ab298 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -7,7 +7,7 @@ use alloc::collections::BTreeMap; use crate::format::MissingDebug; use crate::metadata::debuggable; -use crate::{metadata, Component, ComponentInfo, ComponentKey, ComponentValue, Entity}; +use crate::{metadata, Component, ComponentDesc, ComponentKey, ComponentValue, Entity}; type Offset = usize; @@ -145,9 +145,9 @@ impl BufferStorage { /// # Safety /// The existing data at offset is overwritten without calling drop on the contained value. /// The offset is must be allocated from [`Self::allocate`] with the layout of `T` - pub(crate) unsafe fn write_dyn(&mut self, offset: Offset, info: ComponentInfo, data: *mut u8) { + pub(crate) unsafe fn write_dyn(&mut self, offset: Offset, desc: ComponentDesc, data: *mut u8) { let dst = self.data.as_ptr().add(offset); - let layout = info.layout(); + let layout = desc.layout(); assert_eq!( self.data.as_ptr() as usize % layout.align(), @@ -199,7 +199,7 @@ impl Drop for BufferStorage { /// This is a low level building block. Prefer [EntityBuilder](crate::EntityBuilder) or [CommandBuffer](crate::CommandBuffer) instead. #[derive(Default)] pub struct ComponentBuffer { - entries: BTreeMap, + entries: BTreeMap, storage: BufferStorage, } @@ -207,15 +207,15 @@ impl core::fmt::Debug for ComponentBuffer { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut s = f.debug_map(); - for &(info, offset) in self.entries.values() { - let debugger = info.meta_ref().get(debuggable()); + for &(desc, offset) in self.entries.values() { + let debugger = desc.meta_ref().get(debuggable()); if let Some(debugger) = debugger { unsafe { let ptr = self.storage.at(offset); - s.entry(&info.name(), debugger.debug_ptr(&ptr)); + s.entry(&desc.name(), debugger.debug_ptr(&ptr)); } } else { - s.entry(&info.name(), &MissingDebug); + s.entry(&desc.name(), &MissingDebug); } } @@ -253,7 +253,7 @@ impl ComponentBuffer { } /// Returns the components in the buffer - pub fn components(&self) -> impl Iterator { + pub fn components(&self) -> impl Iterator { self.entries.values().map(|v| &v.0) } @@ -266,18 +266,18 @@ impl ComponentBuffer { /// Set a component in the component buffer pub fn set(&mut self, component: Component, value: T) -> Option { - let info = component.info(); + let desc = component.desc(); - if let Some(&(_, offset)) = self.entries.get(&info.key()) { + if let Some(&(_, offset)) = self.entries.get(&desc.key()) { unsafe { Some(self.storage.replace(offset, value)) } } else { - if info.key().is_relation() && info.meta_ref().has(metadata::exclusive()) { - self.drain_relations_like(info.key.id()); + if desc.key().is_relation() && desc.meta_ref().has(metadata::exclusive()) { + self.drain_relations_like(desc.key.id()); } let offset = self.storage.push(value); - self.entries.insert(info.key(), (info, offset)); + self.entries.insert(desc.key(), (desc, offset)); None } @@ -288,31 +288,31 @@ impl ComponentBuffer { let end = ComponentKey::new(relation, Some(Entity::MAX)); while let Some((&key, _)) = self.entries.range(start..=end).next() { - let (info, offset) = self.entries.remove(&key).unwrap(); + let (desc, offset) = self.entries.remove(&key).unwrap(); unsafe { let ptr = self.storage.at_mut(offset); - info.drop(ptr); + desc.drop(ptr); } } } /// Set from a type erased component - pub(crate) unsafe fn set_dyn(&mut self, info: ComponentInfo, value: *mut u8) { - if let Some(&(_, offset)) = self.entries.get(&info.key()) { + pub(crate) unsafe fn set_dyn(&mut self, desc: ComponentDesc, value: *mut u8) { + if let Some(&(_, offset)) = self.entries.get(&desc.key()) { let old_ptr = self.storage.at_mut(offset); - info.drop(old_ptr); + desc.drop(old_ptr); - ptr::copy_nonoverlapping(value, old_ptr, info.size()); + ptr::copy_nonoverlapping(value, old_ptr, desc.size()); } else { - if info.key().is_relation() && info.meta_ref().has(metadata::exclusive()) { - self.drain_relations_like(info.key.id()); + if desc.key().is_relation() && desc.meta_ref().has(metadata::exclusive()) { + self.drain_relations_like(desc.key.id()); } - let offset = self.storage.allocate(info.layout()); + let offset = self.storage.allocate(desc.layout()); - self.storage.write_dyn(offset, info, value); + self.storage.write_dyn(offset, desc, value); - self.entries.insert(info.key(), (info, offset)); + self.entries.insert(desc.key(), (desc, offset)); } } @@ -347,38 +347,38 @@ impl ComponentBuffer { /// # Safety /// If the passed closure returns *false* the element is considered moved and shall be handled by /// the caller. - pub(crate) unsafe fn retain(&mut self, mut f: impl FnMut(ComponentInfo, *mut u8) -> bool) { - self.entries.retain(|_, (info, offset)| { + pub(crate) unsafe fn retain(&mut self, mut f: impl FnMut(ComponentDesc, *mut u8) -> bool) { + self.entries.retain(|_, (desc, offset)| { let ptr = unsafe { self.storage.at_mut(*offset) }; - f(*info, ptr) + f(*desc, ptr) }) } } pub(crate) struct ComponentBufferIter<'a> { - entries: &'a mut BTreeMap, + entries: &'a mut BTreeMap, storage: &'a mut BufferStorage, } impl<'a> Iterator for ComponentBufferIter<'a> { - type Item = (ComponentInfo, *mut u8); + type Item = (ComponentDesc, *mut u8); fn next(&mut self) -> Option { - let (_, (info, offset)) = self.entries.pop_first()?; + let (_, (desc, offset)) = self.entries.pop_first()?; unsafe { let data = self.storage.at_mut(offset); - Some((info, data)) + Some((desc, data)) } } } impl Drop for ComponentBuffer { fn drop(&mut self) { - for &(info, offset) in self.entries.values() { + for &(desc, offset) in self.entries.values() { unsafe { let ptr = self.storage.at_mut(offset); - info.drop(ptr); + desc.drop(ptr); } } } @@ -490,13 +490,13 @@ mod tests { let shared_2: Arc = Arc::new("abc".into()); unsafe { let mut shared = shared.clone(); - buffer.set_dyn(f().info(), &mut shared as *mut _ as *mut u8); + buffer.set_dyn(f().desc(), &mut shared as *mut _ as *mut u8); mem::forget(shared) } unsafe { let mut shared = shared_2.clone(); - buffer.set_dyn(f().info(), &mut shared as *mut _ as *mut u8); + buffer.set_dyn(f().desc(), &mut shared as *mut _ as *mut u8); mem::forget(shared) } diff --git a/src/commands.rs b/src/commands.rs index c32f138a..d341a760 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -4,7 +4,7 @@ use alloc::{boxed::Box, format, vec::Vec}; use anyhow::Context; use crate::{ - buffer::MultiComponentBuffer, BatchSpawn, Component, ComponentInfo, ComponentValue, Entity, + buffer::MultiComponentBuffer, BatchSpawn, Component, ComponentDesc, ComponentValue, Entity, EntityBuilder, World, }; @@ -22,7 +22,7 @@ enum Command { /// Set a component for an entity Set { id: Entity, - info: ComponentInfo, + desc: ComponentDesc, offset: usize, }, /// Despawn an entity @@ -30,7 +30,7 @@ enum Command { /// Remove a component from an entity Remove { id: Entity, - info: ComponentInfo, + desc: ComponentDesc, }, /// Execute an arbitrary function with a mutable reference to the world. @@ -49,16 +49,16 @@ impl fmt::Debug for Command { .field(&batch) .field(&ids.len()) .finish(), - Self::Set { id, info, offset } => f + Self::Set { id, desc, offset } => f .debug_struct("Set") .field("id", id) - .field("info", info) + .field("desc", desc) .field("offset", offset) .finish(), Self::Despawn(arg0) => f.debug_tuple("Despawn").field(arg0).finish(), Self::Remove { id, - info: component, + desc: component, } => f .debug_struct("Remove") .field("id", id) @@ -108,7 +108,7 @@ impl CommandBuffer { let offset = self.inserts.push(value); self.commands.push(Command::Set { id, - info: component.info(), + desc: component.desc(), offset, }); @@ -121,7 +121,7 @@ impl CommandBuffer { pub fn remove(&mut self, id: Entity, component: Component) -> &mut Self { self.commands.push(Command::Remove { id, - info: component.info(), + desc: component.desc(), }); self @@ -208,21 +208,21 @@ impl CommandBuffer { .map_err(|v| v.into_anyhow()) .context("Failed to spawn entity")?; } - Command::Set { id, info, offset } => unsafe { + Command::Set { id, desc, offset } => unsafe { let value = self.inserts.take_dyn(offset); world - .set_dyn(id, info, value) + .set_dyn(id, desc, value) .map_err(|v| v.into_anyhow()) - .with_context(|| format!("Failed to set component {}", info.name()))?; + .with_context(|| format!("Failed to set component {}", desc.name()))?; }, Command::Despawn(id) => world .despawn(id) .map_err(|v| v.into_anyhow()) .context("Failed to despawn entity")?, - Command::Remove { id, info } => world - .remove_dyn(id, info) + Command::Remove { id, desc } => world + .remove_dyn(id, desc) .map_err(|v| v.into_anyhow()) - .with_context(|| format!("Failed to remove component {}", info.name()))?, + .with_context(|| format!("Failed to remove component {}", desc.name()))?, Command::Defer(func) => { func(world).context("Failed to execute deferred function")? } diff --git a/src/component.rs b/src/component.rs index a0c1e8c2..2a8050ea 100644 --- a/src/component.rs +++ b/src/component.rs @@ -245,9 +245,9 @@ impl Component { self.key.id } - /// Returns the type erased component info - pub fn info(self) -> ComponentInfo { - ComponentInfo::of(self) + /// Returns the type erased component description + pub fn desc(self) -> ComponentDesc { + ComponentDesc::of(self) } /// Transform this into a mutable fetch @@ -305,13 +305,13 @@ impl Component { /// Returns all metadata components pub fn get_meta(&self) -> ComponentBuffer { - self.vtable.meta.get(self.info()) + self.vtable.meta.get(self.desc()) } } impl Metadata for Component { - fn attach(info: ComponentInfo, buffer: &mut ComponentBuffer) { - buffer.set(crate::components::component_info(), info); + fn attach(desc: ComponentDesc, buffer: &mut ComponentBuffer) { + buffer.set(crate::components::component_info(), desc); } } @@ -356,19 +356,19 @@ impl RelationExt for Component { /// Represents a type erased component along with its memory layout and drop fn. #[derive(Clone, Copy)] -pub struct ComponentInfo { +pub struct ComponentDesc { pub(crate) key: ComponentKey, pub(crate) vtable: &'static UntypedVTable, } -impl Eq for ComponentInfo {} -impl PartialEq for ComponentInfo { +impl Eq for ComponentDesc {} +impl PartialEq for ComponentDesc { fn eq(&self, other: &Self) -> bool { self.key == other.key && ptr::eq(self.vtable, other.vtable) } } -impl core::fmt::Debug for ComponentInfo { +impl core::fmt::Debug for ComponentDesc { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self.key.object { Some(object) => write!(f, "{}({}) {}", self.vtable.name, object, self.key.id()), @@ -377,25 +377,25 @@ impl core::fmt::Debug for ComponentInfo { } } -impl From> for ComponentInfo { +impl From> for ComponentDesc { fn from(v: Component) -> Self { - ComponentInfo::of(v) + ComponentDesc::of(v) } } -impl PartialOrd for ComponentInfo { +impl PartialOrd for ComponentDesc { fn partial_cmp(&self, other: &Self) -> Option { self.key.partial_cmp(&other.key) } } -impl Ord for ComponentInfo { +impl Ord for ComponentDesc { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.key.cmp(&other.key) } } -impl ComponentInfo { +impl ComponentDesc { /// Convert back to a typed form /// /// # Panics @@ -405,7 +405,7 @@ impl ComponentInfo { Component::from_raw_parts(self.key, self.vtable) } - /// Returns the component info of a types component + /// Returns the component description of a types component pub fn of(component: Component) -> Self { Self { key: component.key(), diff --git a/src/components.rs b/src/components.rs index 944b59c7..3c97bd26 100644 --- a/src/components.rs +++ b/src/components.rs @@ -6,7 +6,7 @@ use alloc::string::String; use crate::component; use crate::Exclusive; -use crate::ComponentInfo; +use crate::ComponentDesc; use crate::Debuggable; component! { @@ -22,7 +22,7 @@ component! { /// /// Added automatically to all components. /// This is the basis of the reflection provided by flax - pub component_info: ComponentInfo => [ Debuggable ], + pub component_info: ComponentDesc => [ Debuggable ], /// Added automatically to all STATIC entities pub is_static: () => [ Debuggable ], diff --git a/src/entity/builder.rs b/src/entity/builder.rs index 6aee782d..841275c9 100644 --- a/src/entity/builder.rs +++ b/src/entity/builder.rs @@ -1,5 +1,5 @@ use crate::{ - buffer::ComponentBuffer, error::Result, CommandBuffer, Component, ComponentInfo, + buffer::ComponentBuffer, error::Result, CommandBuffer, Component, ComponentDesc, ComponentValue, Entity, RelationExt, World, }; use alloc::{boxed::Box, vec::Vec}; @@ -65,8 +65,8 @@ impl EntityBuilder { self } - pub(crate) unsafe fn set_dyn(&mut self, info: ComponentInfo, value: *mut u8) -> &mut Self { - self.buffer.set_dyn(info, value); + pub(crate) unsafe fn set_dyn(&mut self, desc: ComponentDesc, value: *mut u8) -> &mut Self { + self.buffer.set_dyn(desc, value); self } @@ -244,7 +244,7 @@ mod test { world.get(id, is_enemy()).as_deref(), Err(&Error::MissingComponent(MissingComponent { id, - info: is_enemy().info() + desc: is_enemy().desc() })) ); } diff --git a/src/entity_ref.rs b/src/entity_ref.rs index 1c561567..d42cfad0 100644 --- a/src/entity_ref.rs +++ b/src/entity_ref.rs @@ -38,7 +38,7 @@ impl<'a> EntityRefMut<'a> { .get_at(self.loc(), component) .ok_or_else(|| MissingComponent { id: self.id, - info: component.info(), + desc: component.desc(), }) } @@ -51,7 +51,7 @@ impl<'a> EntityRefMut<'a> { .get_mut_at(self.loc(), component) .ok_or_else(|| MissingComponent { id: self.id, - info: component.info(), + desc: component.desc(), }) } @@ -85,7 +85,7 @@ impl<'a> EntityRefMut<'a> { arch.update(loc.slot, component, FnWriter::new(f), tick) .ok_or(MissingComponent { id: self.id, - info: component.info(), + desc: component.desc(), }) } @@ -102,7 +102,7 @@ impl<'a> EntityRefMut<'a> { arch.update(loc.slot, component, WriteDedup::new(value), tick) .ok_or(MissingComponent { id: self.id, - info: component.info(), + desc: component.desc(), }) } @@ -147,7 +147,7 @@ impl<'a> EntityRefMut<'a> { /// Set a component for the entity pub fn set(&mut self, component: Component, value: T) -> Option { self.set_with_writer(SingleComponentWriter::new( - component.info(), + component.desc(), Replace::new(value), )) .left() @@ -158,7 +158,7 @@ impl<'a> EntityRefMut<'a> { /// Does not trigger a modification event if the value is the same pub fn set_dedup(&mut self, component: Component, value: T) { self.set_with_writer(SingleComponentWriter::new( - component.info(), + component.desc(), WriteDedup::new(value), )); } @@ -179,7 +179,7 @@ impl<'a> EntityRefMut<'a> { let (old, loc) = unsafe { let loc = self .world - .remove_inner(self.id, component.info(), |ptr| { + .remove_inner(self.id, component.desc(), |ptr| { res.write(ptr.cast::().read()); }) .map_err(|v| v.try_into_missing_component().unwrap())?; @@ -301,7 +301,7 @@ impl<'a> EntityRef<'a> { .get(self.slot, component) .ok_or_else(|| MissingComponent { id: self.id, - info: component.info(), + desc: component.desc(), }) } @@ -314,7 +314,7 @@ impl<'a> EntityRef<'a> { .get_mut(self.slot, component, self.world.advance_change_tick()) .ok_or_else(|| MissingComponent { id: self.id, - info: component.info(), + desc: component.desc(), }) } @@ -485,7 +485,7 @@ mod test { res.as_deref(), Err(&MissingComponent { id, - info: is_static().info() + desc: is_static().desc() }) ) } @@ -617,7 +617,7 @@ mod test { entity.update(b(), |v| v.push('_')), Err(MissingComponent { id, - info: b().info() + desc: b().desc() }) ); diff --git a/src/entry.rs b/src/entry.rs index 720962e7..558aa939 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -28,7 +28,7 @@ impl<'a, T: ComponentValue> VacantEntry<'a, T> { .world .set_with_writer( self.id, - SingleComponentWriter::new(self.component.info(), Replace { value }), + SingleComponentWriter::new(self.component.desc(), Replace { value }), ) .expect("Entry is valid"); diff --git a/src/error.rs b/src/error.rs index 7d72c145..42fb762d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use core::fmt::Display; -use crate::{ComponentInfo, Entity}; +use crate::{ComponentDesc, Entity}; #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] @@ -51,7 +51,7 @@ pub struct MissingComponent { /// The entity which did not have the component pub id: Entity, /// The missing component - pub info: ComponentInfo, + pub desc: ComponentDesc, } /// Result alias for [crate::error::Result] @@ -87,7 +87,7 @@ impl Display for MissingComponent { write!( f, "Entity {} does not have the component {:?}", - self.id, self.info + self.id, self.desc ) } } diff --git a/src/events.rs b/src/events.rs index 68061414..9d5e8343 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,7 +1,7 @@ use alloc::vec::Vec; use crate::{ - archetype::Archetype, filter::StaticFilter, ComponentInfo, ComponentKey, ComponentValue, Entity, + archetype::Archetype, filter::StaticFilter, ComponentDesc, ComponentKey, ComponentValue, Entity, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -50,7 +50,7 @@ pub trait EventSubscriber: ComponentValue { /// Returns true if the subscriber is interested in this component #[inline] - fn matches_component(&self, _: ComponentInfo) -> bool { + fn matches_component(&self, _: ComponentDesc) -> bool { true } @@ -164,8 +164,8 @@ where } #[inline] - fn matches_component(&self, info: ComponentInfo) -> bool { - self.subscriber.matches_component(info) + fn matches_component(&self, desc: ComponentDesc) -> bool { + self.subscriber.matches_component(desc) } #[inline] @@ -198,8 +198,8 @@ where } #[inline] - fn matches_component(&self, info: ComponentInfo) -> bool { - self.subscriber.matches_component(info) + fn matches_component(&self, desc: ComponentDesc) -> bool { + self.subscriber.matches_component(desc) } #[inline] @@ -229,8 +229,8 @@ where } #[inline] - fn matches_component(&self, info: ComponentInfo) -> bool { - self.components.contains(&info.key()) && self.subscriber.matches_component(info) + fn matches_component(&self, desc: ComponentDesc) -> bool { + self.components.contains(&desc.key()) && self.subscriber.matches_component(desc) } #[inline] diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 2673a755..dc32d746 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -96,17 +96,5 @@ impl<'q, 'w, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> fn set_visited(&mut self, slots: Slice) { self.guard .set_modified(&self.arch.entities, slots, self.tick); - // let event = EventData { - // ids: &self.ids[slots.as_range()], - // key: self.cell.info().key, - // kind: EventKind::Modified, - // }; - - // for handler in self.cell.subscribers.iter() { - // handler.on_event(&event) - // } - - // self.changes - // .set_modified_if_tracking(Change::new(slots, self.tick)); } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 15861cba..97e66d83 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -33,7 +33,7 @@ where let borrows: SmallVec<[_; 4]> = { data.arch .relations_like(self.component.id()) - .map(|(info, cell)| (info.object.unwrap(), cell.borrow())) + .map(|(desc, cell)| (desc.object.unwrap(), cell.borrow())) .collect() }; diff --git a/src/filter/mod.rs b/src/filter/mod.rs index cb5ad407..e8cdfb65 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -687,7 +687,7 @@ mod tests { c: u32, } - let mut archetype = Archetype::new([a().info(), b().info(), c().info()]); + let mut archetype = Archetype::new([a().desc(), b().desc(), c().desc()]); let filter = (ChangeFilter::new(a(), ChangeKind::Modified) & ChangeFilter::new(b(), ChangeKind::Modified)) diff --git a/src/format.rs b/src/format.rs index 71543fde..a1db87b8 100644 --- a/src/format.rs +++ b/src/format.rs @@ -136,12 +136,12 @@ impl<'a> Debug for RowValueFormatter<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let mut map = f.debug_map(); for data in self.arch.try_borrow_all().flatten() { - let info = data.storage.info(); + let desc = data.storage.desc(); - if let Ok(visitor) = self.world.get(info.key().id, debuggable()) { - map.entry(&info, (visitor.debug_storage)(&data.storage, self.slot)); + if let Ok(visitor) = self.world.get(desc.key().id, debuggable()) { + map.entry(&desc, (visitor.debug_storage)(&data.storage, self.slot)); } else { - map.entry(&info, &MissingDebug); + map.entry(&desc, &MissingDebug); } } diff --git a/src/lib.rs b/src/lib.rs index 386fd626..8532aaa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,7 @@ mod writer; pub use archetype::{ArchetypeId, BatchSpawn, RefMut}; pub use commands::CommandBuffer; pub use component::{ - Component, ComponentFn, ComponentInfo, ComponentKey, ComponentValue, RelationFn, + Component, ComponentDesc, ComponentFn, ComponentKey, ComponentValue, RelationFn, }; pub use components::{child_of, component_info, is_static, name}; pub use entity::{entity_ids, Entity, EntityBuilder}; diff --git a/src/macros.rs b/src/macros.rs index 3390a64c..ea29e5ed 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -30,7 +30,7 @@ /// # Metadata /// /// Metadata can be attached to any component, which allows reflection and -/// additional info for components. Any type which implements [`crate::metadata::Metadata`] can be used. +/// additional desc for components. Any type which implements [`crate::metadata::Metadata`] can be used. /// /// The following allows the component value to be printed for the world debug /// formatter, and it thus recommended to add where possible. @@ -105,15 +105,15 @@ macro_rules! component { $vis fn $name($obj: $crate::Entity) -> $crate::Component<$ty> { static COMPONENT_ID: ::core::sync::atomic::AtomicU32 = ::core::sync::atomic::AtomicU32::new($crate::entity::EntityIndex::MAX); - fn meta(_component: $crate::ComponentInfo) -> $crate::buffer::ComponentBuffer { + fn meta(_desc: $crate::ComponentDesc) -> $crate::buffer::ComponentBuffer { let mut _buffer = $crate::buffer::ComponentBuffer::new(); - <$crate::metadata::Name as $crate::metadata::Metadata<$ty>>::attach(_component, &mut _buffer); - <$crate::Component<$ty> as $crate::metadata::Metadata<$ty>>::attach(_component, &mut _buffer); + <$crate::metadata::Name as $crate::metadata::Metadata<$ty>>::attach(_desc, &mut _buffer); + <$crate::Component<$ty> as $crate::metadata::Metadata<$ty>>::attach(_desc, &mut _buffer); $( $( - <$metadata as $crate::metadata::Metadata::<$ty>>::attach(_component, &mut _buffer); + <$metadata as $crate::metadata::Metadata::<$ty>>::attach(_desc, &mut _buffer); )* )* @@ -138,15 +138,15 @@ macro_rules! component { $(#[$outer])* $vis fn $name() -> $crate::Component<$ty> { static COMPONENT_ID: ::core::sync::atomic::AtomicU32 = ::core::sync::atomic::AtomicU32::new($crate::entity::EntityIndex::MAX); - fn meta(_component: $crate::ComponentInfo) -> $crate::buffer::ComponentBuffer { + fn meta(_desc: $crate::ComponentDesc) -> $crate::buffer::ComponentBuffer { let mut _buffer = $crate::buffer::ComponentBuffer::new(); - <$crate::metadata::Name as $crate::metadata::Metadata<$ty>>::attach(_component, &mut _buffer); - <$crate::Component<$ty> as $crate::metadata::Metadata<$ty>>::attach(_component, &mut _buffer); + <$crate::metadata::Name as $crate::metadata::Metadata<$ty>>::attach(_desc, &mut _buffer); + <$crate::Component<$ty> as $crate::metadata::Metadata<$ty>>::attach(_desc, &mut _buffer); $( $( - <$metadata as $crate::metadata::Metadata::<$ty>>::attach(_component, &mut _buffer); + <$metadata as $crate::metadata::Metadata::<$ty>>::attach(_desc, &mut _buffer); )* )* @@ -183,15 +183,15 @@ macro_rules! component_vtable { ($name:tt: $ty: ty $(=> [$($metadata: ty),*])?) => { { - fn meta(_info: $crate::ComponentInfo) -> $crate::buffer::ComponentBuffer { + fn meta(_desc: $crate::ComponentDesc) -> $crate::buffer::ComponentBuffer { let mut _buffer = $crate::buffer::ComponentBuffer::new(); - <$crate::metadata::Name as $crate::metadata::Metadata<$ty>>::attach(_info, &mut _buffer); - <$crate::Component<$ty> as $crate::metadata::Metadata<$ty>>::attach(_info, &mut _buffer); + <$crate::metadata::Name as $crate::metadata::Metadata<$ty>>::attach(_desc, &mut _buffer); + <$crate::Component<$ty> as $crate::metadata::Metadata<$ty>>::attach(_desc, &mut _buffer); $( $( - <$metadata as $crate::metadata::Metadata::<$ty>>::attach(_info, &mut _buffer); + <$metadata as $crate::metadata::Metadata::<$ty>>::attach(_desc, &mut _buffer); )* )* diff --git a/src/metadata/debuggable.rs b/src/metadata/debuggable.rs index cbd156c9..65b93d30 100644 --- a/src/metadata/debuggable.rs +++ b/src/metadata/debuggable.rs @@ -3,7 +3,7 @@ use core::{any::Any, fmt::Debug}; use crate::{ archetype::{Slot, Storage}, buffer::ComponentBuffer, - component, ComponentInfo, ComponentValue, + component, ComponentDesc, ComponentValue, }; use super::Metadata; @@ -36,7 +36,7 @@ impl Metadata for Debuggable where T: Sized + core::fmt::Debug + ComponentValue, { - fn attach(_: ComponentInfo, buffer: &mut ComponentBuffer) { + fn attach(_: ComponentDesc, buffer: &mut ComponentBuffer) { buffer.set( debuggable(), Debuggable { diff --git a/src/metadata/mod.rs b/src/metadata/mod.rs index ac8840ea..06c1e359 100644 --- a/src/metadata/mod.rs +++ b/src/metadata/mod.rs @@ -1,6 +1,6 @@ use crate::buffer::ComponentBuffer; use crate::components::name; -use crate::{ComponentInfo, ComponentValue}; +use crate::{ComponentDesc, ComponentValue}; mod debuggable; mod relation; @@ -13,7 +13,7 @@ pub use relation::*; /// components. pub trait Metadata { /// Attach the metadata to the component buffer - fn attach(info: ComponentInfo, buffer: &mut ComponentBuffer); + fn attach(desc: ComponentDesc, buffer: &mut ComponentBuffer); } #[derive(Debug, Clone)] @@ -24,8 +24,8 @@ impl Metadata for Name where T: ComponentValue, { - fn attach(info: ComponentInfo, buffer: &mut ComponentBuffer) { - buffer.set(name(), info.name().into()); + fn attach(desc: ComponentDesc, buffer: &mut ComponentBuffer) { + buffer.set(name(), desc.name().into()); } } diff --git a/src/metadata/relation.rs b/src/metadata/relation.rs index 82fef18b..d6a0116e 100644 --- a/src/metadata/relation.rs +++ b/src/metadata/relation.rs @@ -26,7 +26,7 @@ pub struct Exclusive; //pub struct Symmetric; impl Metadata for Exclusive { - fn attach(_: crate::ComponentInfo, buffer: &mut crate::buffer::ComponentBuffer) { + fn attach(_: crate::ComponentDesc, buffer: &mut crate::buffer::ComponentBuffer) { buffer.set(exclusive(), Exclusive); } } diff --git a/src/query/difference.rs b/src/query/difference.rs index 0a0026ac..fbf74aeb 100644 --- a/src/query/difference.rs +++ b/src/query/difference.rs @@ -1,6 +1,6 @@ use core::iter::Peekable; -use crate::{component_info, ArchetypeId, ComponentInfo, Fetch, World}; +use crate::{component_info, ArchetypeId, ComponentDesc, Fetch, World}; /// Returns all items in left not in right struct SetDifference, R: Iterator> { @@ -47,7 +47,7 @@ pub(crate) fn find_missing_components<'q, 'a, Q>( fetch: &Q, arch_id: ArchetypeId, world: &'a World, -) -> impl Iterator + 'a +) -> impl Iterator + 'a where Q: Fetch<'a>, { diff --git a/src/query/entity.rs b/src/query/entity.rs index e28eb4cf..c5330977 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -32,7 +32,7 @@ fn state<'w, 'a, Q: Fetch<'w>, F: Fetch<'w>>( let Some(mut p) = state.prepare_fetch(loc.arch_id, arch) else { return match find_missing_components(state.fetch, loc.arch_id, state.world).next() { - Some(missing) => Err(Error::MissingComponent(MissingComponent{id,info: missing})), + Some(missing) => Err(Error::MissingComponent(MissingComponent{id,desc: missing})), None => Err(Error::DoesNotMatch(id)), } }; @@ -158,7 +158,7 @@ mod test { query.borrow(&world).get(), Err(Error::MissingComponent(MissingComponent { id, - info: name().info() + desc: name().desc() })) ); world.set(id, name(), "Bar".into()).unwrap(); diff --git a/src/query/mod.rs b/src/query/mod.rs index 142998b5..b6d1eaf7 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -398,7 +398,7 @@ mod test { borrow.get(id4), Err(Error::MissingComponent(MissingComponent { id: id4, - info: b().info() + desc: b().desc() })) ); } diff --git a/src/query/planar.rs b/src/query/planar.rs index 250652b4..973a5076 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -277,7 +277,7 @@ where self.prepare_archetype(arch_id).ok_or_else(|| { match find_missing_components(self.state.fetch, arch_id, self.state.world).next() { Some(missing) => { - Error::MissingComponent(MissingComponent { id, info: missing }) + Error::MissingComponent(MissingComponent { id, desc: missing }) } None => Error::DoesNotMatch(id), } diff --git a/src/serialize/de.rs b/src/serialize/de.rs index 2cd4b129..e8665e43 100644 --- a/src/serialize/de.rs +++ b/src/serialize/de.rs @@ -8,7 +8,7 @@ use serde::{ use crate::{ archetype::{BatchSpawn, Storage}, - Component, ComponentInfo, ComponentValue, Entity, EntityBuilder, World, + Component, ComponentDesc, ComponentValue, Entity, EntityBuilder, World, }; use super::{RowFields, SerializeFormat, WorldFields}; @@ -19,14 +19,14 @@ struct Slot { deser_col: fn( deserializer: &mut dyn erased_serde::Deserializer, len: usize, - component: ComponentInfo, + component: ComponentDesc, ) -> erased_serde::Result, deser_one: fn( deserializer: &mut dyn erased_serde::Deserializer, - component: ComponentInfo, + component: ComponentDesc, builder: &mut EntityBuilder, ) -> erased_serde::Result<()>, - info: ComponentInfo, + desc: ComponentDesc, } /// [ T, T, T ] @@ -43,7 +43,7 @@ impl<'a, 'de> DeserializeSeed<'de> for DeserializeStorage<'a> { D: Deserializer<'de>, { let mut deserializer = ::erase(deserializer); - let storage = (self.slot.deser_col)(&mut deserializer, self.len, self.slot.info) + let storage = (self.slot.deser_col)(&mut deserializer, self.len, self.slot.desc) .map_err(de::Error::custom)?; Ok(storage) @@ -80,10 +80,10 @@ impl DeserializeBuilder { fn deser_col Deserialize<'x>>( deserializer: &mut dyn erased_serde::Deserializer, len: usize, - info: ComponentInfo, + desc: ComponentDesc, ) -> erased_serde::Result { deserializer.deserialize_seq(StorageVisitor:: { - info, + desc, cap: len, _marker: PhantomData, }) @@ -91,11 +91,11 @@ impl DeserializeBuilder { fn deser_one Deserialize<'x>>( deserializer: &mut dyn erased_serde::Deserializer, - info: ComponentInfo, + desc: ComponentDesc, builder: &mut EntityBuilder, ) -> erased_serde::Result<()> { let value = T::deserialize(deserializer)?; - builder.set(info.downcast(), value); + builder.set(desc.downcast(), value); Ok(()) } @@ -106,7 +106,7 @@ impl DeserializeBuilder { Slot { deser_col: deser_col::, deser_one: deser_one::, - info: component.info(), + desc: component.desc(), }, ); self @@ -315,7 +315,7 @@ impl<'de, 'a> DeserializeSeed<'de> for DeserializeComponent<'a> { D: Deserializer<'de>, { let mut deserializer = ::erase(deserializer); - (self.slot.deser_one)(&mut deserializer, self.slot.info, self.builder) + (self.slot.deser_one)(&mut deserializer, self.slot.desc, self.builder) .map_err(de::Error::custom)?; Ok(()) @@ -576,7 +576,7 @@ impl<'de, 'a> Visitor<'de> for StoragesVisitor<'a> { /// Visit a single column of component values struct StorageVisitor { - info: ComponentInfo, + desc: ComponentDesc, cap: usize, _marker: PhantomData, } @@ -592,7 +592,7 @@ impl<'de, T: ComponentValue + de::Deserialize<'de>> Visitor<'de> for StorageVisi where A: SeqAccess<'de>, { - let mut storage = Storage::with_capacity(self.info, self.cap); + let mut storage = Storage::with_capacity(self.desc, self.cap); while let Some(item) = seq.next_element::()? { unsafe { storage.push(item) } diff --git a/src/system/mod.rs b/src/system/mod.rs index edb4bc3c..a296963f 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -497,7 +497,7 @@ pub(crate) fn access_info(accesses: &[Access], world: &World) -> AccessInfo { .archetypes .entry(id) .or_insert_with(|| ArchetypeAccess { - arch: arch.info(), + arch: arch.desc(), ..Default::default() }) .components @@ -513,7 +513,7 @@ pub(crate) fn access_info(accesses: &[Access], world: &World) -> AccessInfo { .archetypes .entry(id) .or_insert_with(|| ArchetypeAccess { - arch: arch.info(), + arch: arch.desc(), ..Default::default() }) .change_events diff --git a/src/vtable.rs b/src/vtable.rs index 1692b0d5..202de1ae 100644 --- a/src/vtable.rs +++ b/src/vtable.rs @@ -2,29 +2,29 @@ use core::{alloc::Layout, any::TypeId, marker::PhantomData, mem, ptr::NonNull}; use once_cell::sync::OnceCell; -use crate::{buffer::ComponentBuffer, ComponentInfo, ComponentValue}; +use crate::{buffer::ComponentBuffer, ComponentDesc, ComponentValue}; #[doc(hidden)] pub struct LazyComponentBuffer { value: OnceCell, - init: fn(ComponentInfo) -> ComponentBuffer, + init: fn(ComponentDesc) -> ComponentBuffer, } impl LazyComponentBuffer { /// Creates a new component buffer which can also be recreated - pub const fn new(init: fn(ComponentInfo) -> ComponentBuffer) -> Self { + pub const fn new(init: fn(ComponentDesc) -> ComponentBuffer) -> Self { Self { value: OnceCell::new(), init, } } - pub(crate) fn get_ref(&self, info: ComponentInfo) -> &ComponentBuffer { - self.value.get_or_init(|| (self.init)(info)) + pub(crate) fn get_ref(&self, desc: ComponentDesc) -> &ComponentBuffer { + self.value.get_or_init(|| (self.init)(desc)) } - pub(crate) fn get(&self, info: ComponentInfo) -> ComponentBuffer { - (self.init)(info) + pub(crate) fn get(&self, desc: ComponentDesc) -> ComponentBuffer { + (self.init)(desc) } } diff --git a/src/world.rs b/src/world.rs index a611e277..2a728c21 100644 --- a/src/world.rs +++ b/src/world.rs @@ -29,7 +29,7 @@ use crate::{ writer::{ self, EntityWriter, FnWriter, Replace, ReplaceDyn, SingleComponentWriter, WriteDedup, }, - ArchetypeId, BatchSpawn, Component, ComponentInfo, ComponentKey, ComponentVTable, + ArchetypeId, BatchSpawn, Component, ComponentDesc, ComponentKey, ComponentVTable, ComponentValue, Error, Fetch, Query, RefMut, RelationExt, }; @@ -219,8 +219,8 @@ impl World { let (arch_id, _) = self.archetypes.find_create(buffer.components().copied()); let (loc, arch) = self.spawn_at_inner(id, arch_id)?; - for (info, src) in buffer.drain() { - unsafe { arch.push(info.key(), src, change_tick) } + for (desc, src) in buffer.drain() { + unsafe { arch.push(desc.key(), src, change_tick) } } Ok((id, loc)) @@ -239,9 +239,9 @@ impl World { let (id, _, arch) = self.spawn_inner(arch_id, EntityKind::empty()); - for (info, src) in buffer.drain() { + for (desc, src) in buffer.drain() { unsafe { - arch.push(info.key, src, change_tick); + arch.push(desc.key, src, change_tick); } } @@ -288,7 +288,7 @@ impl World { let src = self.archetypes.get(loc.arch_id); let change_tick = self.advance_change_tick(); - let dst_components: SmallVec<[ComponentInfo; 8]> = + let dst_components: SmallVec<[ComponentDesc; 8]> = src.components().filter(|v| f(v.key())).collect(); let (dst_id, _) = self.archetypes.find_create(dst_components); @@ -318,20 +318,20 @@ impl World { } /// Set metadata for a given component if they do not already exist - pub(crate) fn init_component(&mut self, info: ComponentInfo) { + pub(crate) fn init_component(&mut self, desc: ComponentDesc) { assert!( - info.key().id.kind().contains(EntityKind::COMPONENT), + desc.key().id.kind().contains(EntityKind::COMPONENT), "Component is not a component kind id" ); - if self.is_alive(info.key.id()) { + if self.is_alive(desc.key.id()) { return; } - let id = info.key().id; - let mut meta = info.get_meta(); - meta.set(component_info(), info); - meta.set(name(), info.name().into()); + let id = desc.key().id; + let mut meta = desc.get_meta(); + meta.set(component_info(), desc); + meta.set(name(), desc.name().into()); if id.is_static() { meta.set(is_static(), ()); @@ -485,7 +485,7 @@ impl World { .update(slot, component, FnWriter::new(f), change_tick) .ok_or(Error::MissingComponent(MissingComponent { id, - info: component.info(), + desc: component.desc(), })) } @@ -508,7 +508,7 @@ impl World { .update(slot, component, WriteDedup::new(value), tick) .ok_or(Error::MissingComponent(MissingComponent { id, - info: component.info(), + desc: component.desc(), })) } @@ -524,7 +524,7 @@ impl World { Ok(self .set_with_writer( id, - SingleComponentWriter::new(component.info(), Replace::new(value)), + SingleComponentWriter::new(component.desc(), Replace::new(value)), )? .1 .left()) @@ -541,11 +541,11 @@ impl World { pub(crate) fn set_dyn( &mut self, id: Entity, - info: ComponentInfo, + desc: ComponentDesc, value: *mut u8, ) -> Result { let (loc, _) = - self.set_with_writer(id, SingleComponentWriter::new(info, ReplaceDyn { value }))?; + self.set_with_writer(id, SingleComponentWriter::new(desc, ReplaceDyn { value }))?; Ok(loc) } @@ -565,7 +565,7 @@ impl World { } #[inline] - pub(crate) fn remove_dyn(&mut self, id: Entity, component: ComponentInfo) -> Result<()> { + pub(crate) fn remove_dyn(&mut self, id: Entity, component: ComponentDesc) -> Result<()> { unsafe { self.remove_inner(id, component, |ptr| component.drop(ptr)) .map(|_| {}) @@ -575,7 +575,7 @@ impl World { pub(crate) unsafe fn remove_inner( &mut self, id: Entity, - component: ComponentInfo, + desc: ComponentDesc, on_drop: impl FnOnce(*mut u8), ) -> Result { let EntityLocation { @@ -585,19 +585,16 @@ impl World { let src = self.archetypes.get(src_id); - if !src.has(component.key()) { - return Err(Error::MissingComponent(MissingComponent { - id, - info: component, - })); + if !src.has(desc.key()) { + return Err(Error::MissingComponent(MissingComponent { id, desc })); } - let dst_id = match src.incoming(component.key()) { + let dst_id = match src.incoming(desc.key()) { Some(dst) => dst, None => { let components = src .components() - .filter(|v| v.key != component.key()) + .filter(|v| v.key != desc.key()) .collect_vec(); let (dst_id, _) = self.archetypes.find_create(components); @@ -611,8 +608,8 @@ impl World { assert_ne!(src_id, dst_id); // Borrow disjoint let (src, dst) = self.archetypes.get_disjoint(src_id, dst_id).unwrap(); - src.add_incoming(component.key(), dst_id); - dst.add_outgoing(component.key(), src_id); + src.add_incoming(desc.key(), dst_id); + dst.add_outgoing(desc.key(), src_id); // Take the value // This moves the differing value out of the archetype before it is @@ -654,7 +651,7 @@ impl World { pub fn remove(&mut self, id: Entity, component: Component) -> Result { let mut res: MaybeUninit = MaybeUninit::uninit(); let res = unsafe { - self.remove_inner(id, component.info(), |ptr| { + self.remove_inner(id, component.desc(), |ptr| { res.write(ptr.cast::().read()); })?; @@ -674,7 +671,7 @@ impl World { self.get_at(loc, component).ok_or_else(|| { Error::MissingComponent(MissingComponent { id, - info: component.info(), + desc: component.desc(), }) }) } @@ -713,7 +710,7 @@ impl World { self.get_mut_at(loc, component).ok_or_else(|| { Error::MissingComponent(MissingComponent { id, - info: component.info(), + desc: component.desc(), }) }) } @@ -906,11 +903,11 @@ impl World { // The id is not used by anything else let component = Component::new(ComponentKey::new(id, None), vtable); - let info = component.info(); + let desc = component.desc(); - let mut meta = info.get_meta(); - meta.set(component_info(), info); - meta.set(crate::name(), info.name().into()); + let mut meta = desc.get_meta(); + meta.set(component_info(), desc); + meta.set(crate::name(), desc.name().into()); self.set_with(id, &mut meta).unwrap(); component @@ -1021,7 +1018,7 @@ impl World { /// Returns a human friendly breakdown of the archetypes in the world pub fn archetype_info(&self) -> BTreeMap { - self.archetypes.iter().map(|(k, v)| (k, v.info())).collect() + self.archetypes.iter().map(|(k, v)| (k, v.desc())).collect() } /// Attempt to find an alive entity given the id @@ -1035,14 +1032,14 @@ impl World { pub fn find_component(&self, id: ComponentKey) -> Option> { let e = self.entity(id.id).ok()?; - let info = e.get(component_info()).ok()?; + let desc = e.get(component_info()).ok()?; - if !info.is::() { - panic!("Attempt to construct a component from the wrong type. Found: {info:#?}"); + if !desc.is::() { + panic!("Attempt to construct a component from the wrong type. Found: {desc:#?}"); } // Safety: the type - Some(Component::from_raw_parts(id, info.vtable)) + Some(Component::from_raw_parts(id, desc.vtable)) } /// Access, insert, and remove all components of an entity @@ -1169,7 +1166,7 @@ impl World { let arch = arch.drain(); for mut cell in arch.cells.into_values() { let mut storage = cell.drain(); - let mut id = storage.info().key; + let mut id = storage.desc().key; // Modify the relations to match new components id.id = *new_ids.get(&id.id).unwrap_or(&id.id); @@ -1201,8 +1198,8 @@ impl World { // Take each entity one by one and append them to the world if arch.has(is_static().key()) { while let Some(id) = unsafe { - arch.pop_last(|mut info, ptr| { - let key = &mut info.key; + arch.pop_last(|mut desc, ptr| { + let key = &mut desc.key; // Modify the relations to match new components key.id = *new_ids.get(&key.id).unwrap_or(&key.id); @@ -1212,7 +1209,7 @@ impl World { } // Migrate custom components - buffer.set_dyn(info, ptr); + buffer.set_dyn(desc, ptr); }) } { buffer.append_to(self, id).unwrap(); @@ -1358,7 +1355,7 @@ mod tests { // () -> (a) -> (ab) -> (abc) let (_, archetype) = world .archetypes - .find_create([a().info(), b().info(), c().info()]); + .find_create([a().desc(), b().desc(), c().desc()]); assert!(!archetype.has(d().key())); assert!(archetype.has(a().key())); assert!(archetype.has(b().key())); @@ -1367,7 +1364,7 @@ mod tests { // -> (abd) let (_, archetype) = world .archetypes - .find_create([a().info(), b().info(), d().info()]); + .find_create([a().desc(), b().desc(), d().desc()]); assert!(archetype.has(d().key())); assert!(!archetype.has(c().key())); } @@ -1385,7 +1382,7 @@ mod tests { world.get(id, b()).as_deref(), Err(&Error::MissingComponent(MissingComponent { id, - info: b().info() + desc: b().desc() })) ); assert!(!world.has(id, c())); @@ -1402,7 +1399,7 @@ mod tests { world.get(id, b()).as_deref(), Err(&Error::MissingComponent(MissingComponent { id, - info: b().info() + desc: b().desc() })) ); @@ -1476,7 +1473,7 @@ mod tests { world.get(id, e()).as_deref(), Err(&Error::MissingComponent(MissingComponent { id, - info: e().info() + desc: e().desc() })) ); diff --git a/src/writer.rs b/src/writer.rs index af2b62a0..411b0bfb 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -9,7 +9,7 @@ use crate::{ entity::EntityLocation, metadata::exclusive, world::update_entity_loc, - ArchetypeId, ComponentInfo, ComponentValue, Entity, World, + ArchetypeId, ComponentDesc, ComponentValue, Entity, World, }; /// Describes a modification to the components of an entity within the context of an archetype @@ -78,13 +78,13 @@ pub unsafe trait EntityWriter { } pub(crate) struct SingleComponentWriter { - info: ComponentInfo, + desc: ComponentDesc, writer: W, } impl SingleComponentWriter { - pub(crate) fn new(info: ComponentInfo, writer: W) -> Self { - Self { info, writer } + pub(crate) fn new(desc: ComponentDesc, writer: W) -> Self { + Self { desc, writer } } } @@ -98,7 +98,7 @@ unsafe impl EntityWriter for SingleCompon src_loc: EntityLocation, tick: u32, ) -> (EntityLocation, Self::Output) { - let key = self.info.key(); + let key = self.desc.key(); let arch = world.archetypes.get_mut(src_loc.arch_id); @@ -119,16 +119,16 @@ unsafe impl EntityWriter for SingleCompon (src, dst, dst_id) } else { // Oh no! The archetype is missing the component - let exclusive = if self.info.meta_ref().has(exclusive()) { - slice::from_ref(&self.info.key.id) + let exclusive = if self.desc.meta_ref().has(exclusive()) { + slice::from_ref(&self.desc.key.id) } else { &[] }; let (components, superset) = - find_archetype_components(arch.components(), [self.info], exclusive); + find_archetype_components(arch.components(), [self.desc], exclusive); - world.init_component(self.info); + world.init_component(self.desc); let (dst_id, _) = world.archetypes.find_create(components.iter().copied()); // Add a quick edge to refer to later @@ -266,13 +266,13 @@ impl ComponentUpdater for ReplaceDyn { type Updated = (); unsafe fn update(self, data: &mut CellData, slot: Slot, id: Entity, tick: u32) { - let info = data.storage.info(); + let desc = data.storage.desc(); unsafe { let dst = data.storage.at_mut(slot).unwrap(); - info.drop(dst); + desc.drop(dst); - ptr::copy_nonoverlapping(self.value, dst, info.size()); + ptr::copy_nonoverlapping(self.value, dst, desc.size()); } data.set_modified(&[id], Slice::single(slot), tick); @@ -314,16 +314,16 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { let arch = world.archetypes.get_mut(src_loc.arch_id); unsafe { - self.buffer.retain(|info, src| { - let key = info.key; + self.buffer.retain(|desc, src| { + let key = desc.key; // The component exists in the current archetype // This implies that is it also satisfies any exclusive properties if let Some(cell) = arch.cell_mut(key) { let data = cell.data.get_mut(); let dst = data.storage.at_mut(src_loc.slot).unwrap(); - info.drop(dst); - ptr::copy_nonoverlapping(src, dst, info.size()); + desc.drop(dst); + ptr::copy_nonoverlapping(src, dst, desc.size()); data.set_modified(&[id], Slice::single(src_loc.slot), tick); false @@ -331,7 +331,7 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { // Component does not exist yet, so defer a move // Exclusive relation - if key.object.is_some() && info.meta_ref().has(exclusive()) { + if key.object.is_some() && desc.meta_ref().has(exclusive()) { if exclusive_relations.contains(&key.id) { panic!("Multiple exclusive relations"); } @@ -355,8 +355,8 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { &exclusive_relations, ); - for &info in self.buffer.components() { - world.init_component(info); + for &desc in self.buffer.components() { + world.init_component(desc); } let (dst_id, _) = world.archetypes.find_create(components); @@ -370,9 +370,9 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { unsafe { src.move_to(dst, src_loc.slot, |c, ptr| c.drop(ptr), tick) }; // Insert the missing components - for (info, src) in self.buffer.drain() { + for (desc, src) in self.buffer.drain() { unsafe { - dst.push(info.key, src, tick); + dst.push(desc.key, src, tick); } } @@ -389,11 +389,11 @@ unsafe impl<'b> EntityWriter for Buffered<'b> { } fn find_archetype_components( - current_components: impl IntoIterator, - new_components: impl IntoIterator, + current_components: impl IntoIterator, + new_components: impl IntoIterator, // Subset of `new_components` exclusive: &[Entity], -) -> (Vec, bool) { +) -> (Vec, bool) { let mut superset = true; let res = new_components .into_iter() diff --git a/tests/components.rs b/tests/components.rs index bf5d4278..0d154d47 100644 --- a/tests/components.rs +++ b/tests/components.rs @@ -11,9 +11,9 @@ use glam::{vec2, Vec2}; fn custom_component() { let mut world = World::new(); - static META: LazyComponentBuffer = LazyComponentBuffer::new(|info| { + static META: LazyComponentBuffer = LazyComponentBuffer::new(|desc| { let mut buf = ComponentBuffer::new(); - >::attach(info, &mut buf); + >::attach(desc, &mut buf); buf }); @@ -35,7 +35,7 @@ fn custom_component() { world.get(id, position).as_deref(), Err(&Error::MissingComponent(MissingComponent { id, - info: position.info() + desc: position.desc() })), ); } diff --git a/tests/entity.rs b/tests/entity.rs index 8c3eebd2..d3c0aeb9 100644 --- a/tests/entity.rs +++ b/tests/entity.rs @@ -138,7 +138,7 @@ fn entity_hierarchy() { entity.get(a()).as_deref(), Err(&MissingComponent { id, - info: a().info() + desc: a().desc() }) ); diff --git a/tests/entity_builder.rs b/tests/entity_builder.rs index 2cb8d791..41f275b9 100644 --- a/tests/entity_builder.rs +++ b/tests/entity_builder.rs @@ -30,7 +30,7 @@ fn entity_builder() { world.get(id2, b()).as_deref(), Err(&Error::MissingComponent(MissingComponent { id: id2, - info: b().info() + desc: b().desc() })) ); @@ -56,7 +56,7 @@ fn entity_builder() { world.get(id3, relation(id2)).as_deref(), Err(&Error::MissingComponent(MissingComponent { id: id3, - info: relation(id2).info() + desc: relation(id2).desc() })) ); @@ -84,7 +84,7 @@ fn entity_builder_cmd() { world.get(id2, b()).as_deref(), Err(&Error::MissingComponent(MissingComponent { id: id2, - info: b().info() + desc: b().desc() })) ); @@ -108,7 +108,7 @@ fn entity_builder_cmd() { world.get(id3, relation(id2)).as_deref(), Err(&Error::MissingComponent(MissingComponent { id: id3, - info: relation(id2).info() + desc: relation(id2).desc() })) ); From 677ffdcf137749d7e66558330fe3d5f7c6693879 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 30 Jul 2023 15:11:10 +0200 Subject: [PATCH 41/52] fix: use of std --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 42fb762d..91844706 100644 --- a/src/error.rs +++ b/src/error.rs @@ -30,7 +30,7 @@ impl Error { return anyhow::Error::new(self); } - pub(crate) fn try_into_missing_component(self) -> std::result::Result { + pub(crate) fn try_into_missing_component(self) -> core::result::Result { if let Self::MissingComponent(v) = self { Ok(v) } else { From e032971265aec4f44f96e7a9307ffbd5dac3ea40 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Thu, 3 Aug 2023 00:14:15 +0200 Subject: [PATCH 42/52] wip: fetch rework --- src/archetype/guard.rs | 60 ++++++++++++-------------------- src/archetype/mod.rs | 8 ++--- src/fetch/as_deref.rs | 12 ++++--- src/fetch/cloned.rs | 16 +++------ src/fetch/component.rs | 22 +++++++++--- src/fetch/component_mut.rs | 40 +++++++++++++++------ src/fetch/copied.rs | 16 +++------ src/fetch/entity_ref.rs | 31 +++++++++++++---- src/fetch/map.rs | 15 ++++---- src/fetch/maybe_mut.rs | 36 ++++++++++++++----- src/fetch/mod.rs | 71 +++++++++++++++++++++++--------------- src/fetch/opt.rs | 40 ++++++++++----------- src/fetch/relations.rs | 23 ++++++++++-- src/fetch/satisfied.rs | 24 ++++++++++--- src/fetch/source.rs | 17 ++++++--- src/query/borrow.rs | 4 ++- src/query/iter.rs | 52 ++++++++++++++++++++++++---- src/query/planar.rs | 39 +++++++++++++++++++-- tests/entity.rs | 68 ++++++++++++++++++------------------ 19 files changed, 384 insertions(+), 210 deletions(-) diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index dccd114c..655f109e 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -35,17 +35,10 @@ impl<'a, T: ComponentValue + Sized> CellMutGuard<'a, [T]> { } impl<'a, T: ?Sized> CellMutGuard<'a, T> { - pub(crate) fn set_modified(&mut self, entities: &[Entity], slots: Slice, tick: u32) { + pub(crate) fn set_modified(&mut self, ids: &[Entity], slots: Slice, tick: u32) { // SAFETY: `value` is not accessed in this function let data = &mut *self.data; - data.on_event(EventData { - ids: &entities[slots.as_range()], - key: data.key, - kind: EventKind::Modified, - }); - - data.changes - .set_modified_if_tracking(Change::new(slots, tick)); + data.set_modified(ids, slots, tick) } pub(crate) fn filter_map( @@ -59,25 +52,23 @@ impl<'a, T: ?Sized> CellMutGuard<'a, T> { storage, }) } -} -impl<'w, T: ?Sized> Deref for CellMutGuard<'w, T> { - type Target = T; + pub(crate) fn storage(&self) -> NonNull { + self.storage + } - fn deref(&self) -> &Self::Target { + pub(crate) fn get(&self) -> &T { unsafe { self.storage.as_ref() } } -} -impl<'w, T: ?Sized> DerefMut for CellMutGuard<'w, T> { - fn deref_mut(&mut self) -> &mut Self::Target { + pub(crate) fn get_mut(&mut self) -> &mut T { unsafe { self.storage.as_mut() } } } impl<'a, T: Debug + ?Sized> Debug for CellMutGuard<'a, T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - (**self).fmt(f) + (*self.get()).fmt(f) } } @@ -103,7 +94,7 @@ impl<'a, T: ComponentValue + Sized> CellGuard<'a, [T]> { impl<'a, T: ?Sized> CellGuard<'a, T> { #[inline] - pub fn into_slice_ref(self) -> AtomicRef<'a, T> { + pub(crate) fn into_inner(self) -> AtomicRef<'a, T> { AtomicRef::map(self.data, |_| unsafe { self.storage.as_ref() }) } @@ -111,19 +102,15 @@ impl<'a, T: ?Sized> CellGuard<'a, T> { pub(crate) fn changes(&self) -> &Changes { &self.data.changes } -} -impl<'a, T: Debug + ?Sized> Debug for CellGuard<'a, T> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - (**self).fmt(f) + pub(crate) fn get(&self) -> &T { + unsafe { self.storage.as_ref() } } } -impl<'w, T: ?Sized> Deref for CellGuard<'w, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { self.storage.as_ref() } +impl<'a, T: Debug + ?Sized> Debug for CellGuard<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + (*self.get()).fmt(f) } } @@ -133,8 +120,7 @@ impl<'w, T: ?Sized> Deref for CellGuard<'w, T> { pub struct RefMut<'a, T> { guard: CellMutGuard<'a, T>, - // All entities in the archetype - ids: &'a [Entity], + id: Entity, slot: Slot, modified: bool, tick: u32, @@ -143,7 +129,7 @@ pub struct RefMut<'a, T> { impl<'a, T: ComponentValue> RefMut<'a, T> { pub(super) fn new( guard: CellMutGuard<'a, [T]>, - ids: &'a [Entity], + id: Entity, slot: Slot, tick: u32, ) -> Option { @@ -152,7 +138,7 @@ impl<'a, T: ComponentValue> RefMut<'a, T> { Some(Self { guard, - ids, + id, slot, modified: false, tick, @@ -171,7 +157,7 @@ impl<'a, T> Deref for RefMut<'a, T> { #[inline] fn deref(&self) -> &Self::Target { - &self.guard + &self.guard.get() } } @@ -179,7 +165,7 @@ impl<'a, T> DerefMut for RefMut<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.modified = true; - &mut self.guard + &mut self.guard.get_mut() } } @@ -188,11 +174,9 @@ impl<'a, T> Drop for RefMut<'a, T> { fn drop(&mut self) { if self.modified { // SAFETY: `value` is not accessed beyond this point - self.guard.data.set_modified( - &self.ids[self.slot..=self.slot], - Slice::single(self.slot), - self.tick, - ) + self.guard + .data + .set_modified(&[self.id], Slice::single(self.slot), self.tick) } } } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 0cbcc813..822fb8e0 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -252,11 +252,11 @@ impl Cell { #[inline] pub fn get_mut<'a, T: ComponentValue>( &'a self, - entities: &'a [Entity], + id: Entity, slot: Slot, tick: u32, ) -> Option> { - RefMut::new(self.borrow_mut(), entities, slot, tick) + RefMut::new(self.borrow_mut(), id, slot, tick) } } @@ -452,7 +452,7 @@ impl Archetype { tick: u32, ) -> Option> { self.cell(component.key())? - .get_mut(&self.entities, slot, tick) + .get_mut(self.entities[slot], slot, tick) } /// Get a component from the entity at `slot` @@ -467,7 +467,7 @@ impl Archetype { None => return Ok(None), }; - Ok(cell.get_mut(&self.entities, slot, tick)) + Ok(cell.get_mut(self.entities[slot], slot, tick)) } /// Get a component from the entity at `slot` diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index 8d9158a2..eb19cf7f 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -57,16 +57,18 @@ where { type Item = &'q V::Target; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.0.fetch(slot) - } + type Batch = F::Batch; unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { self.0.filter_slots(slots) } - fn set_visited(&mut self, slots: crate::archetype::Slice) { - self.0.set_visited(slots) + unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + self.0.create_batch(slots) + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + F::fetch_next(batch) } } diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index a51aefe3..646f31a0 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -71,20 +71,14 @@ where V: 'static + Clone, { type Item = V; + type Batch = F::Batch; - #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.0.fetch(slot).clone() + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.0.create_batch(slots) } - #[inline] - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - self.0.filter_slots(slots) - } - - #[inline] - fn set_visited(&mut self, slots: Slice) { - self.0.set_visited(slots) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + F::fetch_next(batch).clone() } } diff --git a/src/fetch/component.rs b/src/fetch/component.rs index 56435498..b6ce91ef 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -1,3 +1,5 @@ +use core::slice; + use atomic_refcell::AtomicRef; use crate::{archetype::Slot, system::AccessKind, Component, ComponentValue}; @@ -12,10 +14,20 @@ pub struct ReadComponent<'a, T> { impl<'q, 'w, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { type Item = &'q T; - #[inline(always)] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - // Safety: bounds guaranteed by callee - unsafe { self.borrow.get_unchecked(slot) } + // #[inline(always)] + // unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + // // Safety: bounds guaranteed by callee + // unsafe { self.borrow.get_unchecked(slot) } + // } + + type Batch = slice::Iter<'q, T>; + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.borrow[slots.as_range()].iter() + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + batch.next().unwrap() } } @@ -37,7 +49,7 @@ where fn prepare(&self, data: FetchPrepareData<'w>) -> Option { let borrow = data.arch.borrow(self.key())?; Some(ReadComponent { - borrow: borrow.into_slice_ref(), + borrow: borrow.into_inner(), }) } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index dc32d746..1973faa8 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -1,6 +1,9 @@ use alloc::vec::Vec; -use core::fmt::{self, Formatter}; +use core::{ + fmt::{self, Formatter}, + slice, +}; use crate::{ archetype::{Archetype, CellMutGuard, Slice, Slot}, @@ -84,17 +87,34 @@ pub struct WriteComponent<'a, T> { impl<'q, 'w, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> { type Item = &'q mut T; + type Batch = slice::IterMut<'q, T>; + + // #[inline(always)] + // unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + // // Perform a reborrow + // // Cast from a immutable to a mutable borrow as all calls to this + // // function are guaranteed to be disjoint + // unsafe { &mut *(self.guard.get_unchecked_mut(slot) as *mut T) } + // } + + // fn set_visited(&mut self, slots: Slice) { + // self.guard + // .set_modified(&self.arch.entities, slots, self.tick); + // } + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.guard + .set_modified(&self.arch.entities[slots.as_range()], slots, self.tick); - #[inline(always)] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - // Perform a reborrow - // Cast from a immutable to a mutable borrow as all calls to this - // function are guaranteed to be disjoint - unsafe { &mut *(self.guard.get_unchecked_mut(slot) as *mut T) } + // Convert directly into a non-overlapping subslice without reading the whole slice + let ptr = (self.guard.storage().as_ptr() as *mut T).add(slots.start); + + let slice = slice::from_raw_parts_mut(ptr, slots.len()); + slice.iter_mut() } - fn set_visited(&mut self, slots: Slice) { - self.guard - .set_modified(&self.arch.entities, slots, self.tick); + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + // TODO: raw stepping slice access + batch.next().unwrap() } } diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index ad160e60..2881818e 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -72,20 +72,14 @@ where V: 'static + Copy, { type Item = V; + type Batch = F::Batch; - #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - *self.0.fetch(slot) + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.0.create_batch(slots) } - #[inline] - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - self.0.filter_slots(slots) - } - - #[inline] - fn set_visited(&mut self, slots: Slice) { - self.0.set_visited(slots) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + *F::fetch_next(batch) } } diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index 6ea5e686..5136697f 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -1,9 +1,11 @@ +use core::{iter::Enumerate, slice}; + use alloc::vec::Vec; use crate::{ - archetype::Archetype, + archetype::{Archetype, Slot}, system::{Access, AccessKind}, - EntityRef, Fetch, FetchItem, World, + Entity, EntityRef, Fetch, FetchItem, World, }; use super::{FetchAccessData, PreparedFetch}; @@ -59,16 +61,33 @@ pub struct PreparedEntityRef<'a> { arch: &'a Archetype, } +pub struct Batch<'a> { + pub(crate) world: &'a World, + pub(crate) arch: &'a Archetype, + pub(crate) slot: Slot, +} + impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { type Item = EntityRef<'q>; + type Batch = Batch<'q>; + + unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + Batch { + world: self.world, + arch: self.arch, + slot: slots.start, + } + } #[inline] - unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + let slot = batch.slot; + EntityRef { - arch: self.arch, + arch: batch.arch, + world: batch.world, slot, - id: self.arch.entities()[slot], - world: self.world, + id: batch.arch.entities[slot], } } } diff --git a/src/fetch/map.rs b/src/fetch/map.rs index d84ab9fc..908c66e2 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -63,16 +63,17 @@ where { type Item = T; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - (self.func)(self.query.fetch(slot)) + type Batch = (&'q F, Q::Batch); + + unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + todo!() } - unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { - self.query.filter_slots(slots) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + (batch.0)(Q::fetch_next(&mut batch.1)) } - #[inline] - fn set_visited(&mut self, slots: crate::archetype::Slice) { - self.query.set_visited(slots) + unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { + self.query.filter_slots(slots) } } diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index 31b020c2..4e90c4cf 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use atomic_refcell::AtomicRef; -use core::marker::PhantomData; +use core::{marker::PhantomData, ops::Range}; use crate::{ archetype::{Cell, RefMut, Slot}, @@ -87,16 +87,34 @@ pub struct PreparedMaybeMut<'w, T> { _marker: PhantomData, } +struct Batch<'a> { + cell: &'a Cell, + new_tick: u32, + ids: &'a [Entity], + slot: Slot, +} + impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { type Item = MutGuard<'q, T>; + type Batch = Batch<'q>; - #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - MutGuard { - slot, + unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + Batch { cell: self.cell, new_tick: self.new_tick, - entities: self.entities, + ids: self.entities, + slot: slots.start, + } + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + let slot = batch.slot; + batch.slot += 1; + MutGuard { + slot, + cell: batch.cell, + new_tick: batch.new_tick, + id: batch.ids[slot], _marker: PhantomData, } } @@ -109,7 +127,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { slot, cell: self.cell, new_tick: self.new_tick, - entities: self.entities, + id: self.entities[slot], _marker: PhantomData, } } @@ -120,7 +138,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { /// See: [`MaybeMut`] pub struct MutGuard<'w, T> { slot: Slot, - entities: &'w [Entity], + id: Entity, cell: &'w Cell, new_tick: u32, _marker: PhantomData, @@ -139,7 +157,7 @@ impl<'w, T: ComponentValue> MutGuard<'w, T> { pub fn write(&self) -> RefMut { // Type is guaranteed by constructor self.cell - .get_mut(self.entities, self.slot, self.new_tick) + .get_mut(self.id, self.slot, self.new_tick) .unwrap() } } diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 4e04f854..d4e7db85 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -21,8 +21,8 @@ use crate::{ ArchetypeId, ArchetypeSearcher, Entity, World, }; use alloc::vec::Vec; -use core::fmt::Debug; use core::fmt::{self, Formatter}; +use core::{fmt::Debug, slice}; pub use as_deref::*; pub use cloned::*; @@ -131,6 +131,9 @@ pub trait Fetch<'w>: for<'q> FetchItem<'q> { pub trait PreparedFetch<'q> { /// Item returned by fetch type Item: 'q; + type Batch: 'q; + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch; /// Fetch the item from entity at the slot in the prepared storage. /// # Safety @@ -138,7 +141,7 @@ pub trait PreparedFetch<'q> { /// prepared archetype. /// /// The callee is responsible for assuring disjoint calls. - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item; + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item; #[inline] /// Filter the slots to visit @@ -149,11 +152,6 @@ pub trait PreparedFetch<'q> { unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { slots } - - /// Do something for a slice of entity slots which have been visited, such - /// as updating change tracking for mutable queries. - #[inline] - fn set_visited(&mut self, _slots: Slice) {} } /// Allows filtering the constituent parts of a fetch using a set union @@ -170,17 +168,18 @@ where F: PreparedFetch<'q>, { type Item = F::Item; + type Batch = F::Batch; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - (*self).fetch(slot) + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + (*self).create_batch(slots) } - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - (*self).filter_slots(slots) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + F::fetch_next(batch) } - fn set_visited(&mut self, slots: Slice) { - (*self).set_visited(slots) + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + (*self).filter_slots(slots) } } @@ -222,7 +221,11 @@ impl<'p> ReadOnlyFetch<'p> for () { impl<'q> PreparedFetch<'q> for () { type Item = (); - unsafe fn fetch(&'q mut self, _: Slot) -> Self::Item {} + type Batch = (); + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } impl<'q, F> PreparedFetch<'q> for Option @@ -230,10 +233,14 @@ where F: PreparedFetch<'q>, { type Item = Option; + type Batch = Option; - #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.as_mut().map(|fetch| fetch.fetch(slot)) + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + if let Some(fetch) = self { + Some(fetch.create_batch(slots)) + } else { + None + } } #[inline] @@ -245,10 +252,11 @@ where } } - #[inline] - fn set_visited(&mut self, slots: Slice) { - if let Some(fetch) = self { - fetch.set_visited(slots) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + if let Some(fetch) = batch { + Some(F::fetch_next(fetch)) + } else { + None } } } @@ -291,9 +299,14 @@ impl<'w> Fetch<'w> for EntityIds { impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { type Item = Entity; - #[inline] - unsafe fn fetch(&mut self, slot: usize) -> Self::Item { - self.entities[slot] + type Batch = slice::Iter<'q, Entity>; + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.entities[slots.as_range()].iter() + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + *batch.next().unwrap() } } @@ -332,16 +345,18 @@ macro_rules! tuple_impl { { type Item = ($($ty::Item,)*); + type Batch = ($($ty::Batch,)*); + #[inline] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { ($( - (self.$idx).fetch(slot), + $ty::fetch_next(&mut batch.$idx), )*) } #[inline] - fn set_visited(&mut self, slots: Slice) { - $((self.$idx).set_visited(slots);)* + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + ($((self.$idx).create_batch(slots),)*) } #[inline] diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 389ab070..28b11ed9 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -1,6 +1,7 @@ use core::fmt::{self, Formatter}; use alloc::vec::Vec; +use itertools::Either; use crate::{ archetype::{Archetype, Slice, Slot}, @@ -63,11 +64,7 @@ where F: PreparedFetch<'q>, { type Item = Option; - - #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.0.as_mut().map(|fetch| fetch.fetch(slot)) - } + type Batch = Option; #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -78,11 +75,12 @@ where } } - #[inline] - fn set_visited(&mut self, slots: Slice) { - if let Some(fetch) = &mut self.0 { - fetch.set_visited(slots) - } + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.0.as_mut().map(|v| v.create_batch(slots)) + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + batch.as_mut().map(|v| F::fetch_next(v)) } } @@ -143,13 +141,7 @@ where V: 'q, { type Item = &'q V; - - unsafe fn fetch(&'q mut self, slot: crate::archetype::Slot) -> Self::Item { - match self.fetch { - Some(ref mut v) => v.fetch(slot), - None => self.value, - } - } + type Batch = Either; #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -160,9 +152,17 @@ where } } - fn set_visited(&mut self, slots: Slice) { - if let Some(fetch) = &mut self.fetch { - fetch.set_visited(slots) + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + match self.fetch { + Some(ref mut v) => Either::Left(v.create_batch(slots)), + None => Either::Right(self.value), + } + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + match batch { + Either::Left(v) => F::fetch_next(v), + Either::Right(v) => v, } } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 97e66d83..ca81c69d 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -75,15 +75,32 @@ pub struct PreparedRelations<'a, T> { borrows: SmallVec<[(Entity, CellGuard<'a, [T]>); 4]>, } +pub struct Batch<'a, T> { + borrows: &'a [(Entity, CellGuard<'a, [T]>)], + slot: Slot, +} + impl<'q, 'w, T> PreparedFetch<'q> for PreparedRelations<'w, T> where T: ComponentValue, { type Item = RelationsIter<'q, T>; - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { + type Batch = Batch<'q, T>; + + unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + Batch { + borrows: &self.borrows, + slot: slots.start, + } + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + let slot = batch.slot; + batch.slot += 1; + RelationsIter { - borrows: self.borrows.iter(), + borrows: batch.borrows.iter(), slot, } } @@ -100,7 +117,7 @@ impl<'a, T> Iterator for RelationsIter<'a, T> { fn next(&mut self) -> Option { let (id, borrow) = self.borrows.next()?; - let borrow = &borrow[self.slot]; + let borrow = &borrow.get()[self.slot]; Some((*id, borrow)) } } diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index c99c6a76..26c19b03 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -43,12 +43,28 @@ pub struct PreparedSatisfied(Option); impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { type Item = bool; + type Batch = bool; - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - if let Some(fetch) = &mut self.0 { - !fetch.filter_slots(Slice::single(slot)).is_empty() - } else { + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + let res = self.0.filter_slots(slots); + if res.is_empty() { false + } else { + true + } + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + *batch + } + + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + let res = self.0.filter_slots(slots); + + if res.is_empty() { + Slice::new(slots.start, (slots.start + 1).min(slots.end)) + } else { + res } } } diff --git a/src/fetch/source.rs b/src/fetch/source.rs index a55e5b54..58caf54e 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; use alloc::vec::Vec; use crate::{ - archetype::{Archetype, Slot}, + archetype::{Archetype, Slice, Slot}, entity::EntityLocation, system::Access, ComponentValue, Entity, Fetch, FetchItem, RelationExt, World, @@ -161,13 +161,20 @@ where { type Item = Q::Item; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.fetch_shared(slot) - } - unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { self.fetch.filter_slots(slots) } + + type Batch = Q::Item; + + unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + let mut batch = self.fetch.create_batch(Slice::single(self.slot)); + Q::fetch_next(&mut batch) + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + *batch + } } pub struct PreparedSource { diff --git a/src/query/borrow.rs b/src/query/borrow.rs index 729dd6e0..3c4ae819 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -37,8 +37,10 @@ impl<'w, Q, F> PreparedArchetype<'w, Q, F> { #[inline] pub fn chunks(&mut self) -> ArchetypeChunks { ArchetypeChunks { - iter: FilterIter::new(self.arch.slots(), &mut self.fetch), + fetch: &mut self.fetch as *mut _, + slots: self.arch.slots(), arch: self.arch, + _marker: core::marker::PhantomData, } } } diff --git a/src/query/iter.rs b/src/query/iter.rs index 40db700e..4bb4bdec 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -1,8 +1,10 @@ +use core::ptr::NonNull; + use crate::{ archetype::{Archetype, Slice, Slot}, fetch::PreparedFetch, filter::{FilterIter, Filtered}, - Entity, + Entity, Fetch, }; /// Iterates over a chunk of entities, specified by a predicate. @@ -111,23 +113,59 @@ where /// filters. pub struct ArchetypeChunks<'q, Q, F> { pub(crate) arch: &'q Archetype, - pub(crate) iter: FilterIter<&'q mut Filtered>, + pub(crate) fetch: *mut Filtered, + pub(crate) slots: Slice, + pub(crate) _marker: core::marker::PhantomData<&'q mut ()>, } -impl<'q, Q, F> Iterator for ArchetypeChunks<'q, Q, F> +unsafe impl<'q, Q: 'q, F: 'q> Sync for ArchetypeChunks<'q, Q, F> where &'q mut Filtered: Sync {} +unsafe impl<'q, Q: 'q, F: 'q> Send for ArchetypeChunks<'q, Q, F> where &'q mut Filtered: Send {} + +impl<'q, Q, F> ArchetypeChunks<'q, Q, F> where Q: PreparedFetch<'q>, F: PreparedFetch<'q>, +{ + fn next_slice(slots: &mut Slice, fetch: &mut Filtered) -> Option { + if slots.is_empty() { + return None; + } + + while !slots.is_empty() { + // Safety + // The yielded slots are split off of `self.slots` + let cur = unsafe { fetch.filter_slots(*slots) }; + + let (_l, m, r) = slots + .split_with(&cur) + .expect("Return value of filter must be a subset of `slots"); + + assert_eq!(cur, m); + + *slots = r; + + if !m.is_empty() { + return Some(m); + } + } + + None + } +} +impl<'q, Q, F> Iterator for ArchetypeChunks<'q, Q, F> +where + Q: 'q + PreparedFetch<'q>, + F: 'q + PreparedFetch<'q>, { type Item = Batch<'q, Q, F>; #[inline] fn next(&mut self) -> Option { - // Get the next chunk - let chunk = self.iter.next()?; - // Fetch will never change and all calls are disjoint - let fetch = unsafe { &mut *(self.iter.fetch as *mut Filtered) }; + let fetch = unsafe { &mut *self.fetch }; + + // Get the next chunk + let chunk = Self::next_slice(&mut self.slots, fetch)?; // Set the chunk as visited fetch.set_visited(chunk); diff --git a/src/query/planar.rs b/src/query/planar.rs index 973a5076..4dcbb990 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -1,5 +1,5 @@ use alloc::vec::Vec; -use core::{iter::Flatten, slice::IterMut}; +use core::{iter::Flatten, ptr::NonNull, slice::IterMut}; use smallvec::SmallVec; use crate::{ @@ -323,6 +323,37 @@ where } } +// struct SlicePtrIter { +// ptr: *mut T, +// count: usize, +// } + +// impl SlicePtrIter { +// fn new(slice: *mut [T]) -> Self { +// Self { +// ptr: slice.as_mut_ptr(), +// count: slice.len, +// } +// } +// } + +// impl Iterator for SlicePtrIter { +// type Item = *mut T; + +// fn next(&mut self) -> Option { +// if self.count == 0 { +// return None; +// } + +// self.count -= 1; +// let old = self.ptr; +// unsafe { +// self.ptr = self.ptr.add(1); +// } +// Some(old) +// } +// } + /// An iterator which yields disjoint continuous slices for each matched archetype /// and filter predicate. pub struct BatchedIter<'w, 'q, Q, F> @@ -368,7 +399,11 @@ where } } - let p = self.archetypes.next()?; + let p = unsafe { + &mut *(self.archetypes.next()? + as *mut PreparedArchetype<'w, Q::Prepared, F::Prepared>) + }; + self.current = Some(p.chunks()); } } diff --git a/tests/entity.rs b/tests/entity.rs index d3c0aeb9..9d39a996 100644 --- a/tests/entity.rs +++ b/tests/entity.rs @@ -17,8 +17,8 @@ fn entity_ref() { use pretty_assertions::assert_eq; let mut world = World::new(); - let (tx, changes) = flume::unbounded(); - world.subscribe(tx.filter_components([a().key(), b().key()])); + // let (tx, changes) = flume::unbounded(); + // world.subscribe(tx.filter_components([a().key(), b().key()])); let mut query = Query::new(entity_ids()).filter(a().removed()); @@ -28,41 +28,41 @@ fn entity_ref() { .set(b(), "Foo".into()) .spawn(&mut world); - assert_eq!( - changes.drain().collect_vec(), - [ - Event { - id, - key: a().key(), - kind: EventKind::Added - }, - Event { - id, - key: b().key(), - kind: EventKind::Added - } - ] - ); - - assert_eq!(query.borrow(&world).iter().collect_vec(), []); + // assert_eq!( + // changes.drain().collect_vec(), + // [ + // Event { + // id, + // key: a().key(), + // kind: EventKind::Added + // }, + // Event { + // id, + // key: b().key(), + // kind: EventKind::Added + // } + // ] + // ); + + // assert_eq!(query.borrow(&world).iter().collect_vec(), []); world.clear(id).unwrap(); - assert_eq!( - changes.drain().collect_vec(), - [ - Event { - id, - key: a().key(), - kind: EventKind::Removed - }, - Event { - id, - key: b().key(), - kind: EventKind::Removed - } - ] - ); + // assert_eq!( + // changes.drain().collect_vec(), + // [ + // Event { + // id, + // key: a().key(), + // kind: EventKind::Removed + // }, + // Event { + // id, + // key: b().key(), + // kind: EventKind::Removed + // } + // ] + // ); assert_eq!(query.borrow(&world).iter().collect_vec(), [id]); } From 2434b321143e17f1604e810a425244a09f045725 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 5 Aug 2023 11:47:42 +0200 Subject: [PATCH 43/52] wip: batch fetching --- flax-derive/src/lib.rs | 32 +++++++++-- src/archetype/guard.rs | 1 + src/fetch/transform.rs | 122 ++++++++++++++++++++++++++++++++++++++++- src/filter/change.rs | 20 +++++-- src/filter/cmp.rs | 25 +++++---- src/filter/constant.rs | 33 ++++++++--- src/filter/mod.rs | 24 ++++---- src/filter/set.rs | 52 +++++++++++------- src/query/borrow.rs | 21 +++---- src/query/dfs.rs | 16 ++++-- src/query/iter.rs | 40 ++++++-------- src/query/planar.rs | 7 ++- src/query/walk.rs | 2 +- src/system/mod.rs | 3 +- 14 files changed, 289 insertions(+), 109 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 2f8dfe80..5f98b68b 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -6,8 +6,8 @@ use proc_macro_crate::FoundCrate; use quote::{format_ident, quote}; use syn::{ bracketed, parse::Parse, punctuated::Punctuated, spanned::Spanned, Attribute, DataStruct, - DeriveInput, Error, GenericParam, Generics, Ident, ImplGenerics, Lifetime, LifetimeParam, - Result, Token, Type, TypeGenerics, TypeParam, Visibility, + DeriveInput, Error, GenericParam, Generics, Ident, ImplGenerics, Index, Lifetime, + LifetimeParam, Result, Token, Type, TypeGenerics, TypeParam, Visibility, }; /// ```rust,ignore @@ -88,8 +88,10 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { vis, fetch_name, item_name, + batch_name, prepared_name, q_generics, + wq_generics, field_names, field_types, w_lf, @@ -121,6 +123,10 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { #(#field_names: <#field_types as #crate_name::fetch::FetchItem<#q_lf>>::Item,)* } + // #vis struct #batch_name #wq_generics { + // #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>::Prepared> as #crate_name::fetch::PreparedFetch<#q_lf>>::Batch,)* + // } + // #[automatically_derived] impl #item_impl #crate_name::fetch::FetchItem<#q_lf> for #fetch_name #fetch_ty { type Item = #item_name #item_ty; @@ -275,10 +281,12 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { vis, fetch_name, item_name, + batch_name, prepared_name, field_names, field_types, w_generics, + wq_generics, w_lf, q_lf, .. @@ -289,6 +297,9 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { let prep_impl = params.wq_impl(); let prep_ty = params.w_ty(); let item_ty = params.q_ty(); + let batch_ty = params.wq_ty(); + + let field_idx = (0..field_names.len()).map(Index::from).collect_vec(); quote! { #[doc = #msg] @@ -301,11 +312,12 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { where #(#field_types: 'static,)* { type Item = #item_name #item_ty; + type Batch = (#(<<#field_types as #crate_name::fetch::Fetch<#w_lf>>::Prepared as #crate_name::fetch::PreparedFetch<#q_lf>>::Batch,)*); #[inline] - unsafe fn fetch(&'q mut self, slot: #crate_name::archetype::Slot) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { Self::Item { - #(#field_names: #crate_name::fetch::PreparedFetch::fetch(&mut self.#field_names, slot),)* + #(#field_names: #crate_name::fetch::PreparedFetch::fetch_next(&mut batch.#field_idx),)* } } @@ -315,8 +327,10 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[inline] - fn set_visited(&mut self, slots: #crate_name::archetype::Slice) { - #(#crate_name::fetch::PreparedFetch::set_visited(&mut self.#field_names, slots);)* + unsafe fn create_batch(&mut self, slots: #crate_name::archetype::Slice) -> Self::Batch { + ( + #(#crate_name::fetch::PreparedFetch::create_batch(&mut self.#field_names, slots),)* + ) } } } @@ -388,6 +402,7 @@ struct Params<'a> { fetch_name: Ident, item_name: Ident, + batch_name: Ident, prepared_name: Ident, generics: &'a Generics, @@ -440,6 +455,7 @@ impl<'a> Params<'a> { field_types, attrs, item_name: format_ident!("{fetch_name}Item"), + batch_name: format_ident!("{fetch_name}Batch"), prepared_name: format_ident!("Prepared{fetch_name}"), fetch_name, w_generics: prepend_generics(&[GenericParam::Lifetime(w_lf.clone())], &input.generics), @@ -478,6 +494,10 @@ impl<'a> Params<'a> { self.q_generics.split_for_impl().1 } + fn wq_ty(&self) -> TypeGenerics { + self.wq_generics.split_for_impl().1 + } + fn w_ty(&self) -> TypeGenerics { self.w_generics.split_for_impl().1 } diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 655f109e..61131d69 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -103,6 +103,7 @@ impl<'a, T: ?Sized> CellGuard<'a, T> { &self.data.changes } + #[inline] pub(crate) fn get(&self) -> &T { unsafe { self.storage.as_ref() } } diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index 18c8a39a..4564279e 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -156,12 +156,24 @@ mod tests { } #[derive(Fetch)] - #[fetch(item_derives = [Debug], transforms = [Modified])] + // #[fetch(item_derives = [Debug], transforms = [Modified])] struct MyFetch { a: Component, b: Cloned>, } + // #[automatically_derived] + // impl<'w, 'q> crate::fetch::PreparedFetch<'q> for PreparedMyFetch<'w> + // where + // Component: 'static, + // Cloned>: 'static, + // { + // type Item = MyFetchItem<'q>; + // type Batch = ( + // < as Fetch<'w>>::Prepared as crate::fetch::PreparedFetch<'q>>::Batch, + // ); + // } + let mut world = World::new(); let id1 = Entity::builder() @@ -310,4 +322,112 @@ mod tests { [(id3, (-1, "There".to_string()))] ); } + + fn test_derive_parse() { + use crate::{fetch::Cloned, Component, Fetch}; + + // #[derive(Fetch)] + struct MyFetch { + a: Component, + b: Cloned>, + } + ///The item returned by MyFetch + struct MyFetchItem<'q> { + a: as crate::fetch::FetchItem<'q>>::Item, + b: > as crate::fetch::FetchItem<'q>>::Item, + } + impl<'q> crate::fetch::FetchItem<'q> for MyFetch { + type Item = MyFetchItem<'q>; + } + #[automatically_derived] + impl<'w> crate::Fetch<'w> for MyFetch + where + Component: 'static, + Cloned>: 'static, + { + const MUTABLE: bool = as crate::Fetch<'w>>::MUTABLE + || > as crate::Fetch<'w>>::MUTABLE; + type Prepared = PreparedMyFetch<'w>; + #[inline] + fn prepare( + &'w self, + data: crate::fetch::FetchPrepareData<'w>, + ) -> Option { + Some(Self::Prepared { + a: crate::Fetch::prepare(&self.a, data)?, + b: crate::Fetch::prepare(&self.b, data)?, + }) + } + #[inline] + fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { + crate::Fetch::filter_arch(&self.a, arch) && crate::Fetch::filter_arch(&self.b, arch) + } + fn describe(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + let mut s = f.debug_struct("MyFetch"); + s.field("a", &crate::fetch::FmtQuery(&self.a)); + s.field("b", &crate::fetch::FmtQuery(&self.b)); + s.finish() + } + fn access( + &self, + data: crate::fetch::FetchAccessData, + dst: &mut Vec, + ) { + crate::Fetch::access(&self.a, data, dst); + crate::Fetch::access(&self.b, data, dst) + } + fn searcher(&self, searcher: &mut crate::query::ArchetypeSearcher) { + crate::Fetch::searcher(&self.a, searcher); + crate::Fetch::searcher(&self.b, searcher); + } + } + ///The prepared fetch for MyFetch + struct PreparedMyFetch<'w> { + a: as crate::Fetch<'w>>::Prepared, + b: > as crate::Fetch<'w>>::Prepared, + } + #[automatically_derived] + impl<'w, 'q> crate::fetch::PreparedFetch<'q> for PreparedMyFetch<'w> + where + Component: 'static, + Cloned>: 'static, + { + type Item = MyFetchItem<'q>; + type Batch = ( + < as crate::fetch::Fetch< + 'w, + >>::Prepared as crate::fetch::PreparedFetch<'q>>::Batch, + <, + > as crate::fetch::Fetch< + 'w, + >>::Prepared as crate::fetch::PreparedFetch<'q>>::Batch, + ); + #[inline] + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + Self::Item { + a: < as crate::fetch::Fetch<'w>>::Prepared + as crate::fetch::PreparedFetch<'q> + > ::fetch_next(&mut batch.0), + b: todo!() + } + } + #[inline] + unsafe fn filter_slots( + &mut self, + slots: crate::archetype::Slice, + ) -> crate::archetype::Slice { + crate::fetch::PreparedFetch::filter_slots(&mut (&mut self.a, &mut self.b), slots) + } + #[inline] + unsafe fn create_batch(&mut self, slots: crate::archetype::Slice) -> Self::Batch { + ( + crate::fetch::PreparedFetch::create_batch(&mut self.a, slots), + crate::fetch::PreparedFetch::create_batch(&mut self.b, slots), + ) + } + } + } } diff --git a/src/filter/change.rs b/src/filter/change.rs index ce5d5580..4df0b326 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; use core::fmt::Formatter; +use core::slice; use itertools::Itertools; use crate::archetype::{Archetype, CellGuard, Change, Slot}; @@ -44,7 +45,7 @@ where impl<'q, 'w, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T> { unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { - unsafe { self.data.get_unchecked(slot) } + unsafe { self.data.get().get_unchecked(slot) } } } @@ -162,10 +163,11 @@ impl<'w, T> core::fmt::Debug for PreparedChangeFilter<'w, T> { impl<'q, 'w, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T> { type Item = &'q T; + type Batch = slice::Iter<'q, T>; #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - unsafe { self.data.get_unchecked(slot) } + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + batch.next().unwrap() } #[inline] @@ -181,6 +183,10 @@ impl<'q, 'w, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T cur.intersect(&slots) .unwrap_or(Slice::new(slots.end, slots.end)) } + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.data.get()[slots.as_range()].iter() + } } #[derive(Clone)] @@ -273,9 +279,7 @@ impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { type Item = (); - - #[inline] - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} + type Batch = (); #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -287,6 +291,10 @@ impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { cur.intersect(&slots) .unwrap_or(Slice::new(slots.end, slots.end)) } + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } #[cfg(test)] diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index 4213134e..dbd028fc 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -19,7 +19,7 @@ use crate::{ fetch::{ FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, ReadOnlyFetch, TransformFetch, }, - system::Access, + system::{Access, ParForEach}, Fetch, FetchItem, }; @@ -171,17 +171,12 @@ where } } -impl<'q, 'w, F, M> PreparedFetch<'q> for PreparedCmp<'w, F, M> +impl<'q, 'w, Q, M> PreparedFetch<'q> for PreparedCmp<'w, Q, M> where - F: for<'x> ReadOnlyFetch<'x>, - M: for<'x> CmpMethod<>::Item> + 'w, + Q: for<'x> ReadOnlyFetch<'x>, + M: for<'x> CmpMethod<>::Item> + 'w, { - type Item = >::Item; - - #[inline] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.fetch.fetch(slot) - } + type Item = >::Item; #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -207,9 +202,15 @@ where } } + type Batch = >::Batch; + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.fetch.create_batch(slots) + } + #[inline] - fn set_visited(&mut self, slots: Slice) { - self.fetch.set_visited(slots) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + Q::fetch_next(batch) } } diff --git a/src/filter/constant.rs b/src/filter/constant.rs index 689edb4d..79f27e3b 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -39,14 +39,16 @@ impl<'a> Fetch<'a> for Nothing { impl<'q> PreparedFetch<'q> for Nothing { type Item = (); - - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} + type Batch = (); unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.end, slots.end) } - fn set_visited(&mut self, _slots: Slice) {} + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + #[inline] + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } /// Yields all entities @@ -80,7 +82,12 @@ impl<'w> Fetch<'w> for All { impl<'q> PreparedFetch<'q> for All { type Item = (); - unsafe fn fetch(&'q mut self, _: usize) -> Self::Item {} + type Batch = (); + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + #[inline] + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } impl<'q> FetchItem<'q> for Slice { @@ -110,15 +117,17 @@ impl<'w> Fetch<'w> for Slice { impl<'q> PreparedFetch<'q> for Slice { type Item = (); - - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + type Batch = (); #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { self.intersect(&slots) .unwrap_or(Slice::new(slots.end, slots.end)) } + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } impl<'q> FetchItem<'q> for bool { @@ -151,8 +160,14 @@ impl<'w> Fetch<'w> for bool { impl<'q> PreparedFetch<'q> for bool { type Item = bool; - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item { + type Batch = bool; + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { *self } + + #[inline] + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + *batch + } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index e8cdfb65..4f680c10 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -140,20 +140,20 @@ where { type Item = Q::Item; - #[inline(always)] - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.fetch.fetch(slot) - } - #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { let l = self.fetch.filter_slots(slots); self.filter.filter_slots(l) } - #[inline] - fn set_visited(&mut self, slots: Slice) { - self.fetch.set_visited(slots) + type Batch = Q::Batch; + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.fetch.create_batch(slots) + } + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + Q::fetch_next(batch) } } @@ -533,13 +533,15 @@ pub struct BatchSize(pub(crate) Slot); impl<'q> PreparedFetch<'q> for BatchSize { type Item = (); - - #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + type Batch = (); unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.start, slots.end.min(slots.start + self.0)) } + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } impl<'q> FetchItem<'q> for BatchSize { diff --git a/src/filter/set.rs b/src/filter/set.rs index 6c3fe123..adfa43cc 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -1,5 +1,5 @@ use crate::{ - archetype::{Archetype, Slice, Slot}, + archetype::{Archetype, Slice}, fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, UnionFilter}, system::Access, Fetch, FetchItem, @@ -72,20 +72,21 @@ where type Item = (L::Item, R::Item); #[inline] - unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - (self.0.fetch(slot), self.1.fetch(slot)) + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + let l = self.0.filter_slots(slots); + + self.1.filter_slots(l) } - fn set_visited(&mut self, slots: Slice) { - self.0.set_visited(slots); - self.1.set_visited(slots); + type Batch = (L::Batch, R::Batch); + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + (self.0.create_batch(slots), self.1.create_batch(slots)) } #[inline] - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let l = self.0.filter_slots(slots); - - self.1.filter_slots(l) + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + (L::fetch_next(&mut batch.0), R::fetch_next(&mut batch.1)) } } @@ -134,7 +135,6 @@ where type Item = (); #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { if let Some(fetch) = &mut self.0 { @@ -145,6 +145,12 @@ where slots } } + + type Batch = (); + + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } impl ops::BitOr for Not { @@ -233,16 +239,21 @@ where { type Item = T::Item; - unsafe fn fetch(&'q mut self, slot: usize) -> Self::Item { - self.0.fetch(slot) - } - + #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { self.filter_union(slots) } - fn set_visited(&mut self, slots: Slice) { - self.0.set_visited(slots) + type Batch = T::Batch; + + #[inline] + unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + self.0.create_batch(slots) + } + + #[inline] + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + T::fetch_next(batch) } } @@ -288,6 +299,7 @@ macro_rules! tuple_impl { where $($ty: PreparedFetch<'q>,)* { type Item = (); + type Batch = (); unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { let inner = &mut self.0; @@ -302,11 +314,9 @@ macro_rules! tuple_impl { } #[inline] - unsafe fn fetch(&mut self, _: usize) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} - fn set_visited(&mut self, slots: Slice) { - $( self.0.$idx.set_visited(slots);)* - } + unsafe fn create_batch(&mut self, slots: Slice) -> Self::Batch {} } diff --git a/src/query/borrow.rs b/src/query/borrow.rs index 3c4ae819..ec6de055 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -1,7 +1,7 @@ use crate::{ archetype::{Archetype, Slice}, fetch::{FetchPrepareData, PreparedFetch}, - filter::{FilterIter, Filtered}, + filter::Filtered, ArchetypeId, Entity, Fetch, World, }; @@ -15,23 +15,23 @@ pub(crate) struct PreparedArchetype<'w, Q, F> { impl<'w, Q, F> PreparedArchetype<'w, Q, F> { #[inline] - pub fn manual_chunk<'q>(&'q mut self, slots: Slice) -> Option> + pub fn create_batch<'q>(&'q mut self, slots: Slice) -> Option> where Q: PreparedFetch<'q>, F: PreparedFetch<'q>, { - let chunk = unsafe { self.fetch.filter_slots(slots) }; - if chunk.is_empty() { + let slots = unsafe { self.fetch.filter_slots(slots) }; + if slots.is_empty() { return None; } // Fetch will never change and all calls are disjoint let fetch = unsafe { &mut *(&mut self.fetch as *mut Filtered) }; - // Set the chunk as visited - fetch.set_visited(chunk); - let chunk = Batch::new(self.arch, fetch, chunk); - Some(chunk) + let batch = unsafe { fetch.create_batch(slots) }; + + let batch = Batch::new(self.arch, batch, slots); + Some(batch) } #[inline] @@ -80,9 +80,10 @@ where } } -struct BatchesWithId<'q, Q, F> { +struct BatchesWithId<'q, Q: PreparedFetch<'q>, F> { chunks: ArchetypeChunks<'q, Q, F>, - current: Option>, + // The current batch + current: Option>, } impl<'q, Q, F> Iterator for BatchesWithId<'q, Q, F> diff --git a/src/query/dfs.rs b/src/query/dfs.rs index b6e35bfa..7a927af5 100644 --- a/src/query/dfs.rs +++ b/src/query/dfs.rs @@ -269,7 +269,7 @@ where // Uses a raw pointer to be able to recurse inside the loop // Alternative: release all borrows and borrow/prepare each fetch inside the loop prepared: *mut PreparedArchetype, - chunk: &mut Batch, + chunk: &mut Batch, edge: Option<&[T]>, value: &V, visit: &mut Visit, @@ -314,7 +314,7 @@ where 'w: 'q, { pub(crate) prepared: &'q mut [PreparedArchetype<'w, Q::Prepared, F::Prepared>], - pub(crate) stack: SmallVec<[Batch<'q, Q::Prepared, F::Prepared>; 8]>, + pub(crate) stack: SmallVec<[Batch<'q, Q::Prepared>; 8]>, pub(crate) adj: &'q AdjMap, } @@ -405,7 +405,10 @@ mod test { .tag(tree()) .spawn(&mut world) }) - .collect_vec() else { unreachable!() }; + .collect_vec() + else { + unreachable!() + }; world.set(b, child_of(a), ()).unwrap(); world.set(c, child_of(b), ()).unwrap(); @@ -434,10 +437,13 @@ mod test { .tag(tree()) .spawn(&mut world); - all.insert(id); + all.insert(id); id }) - .collect_vec() else { unreachable!() }; + .collect_vec() + else { + unreachable!() + }; world.set(i, other(), ()).unwrap(); diff --git a/src/query/iter.rs b/src/query/iter.rs index 4bb4bdec..64e7b8e0 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -9,14 +9,14 @@ use crate::{ /// Iterates over a chunk of entities, specified by a predicate. /// In essence, this is the unflattened version of [crate::QueryIter]. -pub struct Batch<'q, Q, F> { +pub struct Batch<'q, Q: PreparedFetch<'q>> { arch: &'q Archetype, - fetch: &'q mut Filtered, + fetch: Q::Batch, pos: Slot, end: Slot, } -impl<'q, Q, F> core::fmt::Debug for Batch<'q, Q, F> { +impl<'q, Q: PreparedFetch<'q>> core::fmt::Debug for Batch<'q, Q> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Batch") .field("pos", &self.pos) @@ -25,11 +25,11 @@ impl<'q, Q, F> core::fmt::Debug for Batch<'q, Q, F> { } } -impl<'q, Q, F> Batch<'q, Q, F> { - pub(crate) fn new(arch: &'q Archetype, fetch: &'q mut Filtered, slice: Slice) -> Self { +impl<'q, Q: PreparedFetch<'q>> Batch<'q, Q> { + pub(crate) fn new(arch: &'q Archetype, batch: Q::Batch, slice: Slice) -> Self { Self { arch, - fetch, + fetch: batch, pos: slice.start, end: slice.end, } @@ -57,10 +57,9 @@ impl<'q, Q, F> Batch<'q, Q, F> { } } -impl<'q, Q, F> Iterator for Batch<'q, Q, F> +impl<'q, Q> Iterator for Batch<'q, Q> where Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, { type Item = Q::Item; @@ -68,25 +67,23 @@ where if self.pos == self.end { None } else { - let fetch = unsafe { &mut *(self.fetch as *mut Filtered) }; - let item = unsafe { fetch.fetch(self.pos) }; + // let fetch = unsafe { &mut *(self.fetch as *mut Q::Batch) }; + let item = unsafe { Q::fetch_next(&mut self.fetch) }; self.pos += 1; Some(item) } } } -impl<'q, Q, F> Batch<'q, Q, F> +impl<'q, Q> Batch<'q, Q> where Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, { pub(crate) fn next_with_id(&mut self) -> Option<(Entity, Q::Item)> { if self.pos == self.end { None } else { - let fetch = unsafe { &mut *(self.fetch as *mut Filtered) }; - let item = unsafe { fetch.fetch(self.pos) }; + let item = unsafe { Q::fetch_next(&mut self.fetch) }; let id = self.arch.entities[self.pos]; self.pos += 1; Some((id, item)) @@ -97,9 +94,8 @@ where if self.pos == self.end { None } else { - let fetch = unsafe { &mut *(self.fetch as *mut Filtered) }; let slot = self.pos; - let item = unsafe { fetch.fetch(slot) }; + let item = unsafe { Q::fetch_next(&mut self.fetch) }; let id = self.arch.entities[slot]; self.pos += 1; @@ -157,7 +153,7 @@ where Q: 'q + PreparedFetch<'q>, F: 'q + PreparedFetch<'q>, { - type Item = Batch<'q, Q, F>; + type Item = Batch<'q, Q>; #[inline] fn next(&mut self) -> Option { @@ -165,12 +161,12 @@ where let fetch = unsafe { &mut *self.fetch }; // Get the next chunk - let chunk = Self::next_slice(&mut self.slots, fetch)?; + let slots = Self::next_slice(&mut self.slots, fetch)?; - // Set the chunk as visited - fetch.set_visited(chunk); - let chunk = Batch::new(self.arch, fetch, chunk); + // Disjoing chunk + let batch = unsafe { fetch.create_batch(slots) }; + let batch = Batch::new(self.arch, batch, slots); - Some(chunk) + Some(batch) } } diff --git a/src/query/planar.rs b/src/query/planar.rs index 4dcbb990..da8c95b7 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -1,5 +1,5 @@ use alloc::vec::Vec; -use core::{iter::Flatten, ptr::NonNull, slice::IterMut}; +use core::{iter::Flatten, slice::IterMut}; use smallvec::SmallVec; use crate::{ @@ -287,7 +287,7 @@ where // guarantees this borrow is unique let p = &mut self.prepared[idx]; let mut chunk = p - .manual_chunk(Slice::single(slot)) + .create_batch(Slice::single(slot)) .ok_or(Error::Filtered(id))?; let item = chunk.next().unwrap(); @@ -366,6 +366,7 @@ where pub(crate) current: Option>, } +/// Iterates over archetypes, yielding batches impl<'q, 'w, Q, F> BatchedIter<'w, 'q, Q, F> where Q: Fetch<'w>, @@ -388,7 +389,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = Batch<'q, Q::Prepared, F::Prepared>; + type Item = Batch<'q, Q::Prepared>; #[inline] fn next(&mut self) -> Option { diff --git a/src/query/walk.rs b/src/query/walk.rs index 5034b685..53021ddd 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -243,7 +243,7 @@ where let p = &mut borrow.prepared[index]; - p.manual_chunk(Slice::single(self.slot))?.next() + p.create_batch(Slice::single(self.slot))?.next() } /// Traverse the immediate children of the current node. diff --git a/src/system/mod.rs b/src/system/mod.rs index a296963f..ae05b167 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -114,8 +114,7 @@ where for<'x> Q: Fetch<'x> + 'static + Send, for<'x> F: Fetch<'x> + 'static + Send, for<'x, 'y> crate::query::BatchedIter<'x, 'y, Q, F>: Send, - for<'x, 'y> crate::query::Batch<'x, >::Prepared, >::Prepared>: - Send, + for<'x, 'y> crate::query::Batch<'x, >::Prepared>: Send, { /// Execute a function for each item in the query in parallel batches pub fn par_for_each(self, func: Func) -> System, (Query,), (), T> From 07b7e9a88b2d87b7c79e9a18fe4bd525c705ac9f Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sat, 5 Aug 2023 23:36:27 +0200 Subject: [PATCH 44/52] wip: batch fetching --- flax-derive/src/lib.rs | 4 +- src/archetype/guard.rs | 2 +- src/component.rs | 9 ++-- src/fetch/maybe_mut.rs | 2 +- src/fetch/source.rs | 4 +- src/fetch/transform.rs | 114 +---------------------------------------- src/filter/mod.rs | 3 +- src/query/borrow.rs | 4 +- src/query/dfs.rs | 6 +-- src/query/entity.rs | 13 +++-- src/query/planar.rs | 1 + src/query/walk.rs | 5 +- src/relation.rs | 8 +-- src/system/mod.rs | 5 +- 14 files changed, 35 insertions(+), 145 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 5f98b68b..667bb3d6 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -317,7 +317,7 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { #[inline] unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { Self::Item { - #(#field_names: #crate_name::fetch::PreparedFetch::fetch_next(&mut batch.#field_idx),)* + #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::fetch_next(&mut batch.#field_idx),)* } } @@ -327,7 +327,7 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[inline] - unsafe fn create_batch(&mut self, slots: #crate_name::archetype::Slice) -> Self::Batch { + unsafe fn create_batch(&'q mut self, slots: #crate_name::archetype::Slice) -> Self::Batch { ( #(#crate_name::fetch::PreparedFetch::create_batch(&mut self.#field_names, slots),)* ) diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 61131d69..4c614ef7 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -166,7 +166,7 @@ impl<'a, T> DerefMut for RefMut<'a, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.modified = true; - &mut self.guard.get_mut() + self.guard.get_mut() } } diff --git a/src/component.rs b/src/component.rs index 2a8050ea..7b72bf96 100644 --- a/src/component.rs +++ b/src/component.rs @@ -166,12 +166,9 @@ impl PartialEq for Component { impl Copy for Component {} impl Clone for Component { + #[inline] fn clone(&self) -> Self { - Self { - key: self.key, - vtable: self.vtable, - marker: PhantomData, - } + *self } } @@ -385,7 +382,7 @@ impl From> for ComponentDesc { impl PartialOrd for ComponentDesc { fn partial_cmp(&self, other: &Self) -> Option { - self.key.partial_cmp(&other.key) + Some(self.cmp(other)) } } diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index 4e90c4cf..3c297010 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -87,7 +87,7 @@ pub struct PreparedMaybeMut<'w, T> { _marker: PhantomData, } -struct Batch<'a> { +pub struct Batch<'a> { cell: &'a Cell, new_tick: u32, ids: &'a [Entity], diff --git a/src/fetch/source.rs b/src/fetch/source.rs index 58caf54e..f1f4ce29 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -148,7 +148,7 @@ where impl<'q, Q> ReadOnlyFetch<'q> for PreparedSource where - Q: ReadOnlyFetch<'q>, + Q: 'q + ReadOnlyFetch<'q>, { unsafe fn fetch_shared(&'q self, _: crate::archetype::Slot) -> Self::Item { self.fetch.fetch_shared(self.slot) @@ -173,7 +173,7 @@ where } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { - *batch + todo!() } } diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index 4564279e..d93e1df4 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -156,24 +156,12 @@ mod tests { } #[derive(Fetch)] - // #[fetch(item_derives = [Debug], transforms = [Modified])] + #[fetch(item_derives = [Debug], transforms = [Modified])] struct MyFetch { a: Component, b: Cloned>, } - // #[automatically_derived] - // impl<'w, 'q> crate::fetch::PreparedFetch<'q> for PreparedMyFetch<'w> - // where - // Component: 'static, - // Cloned>: 'static, - // { - // type Item = MyFetchItem<'q>; - // type Batch = ( - // < as Fetch<'w>>::Prepared as crate::fetch::PreparedFetch<'q>>::Batch, - // ); - // } - let mut world = World::new(); let id1 = Entity::builder() @@ -326,108 +314,10 @@ mod tests { fn test_derive_parse() { use crate::{fetch::Cloned, Component, Fetch}; - // #[derive(Fetch)] + #[derive(Fetch)] struct MyFetch { a: Component, b: Cloned>, } - ///The item returned by MyFetch - struct MyFetchItem<'q> { - a: as crate::fetch::FetchItem<'q>>::Item, - b: > as crate::fetch::FetchItem<'q>>::Item, - } - impl<'q> crate::fetch::FetchItem<'q> for MyFetch { - type Item = MyFetchItem<'q>; - } - #[automatically_derived] - impl<'w> crate::Fetch<'w> for MyFetch - where - Component: 'static, - Cloned>: 'static, - { - const MUTABLE: bool = as crate::Fetch<'w>>::MUTABLE - || > as crate::Fetch<'w>>::MUTABLE; - type Prepared = PreparedMyFetch<'w>; - #[inline] - fn prepare( - &'w self, - data: crate::fetch::FetchPrepareData<'w>, - ) -> Option { - Some(Self::Prepared { - a: crate::Fetch::prepare(&self.a, data)?, - b: crate::Fetch::prepare(&self.b, data)?, - }) - } - #[inline] - fn filter_arch(&self, arch: &crate::archetype::Archetype) -> bool { - crate::Fetch::filter_arch(&self.a, arch) && crate::Fetch::filter_arch(&self.b, arch) - } - fn describe(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - let mut s = f.debug_struct("MyFetch"); - s.field("a", &crate::fetch::FmtQuery(&self.a)); - s.field("b", &crate::fetch::FmtQuery(&self.b)); - s.finish() - } - fn access( - &self, - data: crate::fetch::FetchAccessData, - dst: &mut Vec, - ) { - crate::Fetch::access(&self.a, data, dst); - crate::Fetch::access(&self.b, data, dst) - } - fn searcher(&self, searcher: &mut crate::query::ArchetypeSearcher) { - crate::Fetch::searcher(&self.a, searcher); - crate::Fetch::searcher(&self.b, searcher); - } - } - ///The prepared fetch for MyFetch - struct PreparedMyFetch<'w> { - a: as crate::Fetch<'w>>::Prepared, - b: > as crate::Fetch<'w>>::Prepared, - } - #[automatically_derived] - impl<'w, 'q> crate::fetch::PreparedFetch<'q> for PreparedMyFetch<'w> - where - Component: 'static, - Cloned>: 'static, - { - type Item = MyFetchItem<'q>; - type Batch = ( - < as crate::fetch::Fetch< - 'w, - >>::Prepared as crate::fetch::PreparedFetch<'q>>::Batch, - <, - > as crate::fetch::Fetch< - 'w, - >>::Prepared as crate::fetch::PreparedFetch<'q>>::Batch, - ); - #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { - Self::Item { - a: < as crate::fetch::Fetch<'w>>::Prepared - as crate::fetch::PreparedFetch<'q> - > ::fetch_next(&mut batch.0), - b: todo!() - } - } - #[inline] - unsafe fn filter_slots( - &mut self, - slots: crate::archetype::Slice, - ) -> crate::archetype::Slice { - crate::fetch::PreparedFetch::filter_slots(&mut (&mut self.a, &mut self.b), slots) - } - #[inline] - unsafe fn create_batch(&mut self, slots: crate::archetype::Slice) -> Self::Batch { - ( - crate::fetch::PreparedFetch::create_batch(&mut self.a, slots), - crate::fetch::PreparedFetch::create_batch(&mut self.b, slots), - ) - } - } } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 4f680c10..72cc2e11 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -438,9 +438,10 @@ impl<'a> Fetch<'a> for WithoutRelation { pub struct RefFetch<'a, F>(pub(crate) &'a F); impl<'a, F> Copy for RefFetch<'a, F> {} + impl<'a, F> Clone for RefFetch<'a, F> { fn clone(&self) -> Self { - Self(self.0) + *self } } diff --git a/src/query/borrow.rs b/src/query/borrow.rs index ec6de055..31909d85 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -88,8 +88,8 @@ struct BatchesWithId<'q, Q: PreparedFetch<'q>, F> { impl<'q, Q, F> Iterator for BatchesWithId<'q, Q, F> where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, + Q: 'q + PreparedFetch<'q>, + F: 'q + PreparedFetch<'q>, { type Item = (Entity, Q::Item); diff --git a/src/query/dfs.rs b/src/query/dfs.rs index 7a927af5..7f46899b 100644 --- a/src/query/dfs.rs +++ b/src/query/dfs.rs @@ -225,7 +225,7 @@ where // Fetch will never change and all calls are disjoint let p = unsafe { &mut *prepared.add(arch_index) }; - if let Some(mut chunk) = p.manual_chunk(Slice::single(loc.slot)) { + if let Some(mut chunk) = p.create_batch(Slice::single(loc.slot)) { Self::traverse_batch( self.query_state.world, dfs, @@ -296,7 +296,7 @@ where dfs, prepared, &mut chunk, - edge.as_deref(), + edge.as_ref().map(|v| v.get()), &value, visit, ) @@ -341,7 +341,7 @@ where let arch = &mut self.prepared[arch_index]; // Fetch will never change and all calls are disjoint let p = unsafe { &mut *(arch as *mut PreparedArchetype<_, _>) }; - if let Some(chunk) = p.manual_chunk(slice) { + if let Some(chunk) = p.create_batch(slice) { self.stack.push(chunk) } } diff --git a/src/query/entity.rs b/src/query/entity.rs index c5330977..07f75b59 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -32,9 +32,12 @@ fn state<'w, 'a, Q: Fetch<'w>, F: Fetch<'w>>( let Some(mut p) = state.prepare_fetch(loc.arch_id, arch) else { return match find_missing_components(state.fetch, loc.arch_id, state.world).next() { - Some(missing) => Err(Error::MissingComponent(MissingComponent{id,desc: missing})), + Some(missing) => Err(Error::MissingComponent(MissingComponent { + id, + desc: missing, + })), None => Err(Error::DoesNotMatch(id)), - } + }; }; // Safety @@ -111,8 +114,10 @@ where match &mut self.prepared { Ok((loc, p)) => { // self is a mutable reference, so this is the only reference to the slot - p.fetch.set_visited(Slice::single(loc.slot)); - unsafe { Ok(p.fetch.fetch(loc.slot)) } + unsafe { + let mut batch = p.fetch.create_batch(Slice::single(loc.slot)); + Ok(::fetch_next(&mut batch)) + } } Err(e) => Err(e.clone()), } diff --git a/src/query/planar.rs b/src/query/planar.rs index da8c95b7..b9e99204 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -222,6 +222,7 @@ where where Q: Sync, Q::Prepared: Send, + for<'x> >::Batch: Send, F: Sync, F::Prepared: Send, { diff --git a/src/query/walk.rs b/src/query/walk.rs index 53021ddd..b6c1d363 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -203,6 +203,7 @@ pub struct Node<'w, Q, F> { } impl<'w, Q, F> Clone for Node<'w, Q, F> { + #[inline] fn clone(&self) -> Self { Self { id: self.id, @@ -215,8 +216,6 @@ impl<'w, Q, F> Clone for Node<'w, Q, F> { } } -impl<'w, Q, F> Copy for Node<'w, Q, F> {} - impl<'w, Q, F> Debug for Node<'w, Q, F> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Node").field("id", &self.id).finish() @@ -267,7 +266,7 @@ where /// Traverse the current subtree including the current node in depth-first order. pub fn dfs(&self) -> DfsIter<'w, Q, F> { - let stack = smallvec::smallvec![*self]; + let stack = smallvec::smallvec![self.clone()]; DfsIter { stack, diff --git a/src/relation.rs b/src/relation.rs index 7a2ef669..41236364 100644 --- a/src/relation.rs +++ b/src/relation.rs @@ -86,11 +86,7 @@ impl Copy for Relation {} impl Clone for Relation { fn clone(&self) -> Self { - Self { - id: self.id, - vtable: self.vtable, - marker: PhantomData, - } + *self } } @@ -245,7 +241,7 @@ where let (&key, cell) = self.cells.next()?; Some(( key.object().unwrap(), - cell.get_mut::(self.entities, self.slot, self.change_tick) + cell.get_mut::(self.entities[self.slot], self.slot, self.change_tick) .unwrap(), )) } diff --git a/src/system/mod.rs b/src/system/mod.rs index ae05b167..cc62005a 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -2,8 +2,8 @@ mod context; mod traits; use crate::{ - archetype::ArchetypeInfo, query::QueryData, util::TupleCombine, ArchetypeId, CommandBuffer, - ComponentKey, Fetch, FetchItem, Query, World, + archetype::ArchetypeInfo, fetch::PreparedFetch, query::QueryData, util::TupleCombine, + ArchetypeId, CommandBuffer, ComponentKey, Fetch, FetchItem, Query, World, }; use alloc::{ boxed::Box, @@ -79,6 +79,7 @@ where for<'x> F: Fetch<'x>, for<'x> >::Prepared: Send, for<'x> >::Prepared: Send, + for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Batch: Send, for<'x> Func: Fn(>::Item) + Send + Sync, { fn execute(&mut self, mut data: (QueryData,)) { From 26862ab6e869ee6ea52716018e4e409b249ddb8a Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 00:18:52 +0200 Subject: [PATCH 45/52] wip: batch fetching --- src/archetype/mod.rs | 1 + src/fetch/cloned.rs | 4 ++++ src/fetch/component_mut.rs | 18 +++++------------- src/fetch/copied.rs | 4 ++++ src/fetch/source.rs | 2 +- src/system/mod.rs | 8 ++++---- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 822fb8e0..9fbdf6fe 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -97,6 +97,7 @@ impl CellData { /// Sets the specified entities and slots as modified and invokes subscribers /// **Note**: `ids` must be the slice of entities pointed to by `slice` pub(crate) fn set_modified(&mut self, ids: &[Entity], slice: Slice, change_tick: u32) { + debug_assert_eq!(ids.len(), slice.len()); let component = self.key; self.on_event(EventData { ids, diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index 646f31a0..c688d714 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -80,6 +80,10 @@ where unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { F::fetch_next(batch).clone() } + + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + self.0.filter_slots(slots) + } } impl<'q, V, F> ReadOnlyFetch<'q> for Cloned diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 1973faa8..e8c03caf 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -89,20 +89,12 @@ impl<'q, 'w, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> type Item = &'q mut T; type Batch = slice::IterMut<'q, T>; - // #[inline(always)] - // unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - // // Perform a reborrow - // // Cast from a immutable to a mutable borrow as all calls to this - // // function are guaranteed to be disjoint - // unsafe { &mut *(self.guard.get_unchecked_mut(slot) as *mut T) } - // } - - // fn set_visited(&mut self, slots: Slice) { - // self.guard - // .set_modified(&self.arch.entities, slots, self.tick); - // } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + eprintln!( + "Modified {:?} {}", + &self.arch.entities[slots.as_range()], + self.tick, + ); self.guard .set_modified(&self.arch.entities[slots.as_range()], slots, self.tick); diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index 2881818e..d09b32f5 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -81,6 +81,10 @@ where unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { *F::fetch_next(batch) } + + unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { + self.0.filter_slots(slots) + } } impl<'p, F, V> ReadOnlyFetch<'p> for Copied diff --git a/src/fetch/source.rs b/src/fetch/source.rs index f1f4ce29..a573ce27 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -165,7 +165,7 @@ where self.fetch.filter_slots(slots) } - type Batch = Q::Item; + type Batch = Q::Batch; unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { let mut batch = self.fetch.create_batch(Slice::single(self.slot)); diff --git a/src/system/mod.rs b/src/system/mod.rs index cc62005a..ee25c846 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -112,10 +112,10 @@ where #[cfg(feature = "parallel")] impl SystemBuilder<(Query,), T> where - for<'x> Q: Fetch<'x> + 'static + Send, - for<'x> F: Fetch<'x> + 'static + Send, - for<'x, 'y> crate::query::BatchedIter<'x, 'y, Q, F>: Send, - for<'x, 'y> crate::query::Batch<'x, >::Prepared>: Send, + for<'x> Q: 'static + Fetch<'x> + Send, + for<'x> F: 'static + Fetch<'x> + Send, + for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Batch: Send, + // for<'x, 'y> crate::query::Batch<'y, >::Prepared>: Send, { /// Execute a function for each item in the query in parallel batches pub fn par_for_each(self, func: Func) -> System, (Query,), (), T> From 8b7b5e64aa9cdeb040a0b911415c50b083e6c3b0 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 14:20:45 +0200 Subject: [PATCH 46/52] chore: cleanup --- flax-derive/src/lib.rs | 21 +++++----------- flax-derive/src/test.rs | 2 +- src/archetype/guard.rs | 7 ++---- src/fetch/as_deref.rs | 4 +-- src/fetch/cloned.rs | 4 +-- src/fetch/component.rs | 8 +++--- src/fetch/component_mut.rs | 6 ++--- src/fetch/copied.rs | 10 ++++---- src/fetch/entity_ref.rs | 6 ++--- src/fetch/map.rs | 2 +- src/fetch/maybe_mut.rs | 4 +-- src/fetch/mod.rs | 28 ++++++++++----------- src/fetch/opt.rs | 16 ++++++------ src/fetch/peek.rs | 4 +-- src/fetch/read_only.rs | 6 ++--- src/fetch/relations.rs | 4 +-- src/fetch/satisfied.rs | 7 ++---- src/fetch/source.rs | 42 +++++++++++++++++--------------- src/filter/change.rs | 10 ++++---- src/filter/cmp.rs | 12 ++++----- src/filter/constant.rs | 10 ++++---- src/filter/mod.rs | 50 +++++++++++++++++++++----------------- src/filter/set.rs | 29 +++++++++++----------- src/query/borrow.rs | 11 ++++----- src/query/dfs.rs | 10 ++++---- src/query/entity.rs | 2 +- src/query/iter.rs | 26 +++++++++----------- src/query/mod.rs | 2 +- src/query/planar.rs | 8 +++--- src/query/topo.rs | 10 ++++++-- src/query/walk.rs | 2 +- src/system/mod.rs | 9 +++---- 32 files changed, 182 insertions(+), 190 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 667bb3d6..6b8bd2f7 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -88,7 +88,6 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { vis, fetch_name, item_name, - batch_name, prepared_name, q_generics, wq_generics, @@ -187,7 +186,6 @@ fn derive_union(params: &Params) -> TokenStream { crate_name, field_names, prepared_name, - q_lf, .. } = params; @@ -197,7 +195,7 @@ fn derive_union(params: &Params) -> TokenStream { quote! { #[automatically_derived] - impl #impl_generics #crate_name::fetch::UnionFilter<#q_lf> for #prepared_name #prep_ty where #prepared_name #prep_ty: #crate_name::fetch::PreparedFetch<'q> { + impl #impl_generics #crate_name::fetch::UnionFilter for #prepared_name #prep_ty where #prepared_name #prep_ty: #crate_name::fetch::PreparedFetch<'q> { unsafe fn filter_union(&mut self, slots: #crate_name::archetype::Slice) -> #crate_name::archetype::Slice { #crate_name::fetch::PreparedFetch::filter_slots(&mut #crate_name::filter::Union((#(&mut self.#field_names,)*)), slots) } @@ -281,14 +279,10 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { vis, fetch_name, item_name, - batch_name, prepared_name, field_names, field_types, w_generics, - wq_generics, - w_lf, - q_lf, .. } = params; @@ -297,22 +291,21 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { let prep_impl = params.wq_impl(); let prep_ty = params.w_ty(); let item_ty = params.q_ty(); - let batch_ty = params.wq_ty(); let field_idx = (0..field_names.len()).map(Index::from).collect_vec(); quote! { #[doc = #msg] #vis struct #prepared_name #w_generics { - #(#field_names: <#field_types as #crate_name::Fetch <#w_lf>>::Prepared,)* + #(#field_names: <#field_types as #crate_name::Fetch <'w>>::Prepared,)* } #[automatically_derived] - impl #prep_impl #crate_name::fetch::PreparedFetch<#q_lf> for #prepared_name #prep_ty + impl #prep_impl #crate_name::fetch::PreparedFetch<'q> for #prepared_name #prep_ty where #(#field_types: 'static,)* { type Item = #item_name #item_ty; - type Batch = (#(<<#field_types as #crate_name::fetch::Fetch<#w_lf>>::Prepared as #crate_name::fetch::PreparedFetch<#q_lf>>::Batch,)*); + type Batch = (#(<<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::Batch,)*); #[inline] unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { @@ -327,9 +320,9 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[inline] - unsafe fn create_batch(&'q mut self, slots: #crate_name::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: #crate_name::archetype::Slice) -> Self::Batch { ( - #(#crate_name::fetch::PreparedFetch::create_batch(&mut self.#field_names, slots),)* + #(#crate_name::fetch::PreparedFetch::create_chunk(&mut self.#field_names, slots),)* ) } } @@ -402,7 +395,6 @@ struct Params<'a> { fetch_name: Ident, item_name: Ident, - batch_name: Ident, prepared_name: Ident, generics: &'a Generics, @@ -455,7 +447,6 @@ impl<'a> Params<'a> { field_types, attrs, item_name: format_ident!("{fetch_name}Item"), - batch_name: format_ident!("{fetch_name}Batch"), prepared_name: format_ident!("Prepared{fetch_name}"), fetch_name, w_generics: prepend_generics(&[GenericParam::Lifetime(w_lf.clone())], &input.generics), diff --git a/flax-derive/src/test.rs b/flax-derive/src/test.rs index a2fed05a..904c1f03 100644 --- a/flax-derive/src/test.rs +++ b/flax-derive/src/test.rs @@ -21,7 +21,7 @@ fn derive_fetch_struct() { } #[automatically_derived] - impl<'q> flax_renamed::fetch::FetchItem<'q> for Foo { + impl<'w, 'q> flax_renamed::fetch::FetchItem<'q> for Foo { type Item = FooItem<'q>; } diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index 4c614ef7..e70c5a18 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -6,12 +6,9 @@ use core::{ use atomic_refcell::{AtomicRef, AtomicRefMut}; -use crate::{ - events::{EventData, EventKind}, - ComponentValue, Entity, -}; +use crate::{ComponentValue, Entity}; -use super::{CellData, Change, Changes, Slice, Slot}; +use super::{CellData, Changes, Slice, Slot}; /// Type safe abstraction over a borrowed cell data pub(crate) struct CellMutGuard<'a, T: ?Sized> { diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index eb19cf7f..09f1e3b9 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -63,8 +63,8 @@ where self.0.filter_slots(slots) } - unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { - self.0.create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + self.0.create_chunk(slots) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index c688d714..ca41fae3 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -73,8 +73,8 @@ where type Item = V; type Batch = F::Batch; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - self.0.create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + self.0.create_chunk(slots) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { diff --git a/src/fetch/component.rs b/src/fetch/component.rs index b6ce91ef..5c3ec024 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -11,7 +11,7 @@ pub struct ReadComponent<'a, T> { borrow: AtomicRef<'a, [T]>, } -impl<'q, 'w, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { +impl<'w, 'q, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { type Item = &'q T; // #[inline(always)] @@ -22,7 +22,7 @@ impl<'q, 'w, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { type Batch = slice::Iter<'q, T>; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { self.borrow[slots.as_range()].iter() } @@ -31,8 +31,8 @@ impl<'q, 'w, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { } } -impl<'w, 'p, T: ComponentValue> ReadOnlyFetch<'p> for ReadComponent<'w, T> { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { +impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for ReadComponent<'w, T> { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.borrow.get_unchecked(slot) } } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index e8c03caf..05574a83 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -6,7 +6,7 @@ use core::{ }; use crate::{ - archetype::{Archetype, CellMutGuard, Slice, Slot}, + archetype::{Archetype, CellMutGuard, Slice}, system::{Access, AccessKind}, Component, ComponentValue, Fetch, FetchItem, }; @@ -85,11 +85,11 @@ pub struct WriteComponent<'a, T> { tick: u32, } -impl<'q, 'w, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> { +impl<'w, 'q, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> { type Item = &'q mut T; type Batch = slice::IterMut<'q, T>; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { eprintln!( "Modified {:?} {}", &self.arch.entities[slots.as_range()], diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index d09b32f5..b87e9105 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -74,8 +74,8 @@ where type Item = V; type Batch = F::Batch; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - self.0.create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + self.0.create_chunk(slots) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { @@ -87,13 +87,13 @@ where } } -impl<'p, F, V> ReadOnlyFetch<'p> for Copied +impl<'q, F, V> ReadOnlyFetch<'q> for Copied where - F: ReadOnlyFetch<'p>, + F: ReadOnlyFetch<'q>, F::Item: Deref, V: 'static + Copy, { - unsafe fn fetch_shared(&'p self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { *self.0.fetch_shared(slot) } } diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index 5136697f..b4f5b0bc 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -1,11 +1,9 @@ -use core::{iter::Enumerate, slice}; - use alloc::vec::Vec; use crate::{ archetype::{Archetype, Slot}, system::{Access, AccessKind}, - Entity, EntityRef, Fetch, FetchItem, World, + EntityRef, Fetch, FetchItem, World, }; use super::{FetchAccessData, PreparedFetch}; @@ -71,7 +69,7 @@ impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { type Item = EntityRef<'q>; type Batch = Batch<'q>; - unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { Batch { world: self.world, arch: self.arch, diff --git a/src/fetch/map.rs b/src/fetch/map.rs index 908c66e2..88c0d71b 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -65,7 +65,7 @@ where type Batch = (&'q F, Q::Batch); - unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { todo!() } diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index 3c297010..b294915b 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use atomic_refcell::AtomicRef; -use core::{marker::PhantomData, ops::Range}; +use core::marker::PhantomData; use crate::{ archetype::{Cell, RefMut, Slot}, @@ -98,7 +98,7 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { type Item = MutGuard<'q, T>; type Batch = Batch<'q>; - unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { Batch { cell: self.cell, new_tick: self.new_tick, diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index d4e7db85..204d3bb5 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -133,7 +133,7 @@ pub trait PreparedFetch<'q> { type Item: 'q; type Batch: 'q; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch; + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch; /// Fetch the item from entity at the slot in the prepared storage. /// # Safety @@ -155,7 +155,7 @@ pub trait PreparedFetch<'q> { } /// Allows filtering the constituent parts of a fetch using a set union -pub trait UnionFilter<'q> { +pub trait UnionFilter { // Filter the slots using a union operation of the constituent part /// /// # Safety @@ -170,8 +170,8 @@ where type Item = F::Item; type Batch = F::Batch; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - (*self).create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + (*self).create_chunk(slots) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { @@ -187,7 +187,7 @@ impl<'q> FetchItem<'q> for () { type Item = (); } -impl<'q> UnionFilter<'q> for () { +impl UnionFilter for () { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { slots } @@ -214,8 +214,8 @@ impl<'w> Fetch<'w> for () { fn access(&self, _: FetchAccessData, _: &mut Vec) {} } -impl<'p> ReadOnlyFetch<'p> for () { - unsafe fn fetch_shared(&'p self, _: Slot) -> Self::Item {} +impl<'q> ReadOnlyFetch<'q> for () { + unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} } impl<'q> PreparedFetch<'q> for () { @@ -223,7 +223,7 @@ impl<'q> PreparedFetch<'q> for () { type Batch = (); - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } @@ -235,9 +235,9 @@ where type Item = Option; type Batch = Option; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { if let Some(fetch) = self { - Some(fetch.create_batch(slots)) + Some(fetch.create_chunk(slots)) } else { None } @@ -301,7 +301,7 @@ impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { type Batch = slice::Iter<'q, Entity>; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { self.entities[slots.as_range()].iter() } @@ -355,8 +355,8 @@ macro_rules! tuple_impl { } #[inline] - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - ($((self.$idx).create_batch(slots),)*) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + ($((self.$idx).create_chunk(slots),)*) } #[inline] @@ -370,7 +370,7 @@ macro_rules! tuple_impl { } } - impl<'q, $($ty, )*> UnionFilter<'q> for ($($ty,)*) + impl<'q, $($ty, )*> UnionFilter for ($($ty,)*) where $($ty: PreparedFetch<'q>,)* { diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 28b11ed9..0bcdae37 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -50,11 +50,11 @@ where #[doc(hidden)] pub struct PreparedOpt(pub(crate) Option); -impl<'p, F> ReadOnlyFetch<'p> for PreparedOpt +impl<'q, F> ReadOnlyFetch<'q> for PreparedOpt where - F: ReadOnlyFetch<'p>, + F: ReadOnlyFetch<'q>, { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.0.as_ref().map(|fetch| fetch.fetch_shared(slot)) } } @@ -75,8 +75,8 @@ where } } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - self.0.as_mut().map(|v| v.create_batch(slots)) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + self.0.as_mut().map(|v| v.create_chunk(slots)) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { @@ -135,7 +135,7 @@ impl<'q, F: FetchItem<'q, Item = &'q V>, V: 'static> FetchItem<'q> for OptOr PreparedFetch<'q> for OptOr, &'w V> +impl<'w, 'q, F, V> PreparedFetch<'q> for OptOr, &'w V> where F: PreparedFetch<'q, Item = &'q V>, V: 'q, @@ -152,9 +152,9 @@ where } } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { match self.fetch { - Some(ref mut v) => Either::Left(v.create_batch(slots)), + Some(ref mut v) => Either::Left(v.create_chunk(slots)), None => Either::Right(self.value), } } diff --git a/src/fetch/peek.rs b/src/fetch/peek.rs index d214a664..fb1ff7d5 100644 --- a/src/fetch/peek.rs +++ b/src/fetch/peek.rs @@ -9,7 +9,7 @@ pub trait PeekableFetch<'p> { /// # Safety /// A peek of the same slot should not alias with a reference returned by /// [`PreparedFetch::fetch`]. - unsafe fn peek(&'p self, slot: Slot) -> Self::Peek; + unsafe fn peek(&'q self, slot: Slot) -> Self::Peek; } impl<'p, F> PeekableFetch<'p> for Option @@ -18,7 +18,7 @@ where { type Peek = Option; - unsafe fn peek(&'p self, slot: Slot) -> Self::Peek { + unsafe fn peek(&'q self, slot: Slot) -> Self::Peek { self.as_ref().map(|fetch| fetch.peek(slot)) } } diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index b8d70cec..d9927a95 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -13,11 +13,11 @@ pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; } -impl<'p, F> ReadOnlyFetch<'p> for Option +impl<'q, F> ReadOnlyFetch<'q> for Option where - F: ReadOnlyFetch<'p>, + F: ReadOnlyFetch<'q>, { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.as_ref().map(|fetch| fetch.fetch_shared(slot)) } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index ca81c69d..9b4697e3 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -80,7 +80,7 @@ pub struct Batch<'a, T> { slot: Slot, } -impl<'q, 'w, T> PreparedFetch<'q> for PreparedRelations<'w, T> +impl<'w, 'q, T> PreparedFetch<'q> for PreparedRelations<'w, T> where T: ComponentValue, { @@ -88,7 +88,7 @@ where type Batch = Batch<'q, T>; - unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { Batch { borrows: &self.borrows, slot: slots.start, diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 26c19b03..1b7c12c0 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -1,9 +1,6 @@ use alloc::vec::Vec; -use crate::{ - archetype::{Slice, Slot}, - Fetch, FetchItem, -}; +use crate::{archetype::Slice, Fetch, FetchItem}; use super::{FmtQuery, PreparedFetch}; @@ -45,7 +42,7 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { type Item = bool; type Batch = bool; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { let res = self.0.filter_slots(slots); if res.is_empty() { false diff --git a/src/fetch/source.rs b/src/fetch/source.rs index a573ce27..27d0ca7e 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -1,9 +1,9 @@ -use core::fmt::Debug; +use core::{fmt::Debug, marker::PhantomData}; use alloc::vec::Vec; use crate::{ - archetype::{Archetype, Slice, Slot}, + archetype::{Archetype, Slot}, entity::EntityLocation, system::Access, ComponentValue, Entity, Fetch, FetchItem, RelationExt, World, @@ -79,10 +79,9 @@ impl Source { } } -impl<'q, Q, S> FetchItem<'q> for Source +impl<'w, 'q, Q, S> FetchItem<'q> for Source where Q: FetchItem<'q>, - S: FetchSource, { type Item = Q::Item; } @@ -95,7 +94,7 @@ where { const MUTABLE: bool = Q::MUTABLE; - type Prepared = PreparedSource; + type Prepared = PreparedSource<'w, Q::Prepared>; fn prepare(&'w self, data: super::FetchPrepareData<'w>) -> Option { let loc = self.source.resolve(data.arch, data.world)?; @@ -114,6 +113,7 @@ where Some(PreparedSource { slot: loc.slot, fetch, + _marker: PhantomData, }) } @@ -146,18 +146,18 @@ where } } -impl<'q, Q> ReadOnlyFetch<'q> for PreparedSource -where - Q: 'q + ReadOnlyFetch<'q>, -{ - unsafe fn fetch_shared(&'q self, _: crate::archetype::Slot) -> Self::Item { - self.fetch.fetch_shared(self.slot) - } -} +// impl<'w, 'q, Q> ReadOnlyFetch<'q> for PreparedSource +// where +// Q: ReadOnlyFetch<'q>, +// { +// unsafe fn fetch_shared(&'q self, _: crate::archetype::Slot) -> Self::Item { +// self.fetch.fetch_shared(self.slot) +// } +// } -impl<'q, Q> PreparedFetch<'q> for PreparedSource +impl<'w, 'q, Q> PreparedFetch<'q> for PreparedSource<'w, Q> where - Q: ReadOnlyFetch<'q>, + Q: 'w + ReadOnlyFetch<'q>, { type Item = Q::Item; @@ -165,21 +165,23 @@ where self.fetch.filter_slots(slots) } - type Batch = Q::Batch; + type Batch = Q::Item; - unsafe fn create_batch(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { - let mut batch = self.fetch.create_batch(Slice::single(self.slot)); - Q::fetch_next(&mut batch) + unsafe fn create_chunk(&'q mut self, _: crate::archetype::Slice) -> Self::Batch { + todo!() + // self.fetch.fetch_shared(self.slot) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { todo!() + // *batch } } -pub struct PreparedSource { +pub struct PreparedSource<'w, Q> { slot: Slot, fetch: Q, + _marker: PhantomData<&'w mut ()>, } #[cfg(test)] diff --git a/src/filter/change.rs b/src/filter/change.rs index 4df0b326..41876c38 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -43,7 +43,7 @@ where type Item = &'q T; } -impl<'q, 'w, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T> { +impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T> { unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { unsafe { self.data.get().get_unchecked(slot) } } @@ -161,7 +161,7 @@ impl<'w, T> core::fmt::Debug for PreparedChangeFilter<'w, T> { } } -impl<'q, 'w, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T> { +impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T> { type Item = &'q T; type Batch = slice::Iter<'q, T>; @@ -184,7 +184,7 @@ impl<'q, 'w, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { self.data.get()[slots.as_range()].iter() } } @@ -277,7 +277,7 @@ impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} } -impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { +impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { type Item = (); type Batch = (); @@ -292,7 +292,7 @@ impl<'q, 'w> PreparedFetch<'q> for PreparedRemoveFilter<'w> { .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index dbd028fc..7756b4c1 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -19,7 +19,7 @@ use crate::{ fetch::{ FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, ReadOnlyFetch, TransformFetch, }, - system::{Access, ParForEach}, + system::Access, Fetch, FetchItem, }; @@ -161,17 +161,17 @@ pub struct PreparedCmp<'w, F, M> { method: &'w M, } -impl<'p, 'w, F, M> ReadOnlyFetch<'p> for PreparedCmp<'w, F, M> +impl<'w, 'q, F, M> ReadOnlyFetch<'q> for PreparedCmp<'w, F, M> where F: for<'x> ReadOnlyFetch<'x>, M: for<'x> CmpMethod<>::Item> + 'w, { - unsafe fn fetch_shared(&'p self, slot: Slot) -> Self::Item { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.fetch.fetch_shared(slot) } } -impl<'q, 'w, Q, M> PreparedFetch<'q> for PreparedCmp<'w, Q, M> +impl<'w, 'q, Q, M> PreparedFetch<'q> for PreparedCmp<'w, Q, M> where Q: for<'x> ReadOnlyFetch<'x>, M: for<'x> CmpMethod<>::Item> + 'w, @@ -204,8 +204,8 @@ where type Batch = >::Batch; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - self.fetch.create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + self.fetch.create_chunk(slots) } #[inline] diff --git a/src/filter/constant.rs b/src/filter/constant.rs index 79f27e3b..505a479c 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -45,7 +45,7 @@ impl<'q> PreparedFetch<'q> for Nothing { Slice::new(slots.end, slots.end) } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} #[inline] unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} @@ -84,7 +84,7 @@ impl<'q> PreparedFetch<'q> for All { type Batch = (); - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} #[inline] unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} @@ -125,12 +125,12 @@ impl<'q> PreparedFetch<'q> for Slice { .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } -impl<'q> FetchItem<'q> for bool { +impl<'w, 'q> FetchItem<'q> for bool { type Item = bool; } @@ -162,7 +162,7 @@ impl<'q> PreparedFetch<'q> for bool { type Batch = bool; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { *self } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 72cc2e11..f193cfc3 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -148,8 +148,8 @@ where type Batch = Q::Batch; - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - self.fetch.create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + self.fetch.create_chunk(slots) } unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { @@ -197,31 +197,37 @@ where type Item = Slice; fn next(&mut self) -> Option { - if self.slots.is_empty() { - return None; - } + next_slice(&mut self.slots, &mut self.fetch) + } +} + +pub(crate) fn next_slice<'a, Q: PreparedFetch<'a>>( + slots: &mut Slice, + fetch: &mut Q, +) -> Option { + if slots.is_empty() { + return None; + } - while !self.slots.is_empty() { - // Safety - // The yielded slots are split off of `self.slots` - let cur = unsafe { self.fetch.filter_slots(self.slots) }; + while !slots.is_empty() { + // Safety + // The yielded slots are split off of `self.slots` + let cur = unsafe { fetch.filter_slots(*slots) }; - let (_l, m, r) = self - .slots - .split_with(&cur) - .expect("Return value of filter must be a subset of `slots"); + let (_l, m, r) = slots + .split_with(&cur) + .expect("Return value of filter must be a subset of `slots"); - assert_eq!(cur, m); + assert_eq!(cur, m); - self.slots = r; + *slots = r; - if !m.is_empty() { - return Some(m); - } + if !m.is_empty() { + return Some(m); } - - None } + + None } impl<'q, F: PreparedFetch<'q>> FusedIterator for FilterIter {} @@ -269,7 +275,7 @@ pub struct Without { pub(crate) name: &'static str, } -impl<'q> FetchItem<'q> for Without { +impl<'w, 'q> FetchItem<'q> for Without { type Item = (); } @@ -540,7 +546,7 @@ impl<'q> PreparedFetch<'q> for BatchSize { Slice::new(slots.start, slots.end.min(slots.start + self.0)) } - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } diff --git a/src/filter/set.rs b/src/filter/set.rs index adfa43cc..324f169c 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -80,8 +80,8 @@ where type Batch = (L::Batch, R::Batch); - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - (self.0.create_batch(slots), self.1.create_batch(slots)) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + (self.0.create_chunk(slots), self.1.create_chunk(slots)) } #[inline] @@ -148,7 +148,7 @@ where type Batch = (); - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} } @@ -201,7 +201,7 @@ where impl<'w, T> Fetch<'w> for Union where T: Fetch<'w>, - T::Prepared: for<'q> UnionFilter<'q>, + T::Prepared: UnionFilter, { const MUTABLE: bool = T::MUTABLE; @@ -224,9 +224,9 @@ where } } -impl<'q, T> UnionFilter<'q> for Union +impl UnionFilter for Union where - T: UnionFilter<'q>, + T: UnionFilter, { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { self.0.filter_union(slots) @@ -235,7 +235,7 @@ where impl<'q, T> PreparedFetch<'q> for Union where - T: PreparedFetch<'q> + UnionFilter<'q>, + T: PreparedFetch<'q> + UnionFilter, { type Item = T::Item; @@ -247,8 +247,8 @@ where type Batch = T::Batch; #[inline] - unsafe fn create_batch(&'q mut self, slots: Slice) -> Self::Batch { - self.0.create_batch(slots) + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + self.0.create_chunk(slots) } #[inline] @@ -260,7 +260,7 @@ where macro_rules! tuple_impl { ($($idx: tt => $ty: ident),*) => { // Or - impl<'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { + impl<'w, 'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> { type Item = (); } @@ -295,8 +295,8 @@ macro_rules! tuple_impl { } - impl<'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)> - where $($ty: PreparedFetch<'q>,)* + impl<'w, 'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)> + where 'w: 'q, $($ty: PreparedFetch<'q>,)* { type Item = (); type Batch = (); @@ -316,12 +316,11 @@ macro_rules! tuple_impl { #[inline] unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} - unsafe fn create_batch(&mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&mut self, slots: Slice) -> Self::Batch {} } - - impl<'q, $($ty, )*> UnionFilter<'q> for Or<($(Option<$ty>,)*)> + impl<'q, $($ty, )*> UnionFilter for Or<($(Option<$ty>,)*)> where $($ty: PreparedFetch<'q>,)* { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { diff --git a/src/query/borrow.rs b/src/query/borrow.rs index 31909d85..f5921b53 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -5,7 +5,7 @@ use crate::{ ArchetypeId, Entity, Fetch, World, }; -use super::{ArchetypeChunks, Batch}; +use super::{ArchetypeChunks, Chunk}; pub(crate) struct PreparedArchetype<'w, Q, F> { pub(crate) arch_id: ArchetypeId, @@ -15,7 +15,7 @@ pub(crate) struct PreparedArchetype<'w, Q, F> { impl<'w, Q, F> PreparedArchetype<'w, Q, F> { #[inline] - pub fn create_batch<'q>(&'q mut self, slots: Slice) -> Option> + pub fn create_chunk<'q>(&'q mut self, slots: Slice) -> Option> where Q: PreparedFetch<'q>, F: PreparedFetch<'q>, @@ -28,9 +28,9 @@ impl<'w, Q, F> PreparedArchetype<'w, Q, F> { // Fetch will never change and all calls are disjoint let fetch = unsafe { &mut *(&mut self.fetch as *mut Filtered) }; - let batch = unsafe { fetch.create_batch(slots) }; + let batch = unsafe { fetch.create_chunk(slots) }; - let batch = Batch::new(self.arch, batch, slots); + let batch = Chunk::new(self.arch, batch, slots); Some(batch) } @@ -40,7 +40,6 @@ impl<'w, Q, F> PreparedArchetype<'w, Q, F> { fetch: &mut self.fetch as *mut _, slots: self.arch.slots(), arch: self.arch, - _marker: core::marker::PhantomData, } } } @@ -83,7 +82,7 @@ where struct BatchesWithId<'q, Q: PreparedFetch<'q>, F> { chunks: ArchetypeChunks<'q, Q, F>, // The current batch - current: Option>, + current: Option>, } impl<'q, Q, F> Iterator for BatchesWithId<'q, Q, F> diff --git a/src/query/dfs.rs b/src/query/dfs.rs index 7f46899b..c4e24cf5 100644 --- a/src/query/dfs.rs +++ b/src/query/dfs.rs @@ -12,7 +12,7 @@ use smallvec::SmallVec; use crate::{Entity, Fetch, RelationExt, World}; -use super::{borrow::QueryBorrowState, Batch, PreparedArchetype, QueryStrategy}; +use super::{borrow::QueryBorrowState, Chunk, PreparedArchetype, QueryStrategy}; type AdjMap = BTreeMap>; @@ -225,7 +225,7 @@ where // Fetch will never change and all calls are disjoint let p = unsafe { &mut *prepared.add(arch_index) }; - if let Some(mut chunk) = p.create_batch(Slice::single(loc.slot)) { + if let Some(mut chunk) = p.create_chunk(Slice::single(loc.slot)) { Self::traverse_batch( self.query_state.world, dfs, @@ -269,7 +269,7 @@ where // Uses a raw pointer to be able to recurse inside the loop // Alternative: release all borrows and borrow/prepare each fetch inside the loop prepared: *mut PreparedArchetype, - chunk: &mut Batch, + chunk: &mut Chunk, edge: Option<&[T]>, value: &V, visit: &mut Visit, @@ -314,7 +314,7 @@ where 'w: 'q, { pub(crate) prepared: &'q mut [PreparedArchetype<'w, Q::Prepared, F::Prepared>], - pub(crate) stack: SmallVec<[Batch<'q, Q::Prepared>; 8]>, + pub(crate) stack: SmallVec<[Chunk<'q, Q::Prepared>; 8]>, pub(crate) adj: &'q AdjMap, } @@ -341,7 +341,7 @@ where let arch = &mut self.prepared[arch_index]; // Fetch will never change and all calls are disjoint let p = unsafe { &mut *(arch as *mut PreparedArchetype<_, _>) }; - if let Some(chunk) = p.create_batch(slice) { + if let Some(chunk) = p.create_chunk(slice) { self.stack.push(chunk) } } diff --git a/src/query/entity.rs b/src/query/entity.rs index 07f75b59..2f818112 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -115,7 +115,7 @@ where Ok((loc, p)) => { // self is a mutable reference, so this is the only reference to the slot unsafe { - let mut batch = p.fetch.create_batch(Slice::single(loc.slot)); + let mut batch = p.fetch.create_chunk(Slice::single(loc.slot)); Ok(::fetch_next(&mut batch)) } } diff --git a/src/query/iter.rs b/src/query/iter.rs index 64e7b8e0..101d1a02 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -1,22 +1,20 @@ -use core::ptr::NonNull; - use crate::{ archetype::{Archetype, Slice, Slot}, fetch::PreparedFetch, - filter::{FilterIter, Filtered}, - Entity, Fetch, + filter::{next_slice, Filtered}, + Entity, }; /// Iterates over a chunk of entities, specified by a predicate. /// In essence, this is the unflattened version of [crate::QueryIter]. -pub struct Batch<'q, Q: PreparedFetch<'q>> { +pub struct Chunk<'q, Q: PreparedFetch<'q>> { arch: &'q Archetype, fetch: Q::Batch, pos: Slot, end: Slot, } -impl<'q, Q: PreparedFetch<'q>> core::fmt::Debug for Batch<'q, Q> { +impl<'q, Q: PreparedFetch<'q>> core::fmt::Debug for Chunk<'q, Q> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Batch") .field("pos", &self.pos) @@ -25,7 +23,7 @@ impl<'q, Q: PreparedFetch<'q>> core::fmt::Debug for Batch<'q, Q> { } } -impl<'q, Q: PreparedFetch<'q>> Batch<'q, Q> { +impl<'q, Q: PreparedFetch<'q>> Chunk<'q, Q> { pub(crate) fn new(arch: &'q Archetype, batch: Q::Batch, slice: Slice) -> Self { Self { arch, @@ -57,7 +55,7 @@ impl<'q, Q: PreparedFetch<'q>> Batch<'q, Q> { } } -impl<'q, Q> Iterator for Batch<'q, Q> +impl<'q, Q> Iterator for Chunk<'q, Q> where Q: PreparedFetch<'q>, { @@ -75,7 +73,7 @@ where } } -impl<'q, Q> Batch<'q, Q> +impl<'q, Q> Chunk<'q, Q> where Q: PreparedFetch<'q>, { @@ -111,7 +109,6 @@ pub struct ArchetypeChunks<'q, Q, F> { pub(crate) arch: &'q Archetype, pub(crate) fetch: *mut Filtered, pub(crate) slots: Slice, - pub(crate) _marker: core::marker::PhantomData<&'q mut ()>, } unsafe impl<'q, Q: 'q, F: 'q> Sync for ArchetypeChunks<'q, Q, F> where &'q mut Filtered: Sync {} @@ -148,12 +145,13 @@ where None } } + impl<'q, Q, F> Iterator for ArchetypeChunks<'q, Q, F> where Q: 'q + PreparedFetch<'q>, F: 'q + PreparedFetch<'q>, { - type Item = Batch<'q, Q>; + type Item = Chunk<'q, Q>; #[inline] fn next(&mut self) -> Option { @@ -161,11 +159,11 @@ where let fetch = unsafe { &mut *self.fetch }; // Get the next chunk - let slots = Self::next_slice(&mut self.slots, fetch)?; + let slots = next_slice(&mut self.slots, fetch)?; // Disjoing chunk - let batch = unsafe { fetch.create_batch(slots) }; - let batch = Batch::new(self.arch, batch, slots); + let batch = unsafe { fetch.create_chunk(slots) }; + let batch = Chunk::new(self.arch, batch, slots); Some(batch) } diff --git a/src/query/mod.rs b/src/query/mod.rs index b6d1eaf7..08c1d1f5 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -285,7 +285,7 @@ where (old_tick, new_tick) } - /// Borrow the world for the query. + /// Borrow data in the world for the query. /// /// The returned value holds the borrows of the query fetch. As such, all /// references from iteration or using [QueryBorrow::get`] will have a diff --git a/src/query/planar.rs b/src/query/planar.rs index b9e99204..dfd1cd76 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -14,7 +14,7 @@ use crate::{ use super::{ borrow::QueryBorrowState, difference::find_missing_components, ArchetypeChunks, - ArchetypeSearcher, Batch, PreparedArchetype, QueryStrategy, + ArchetypeSearcher, Chunk, PreparedArchetype, QueryStrategy, }; /// The default linear iteration strategy @@ -288,7 +288,7 @@ where // guarantees this borrow is unique let p = &mut self.prepared[idx]; let mut chunk = p - .create_batch(Slice::single(slot)) + .create_chunk(Slice::single(slot)) .ok_or(Error::Filtered(id))?; let item = chunk.next().unwrap(); @@ -368,7 +368,7 @@ where } /// Iterates over archetypes, yielding batches -impl<'q, 'w, Q, F> BatchedIter<'w, 'q, Q, F> +impl<'w, 'q, Q, F> BatchedIter<'w, 'q, Q, F> where Q: Fetch<'w>, F: Fetch<'w>, @@ -390,7 +390,7 @@ where F: Fetch<'w>, 'w: 'q, { - type Item = Batch<'q, Q::Prepared>; + type Item = Chunk<'q, Q::Prepared>; #[inline] fn next(&mut self) -> Option { diff --git a/src/query/topo.rs b/src/query/topo.rs index 0d3c0b6b..7dfbb8a3 100644 --- a/src/query/topo.rs +++ b/src/query/topo.rs @@ -270,7 +270,10 @@ mod test { .set(name(), i.to_string()) .spawn(&mut world) }) - .collect_vec() else {unreachable!()}; + .collect_vec() + else { + unreachable!() + }; // Intentionally scrambled order as alphabetical order causes the input to already be // sorted. @@ -342,7 +345,10 @@ mod test { .tag(tree()) .spawn(&mut world) }) - .collect_vec() else {unreachable!()}; + .collect_vec() + else { + unreachable!() + }; // d ----* a // | | diff --git a/src/query/walk.rs b/src/query/walk.rs index b6c1d363..78b2ffd4 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -242,7 +242,7 @@ where let p = &mut borrow.prepared[index]; - p.create_batch(Slice::single(self.slot))?.next() + p.create_chunk(Slice::single(self.slot))?.next() } /// Traverse the immediate children of the current node. diff --git a/src/system/mod.rs b/src/system/mod.rs index ee25c846..b0b75192 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -2,8 +2,8 @@ mod context; mod traits; use crate::{ - archetype::ArchetypeInfo, fetch::PreparedFetch, query::QueryData, util::TupleCombine, - ArchetypeId, CommandBuffer, ComponentKey, Fetch, FetchItem, Query, World, + archetype::ArchetypeInfo, fetch::PreparedFetch, filter::Filtered, query::QueryData, + util::TupleCombine, ArchetypeId, CommandBuffer, ComponentKey, Fetch, FetchItem, Query, World, }; use alloc::{ boxed::Box, @@ -77,8 +77,7 @@ impl<'a, Func, Q, F> SystemFn<'a, (QueryData<'a, Q, F>,), ()> for ParForEach Q: Fetch<'x>, for<'x> F: Fetch<'x>, - for<'x> >::Prepared: Send, - for<'x> >::Prepared: Send, + for<'x> as Fetch<'x>>::Prepared: Send, for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Batch: Send, for<'x> Func: Fn(>::Item) + Send + Sync, { @@ -114,7 +113,7 @@ impl SystemBuilder<(Query,), T> where for<'x> Q: 'static + Fetch<'x> + Send, for<'x> F: 'static + Fetch<'x> + Send, - for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Batch: Send, + for<'x> <>::Prepared as PreparedFetch<'x>>::Batch: Send, // for<'x, 'y> crate::query::Batch<'y, >::Prepared>: Send, { /// Execute a function for each item in the query in parallel batches From 4521906ecbda1e48508b68df1f4a833f323943f6 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 18:36:18 +0200 Subject: [PATCH 47/52] fix: source --- flax-derive/src/lib.rs | 8 +++---- src/fetch/as_deref.rs | 10 +++++--- src/fetch/cloned.rs | 14 ++++++++---- src/fetch/component.rs | 20 ++++++++-------- src/fetch/component_mut.rs | 7 +++--- src/fetch/copied.rs | 10 +++++--- src/fetch/entity_ref.rs | 6 ++--- src/fetch/map.rs | 6 ++--- src/fetch/maybe_mut.rs | 16 ++++++++++--- src/fetch/mod.rs | 47 +++++++++++++++++++++++--------------- src/fetch/opt.rs | 16 ++++++++----- src/fetch/read_only.rs | 7 ++++++ src/fetch/relations.rs | 6 ++--- src/fetch/satisfied.rs | 6 ++--- src/fetch/source.rs | 16 ++++++------- src/filter/change.rs | 21 ++++++++++++----- src/filter/cmp.rs | 10 +++++--- src/filter/constant.rs | 24 +++++++++---------- src/filter/mod.rs | 16 +++++++------ src/filter/set.rs | 25 ++++++++++---------- src/query/iter.rs | 4 ++-- src/query/planar.rs | 2 +- src/system/mod.rs | 4 ++-- 23 files changed, 181 insertions(+), 120 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 6b8bd2f7..a41e661e 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -123,7 +123,7 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { } // #vis struct #batch_name #wq_generics { - // #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>::Prepared> as #crate_name::fetch::PreparedFetch<#q_lf>>::Batch,)* + // #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>::Prepared> as #crate_name::fetch::PreparedFetch<#q_lf>>::Chunk,)* // } // #[automatically_derived] @@ -305,10 +305,10 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { where #(#field_types: 'static,)* { type Item = #item_name #item_ty; - type Batch = (#(<<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::Batch,)*); + type Chunk = (#(<<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::Chunk,)*); #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { Self::Item { #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::fetch_next(&mut batch.#field_idx),)* } @@ -320,7 +320,7 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { } #[inline] - unsafe fn create_chunk(&'q mut self, slots: #crate_name::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: #crate_name::archetype::Slice) -> Self::Chunk { ( #(#crate_name::fetch::PreparedFetch::create_chunk(&mut self.#field_names, slots),)* ) diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index 09f1e3b9..b3e0214b 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -57,17 +57,17 @@ where { type Item = &'q V::Target; - type Batch = F::Batch; + type Chunk = F::Chunk; unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { self.0.filter_slots(slots) } - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { self.0.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { F::fetch_next(batch) } } @@ -80,4 +80,8 @@ where unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { self.0.fetch_shared(slot) } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: crate::archetype::Slot) -> Self::Item { + F::fetch_shared_chunk(batch, slot) + } } diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index ca41fae3..c5058bc4 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -6,7 +6,7 @@ use core::{ use alloc::vec::Vec; use crate::{ - archetype::{Archetype, Slice}, + archetype::{Archetype, Slice, Slot}, system::Access, Fetch, FetchItem, }; @@ -71,13 +71,13 @@ where V: 'static + Clone, { type Item = V; - type Batch = F::Batch; + type Chunk = F::Chunk; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.0.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { F::fetch_next(batch).clone() } @@ -92,9 +92,13 @@ where F::Item: Deref, V: 'static + Clone, { - unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { + unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.0.fetch_shared(slot).clone() } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_shared_chunk(batch, slot).clone() + } } impl TransformFetch for Cloned diff --git a/src/fetch/component.rs b/src/fetch/component.rs index 5c3ec024..5821d301 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -14,27 +14,29 @@ pub struct ReadComponent<'a, T> { impl<'w, 'q, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { type Item = &'q T; - // #[inline(always)] - // unsafe fn fetch(&'q mut self, slot: Slot) -> Self::Item { - // // Safety: bounds guaranteed by callee - // unsafe { self.borrow.get_unchecked(slot) } - // } + type Chunk = slice::Iter<'q, T>; - type Batch = slice::Iter<'q, T>; - - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + #[inline] + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.borrow[slots.as_range()].iter() } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + #[inline] + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { batch.next().unwrap() } } impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for ReadComponent<'w, T> { + #[inline] unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.borrow.get_unchecked(slot) } + + #[inline] + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + &batch.as_slice()[slot] + } } impl<'w, T> Fetch<'w> for Component diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 05574a83..4bcd9da0 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -87,9 +87,9 @@ pub struct WriteComponent<'a, T> { impl<'w, 'q, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> { type Item = &'q mut T; - type Batch = slice::IterMut<'q, T>; + type Chunk = slice::IterMut<'q, T>; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { eprintln!( "Modified {:?} {}", &self.arch.entities[slots.as_range()], @@ -105,7 +105,8 @@ impl<'w, 'q, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> slice.iter_mut() } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + #[inline] + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { // TODO: raw stepping slice access batch.next().unwrap() } diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index b87e9105..5b3c41af 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -72,13 +72,13 @@ where V: 'static + Copy, { type Item = V; - type Batch = F::Batch; + type Chunk = F::Chunk; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.0.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { *F::fetch_next(batch) } @@ -96,6 +96,10 @@ where unsafe fn fetch_shared(&'q self, slot: crate::archetype::Slot) -> Self::Item { *self.0.fetch_shared(slot) } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: crate::archetype::Slot) -> Self::Item { + *F::fetch_shared_chunk(batch, slot) + } } impl TransformFetch for Copied diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index b4f5b0bc..1458f4e4 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -67,9 +67,9 @@ pub struct Batch<'a> { impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { type Item = EntityRef<'q>; - type Batch = Batch<'q>; + type Chunk = Batch<'q>; - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { Batch { world: self.world, arch: self.arch, @@ -78,7 +78,7 @@ impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { } #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { let slot = batch.slot; EntityRef { diff --git a/src/fetch/map.rs b/src/fetch/map.rs index 88c0d71b..55259886 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -63,13 +63,13 @@ where { type Item = T; - type Batch = (&'q F, Q::Batch); + type Chunk = (&'q F, Q::Chunk); - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { todo!() } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { (batch.0)(Q::fetch_next(&mut batch.1)) } diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index b294915b..b8a8bdbb 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -96,9 +96,9 @@ pub struct Batch<'a> { impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { type Item = MutGuard<'q, T>; - type Batch = Batch<'q>; + type Chunk = Batch<'q>; - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { Batch { cell: self.cell, new_tick: self.new_tick, @@ -107,7 +107,7 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { } } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { let slot = batch.slot; batch.slot += 1; MutGuard { @@ -131,6 +131,16 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { _marker: PhantomData, } } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + MutGuard { + slot, + cell: batch.cell, + new_tick: batch.new_tick, + id: batch.ids[slot], + _marker: PhantomData, + } + } } /// Protects against accidental mutation. diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 204d3bb5..a872b3ad 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -131,9 +131,9 @@ pub trait Fetch<'w>: for<'q> FetchItem<'q> { pub trait PreparedFetch<'q> { /// Item returned by fetch type Item: 'q; - type Batch: 'q; + type Chunk: 'q; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch; + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk; /// Fetch the item from entity at the slot in the prepared storage. /// # Safety @@ -141,7 +141,7 @@ pub trait PreparedFetch<'q> { /// prepared archetype. /// /// The callee is responsible for assuring disjoint calls. - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item; + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item; #[inline] /// Filter the slots to visit @@ -168,13 +168,13 @@ where F: PreparedFetch<'q>, { type Item = F::Item; - type Batch = F::Batch; + type Chunk = F::Chunk; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { (*self).create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { F::fetch_next(batch) } @@ -216,16 +216,17 @@ impl<'w> Fetch<'w> for () { impl<'q> ReadOnlyFetch<'q> for () { unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item {} } impl<'q> PreparedFetch<'q> for () { type Item = (); - type Batch = (); + type Chunk = (); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} } impl<'q, F> PreparedFetch<'q> for Option @@ -233,9 +234,9 @@ where F: PreparedFetch<'q>, { type Item = Option; - type Batch = Option; + type Chunk = Option; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { if let Some(fetch) = self { Some(fetch.create_chunk(slots)) } else { @@ -252,7 +253,7 @@ where } } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { if let Some(fetch) = batch { Some(F::fetch_next(fetch)) } else { @@ -299,13 +300,13 @@ impl<'w> Fetch<'w> for EntityIds { impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { type Item = Entity; - type Batch = slice::Iter<'q, Entity>; + type Chunk = slice::Iter<'q, Entity>; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.entities[slots.as_range()].iter() } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { *batch.next().unwrap() } } @@ -315,6 +316,9 @@ impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { unsafe fn fetch_shared(&self, slot: usize) -> Self::Item { self.entities[slot] } + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + batch.as_slice()[slot] + } } // Implement for tuples @@ -337,6 +341,13 @@ macro_rules! tuple_impl { (self.$idx).fetch_shared(slot), )*) } + + #[inline(always)] + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + ($( + $ty::fetch_shared_chunk(&chunk.$idx, slot), + )*) + } } @@ -345,17 +356,17 @@ macro_rules! tuple_impl { { type Item = ($($ty::Item,)*); - type Batch = ($($ty::Batch,)*); + type Chunk = ($($ty::Chunk,)*); #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { ($( $ty::fetch_next(&mut batch.$idx), )*) } #[inline] - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { ($((self.$idx).create_chunk(slots),)*) } diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 0bcdae37..6bb09c65 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -57,6 +57,10 @@ where unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.0.as_ref().map(|fetch| fetch.fetch_shared(slot)) } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + batch.as_ref().map(|v| F::fetch_shared_chunk(v, slot)) + } } impl<'q, F> PreparedFetch<'q> for PreparedOpt @@ -64,7 +68,7 @@ where F: PreparedFetch<'q>, { type Item = Option; - type Batch = Option; + type Chunk = Option; #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -75,11 +79,11 @@ where } } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.0.as_mut().map(|v| v.create_chunk(slots)) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { batch.as_mut().map(|v| F::fetch_next(v)) } } @@ -141,7 +145,7 @@ where V: 'q, { type Item = &'q V; - type Batch = Either; + type Chunk = Either; #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -152,14 +156,14 @@ where } } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { match self.fetch { Some(ref mut v) => Either::Left(v.create_chunk(slots)), None => Either::Right(self.value), } } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { match batch { Either::Left(v) => F::fetch_next(v), Either::Right(v) => v, diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index d9927a95..60740078 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -11,6 +11,7 @@ pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { /// # Safety /// Slot must be valid unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item; } impl<'q, F> ReadOnlyFetch<'q> for Option @@ -20,4 +21,10 @@ where unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.as_ref().map(|fetch| fetch.fetch_shared(slot)) } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + batch + .as_ref() + .map(|v| >::fetch_shared_chunk(v, slot)) + } } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 9b4697e3..29122953 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -86,16 +86,16 @@ where { type Item = RelationsIter<'q, T>; - type Batch = Batch<'q, T>; + type Chunk = Batch<'q, T>; - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { Batch { borrows: &self.borrows, slot: slots.start, } } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { let slot = batch.slot; batch.slot += 1; diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 1b7c12c0..40de00dd 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -40,9 +40,9 @@ pub struct PreparedSatisfied(Option); impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { type Item = bool; - type Batch = bool; + type Chunk = bool; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { let res = self.0.filter_slots(slots); if res.is_empty() { false @@ -51,7 +51,7 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { } } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { *batch } diff --git a/src/fetch/source.rs b/src/fetch/source.rs index 27d0ca7e..32fb020a 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -3,7 +3,7 @@ use core::{fmt::Debug, marker::PhantomData}; use alloc::vec::Vec; use crate::{ - archetype::{Archetype, Slot}, + archetype::{Archetype, Slice, Slot}, entity::EntityLocation, system::Access, ComponentValue, Entity, Fetch, FetchItem, RelationExt, World, @@ -79,7 +79,7 @@ impl Source { } } -impl<'w, 'q, Q, S> FetchItem<'q> for Source +impl<'q, Q, S> FetchItem<'q> for Source where Q: FetchItem<'q>, { @@ -165,16 +165,14 @@ where self.fetch.filter_slots(slots) } - type Batch = Q::Item; + type Chunk = Q::Chunk; - unsafe fn create_chunk(&'q mut self, _: crate::archetype::Slice) -> Self::Batch { - todo!() - // self.fetch.fetch_shared(self.slot) + unsafe fn create_chunk(&'q mut self, _: crate::archetype::Slice) -> Self::Chunk { + self.fetch.create_chunk(Slice::single(self.slot)) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { - todo!() - // *batch + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { + Q::fetch_shared_chunk(batch, 0) } } diff --git a/src/filter/change.rs b/src/filter/change.rs index 41876c38..6519e6b3 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -47,6 +47,11 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { unsafe { self.data.get().get_unchecked(slot) } } + + #[inline] + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + batch.as_slice().get_unchecked(slot) + } } impl<'w, T> Fetch<'w> for ChangeFilter @@ -163,10 +168,10 @@ impl<'w, T> core::fmt::Debug for PreparedChangeFilter<'w, T> { impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T> { type Item = &'q T; - type Batch = slice::Iter<'q, T>; + type Chunk = slice::Iter<'q, T>; #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { batch.next().unwrap() } @@ -184,7 +189,7 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.data.get()[slots.as_range()].iter() } } @@ -274,12 +279,16 @@ impl<'w> core::fmt::Debug for PreparedRemoveFilter<'w> { } impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { + #[inline] unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} + + #[inline] + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item {} } impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { type Item = (); - type Batch = (); + type Chunk = (); #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -292,9 +301,9 @@ impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} } #[cfg(test)] diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index 7756b4c1..9b77befb 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -169,6 +169,10 @@ where unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { self.fetch.fetch_shared(slot) } + + unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_shared_chunk(batch, slot) + } } impl<'w, 'q, Q, M> PreparedFetch<'q> for PreparedCmp<'w, Q, M> @@ -202,14 +206,14 @@ where } } - type Batch = >::Batch; + type Chunk = >::Chunk; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.fetch.create_chunk(slots) } #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { Q::fetch_next(batch) } } diff --git a/src/filter/constant.rs b/src/filter/constant.rs index 505a479c..b6bde412 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -39,16 +39,16 @@ impl<'a> Fetch<'a> for Nothing { impl<'q> PreparedFetch<'q> for Nothing { type Item = (); - type Batch = (); + type Chunk = (); unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.end, slots.end) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} } /// Yields all entities @@ -82,12 +82,12 @@ impl<'w> Fetch<'w> for All { impl<'q> PreparedFetch<'q> for All { type Item = (); - type Batch = (); + type Chunk = (); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} } impl<'q> FetchItem<'q> for Slice { @@ -117,7 +117,7 @@ impl<'w> Fetch<'w> for Slice { impl<'q> PreparedFetch<'q> for Slice { type Item = (); - type Batch = (); + type Chunk = (); #[inline] unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -125,9 +125,9 @@ impl<'q> PreparedFetch<'q> for Slice { .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} } impl<'w, 'q> FetchItem<'q> for bool { @@ -160,14 +160,14 @@ impl<'w> Fetch<'w> for bool { impl<'q> PreparedFetch<'q> for bool { type Item = bool; - type Batch = bool; + type Chunk = bool; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { *self } #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { *batch } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index f193cfc3..968623f3 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -146,13 +146,13 @@ where self.filter.filter_slots(l) } - type Batch = Q::Batch; + type Chunk = Q::Chunk; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.fetch.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { Q::fetch_next(batch) } } @@ -275,7 +275,7 @@ pub struct Without { pub(crate) name: &'static str, } -impl<'w, 'q> FetchItem<'q> for Without { +impl<'q> FetchItem<'q> for Without { type Item = (); } @@ -540,15 +540,17 @@ pub struct BatchSize(pub(crate) Slot); impl<'q> PreparedFetch<'q> for BatchSize { type Item = (); - type Batch = (); + type Chunk = (); unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { Slice::new(slots.start, slots.end.min(slots.start + self.0)) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + #[inline] + unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {} } impl<'q> FetchItem<'q> for BatchSize { diff --git a/src/filter/set.rs b/src/filter/set.rs index 324f169c..854128b2 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -78,14 +78,14 @@ where self.1.filter_slots(l) } - type Batch = (L::Batch, R::Batch); + type Chunk = (L::Chunk, R::Chunk); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { (self.0.create_chunk(slots), self.1.create_chunk(slots)) } #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { (L::fetch_next(&mut batch.0), R::fetch_next(&mut batch.1)) } } @@ -146,11 +146,11 @@ where } } - type Batch = (); + type Chunk = (); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch {} + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} } impl ops::BitOr for Not { @@ -244,15 +244,15 @@ where self.filter_union(slots) } - type Batch = T::Batch; + type Chunk = T::Chunk; #[inline] - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Batch { + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.0.create_chunk(slots) } #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item { + unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { T::fetch_next(batch) } } @@ -299,7 +299,7 @@ macro_rules! tuple_impl { where 'w: 'q, $($ty: PreparedFetch<'q>,)* { type Item = (); - type Batch = (); + type Chunk = (); unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { let inner = &mut self.0; @@ -314,9 +314,10 @@ macro_rules! tuple_impl { } #[inline] - unsafe fn fetch_next(batch: &mut Self::Batch) -> Self::Item {} + unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {} - unsafe fn create_chunk(&mut self, slots: Slice) -> Self::Batch {} + #[inline] + unsafe fn create_chunk(&mut self, _: Slice) -> Self::Chunk {} } diff --git a/src/query/iter.rs b/src/query/iter.rs index 101d1a02..8a25a2d8 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -9,7 +9,7 @@ use crate::{ /// In essence, this is the unflattened version of [crate::QueryIter]. pub struct Chunk<'q, Q: PreparedFetch<'q>> { arch: &'q Archetype, - fetch: Q::Batch, + fetch: Q::Chunk, pos: Slot, end: Slot, } @@ -24,7 +24,7 @@ impl<'q, Q: PreparedFetch<'q>> core::fmt::Debug for Chunk<'q, Q> { } impl<'q, Q: PreparedFetch<'q>> Chunk<'q, Q> { - pub(crate) fn new(arch: &'q Archetype, batch: Q::Batch, slice: Slice) -> Self { + pub(crate) fn new(arch: &'q Archetype, batch: Q::Chunk, slice: Slice) -> Self { Self { arch, fetch: batch, diff --git a/src/query/planar.rs b/src/query/planar.rs index dfd1cd76..b4dbd4c6 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -222,7 +222,7 @@ where where Q: Sync, Q::Prepared: Send, - for<'x> >::Batch: Send, + for<'x> >::Chunk: Send, F: Sync, F::Prepared: Send, { diff --git a/src/system/mod.rs b/src/system/mod.rs index b0b75192..66caff4f 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -78,7 +78,7 @@ where for<'x> Q: Fetch<'x>, for<'x> F: Fetch<'x>, for<'x> as Fetch<'x>>::Prepared: Send, - for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Batch: Send, + for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Chunk: Send, for<'x> Func: Fn(>::Item) + Send + Sync, { fn execute(&mut self, mut data: (QueryData,)) { @@ -113,7 +113,7 @@ impl SystemBuilder<(Query,), T> where for<'x> Q: 'static + Fetch<'x> + Send, for<'x> F: 'static + Fetch<'x> + Send, - for<'x> <>::Prepared as PreparedFetch<'x>>::Batch: Send, + for<'x> <>::Prepared as PreparedFetch<'x>>::Chunk: Send, // for<'x, 'y> crate::query::Batch<'y, >::Prepared>: Send, { /// Execute a function for each item in the query in parallel batches From 411d3fd4616350a2f4cdec73eaa59e8a020b7c8d Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 19:01:08 +0200 Subject: [PATCH 48/52] fix: remaining queries --- src/fetch/map.rs | 2 +- src/fetch/mod.rs | 66 ++++++++++++++++++++---------------------- src/fetch/peek.rs | 24 --------------- src/fetch/read_only.rs | 15 ---------- src/fetch/satisfied.rs | 35 ++++++++++++++-------- src/filter/mod.rs | 16 +++++----- src/filter/set.rs | 9 +++--- 7 files changed, 69 insertions(+), 98 deletions(-) delete mode 100644 src/fetch/peek.rs diff --git a/src/fetch/map.rs b/src/fetch/map.rs index 55259886..37c23ecc 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -66,7 +66,7 @@ where type Chunk = (&'q F, Q::Chunk); unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { - todo!() + (self.func, self.query.create_chunk(slots)) } unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index a872b3ad..ed9def3a 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -215,8 +215,10 @@ impl<'w> Fetch<'w> for () { } impl<'q> ReadOnlyFetch<'q> for () { + #[inline] unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item {} + #[inline] + unsafe fn fetch_shared_chunk(_: &Self::Chunk, _: Slot) -> Self::Item {} } impl<'q> PreparedFetch<'q> for () { @@ -224,44 +226,38 @@ impl<'q> PreparedFetch<'q> for () { type Chunk = (); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} -} - -impl<'q, F> PreparedFetch<'q> for Option -where - F: PreparedFetch<'q>, -{ - type Item = Option; - type Chunk = Option; - - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { - if let Some(fetch) = self { - Some(fetch.create_chunk(slots)) - } else { - None - } - } - #[inline] - unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - if let Some(fetch) = self { - fetch.filter_slots(slots) - } else { - Slice::new(slots.end, slots.end) - } - } + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - if let Some(fetch) = batch { - Some(F::fetch_next(fetch)) - } else { - None - } - } + #[inline] + unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {} } +// impl<'q, F> PreparedFetch<'q> for Option +// where +// F: PreparedFetch<'q>, +// { +// type Item = Option; +// type Chunk = Option; + +// unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { +// self.as_mut().map(|fetch| fetch.create_chunk(slots)) +// } + +// #[inline] +// unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { +// if let Some(fetch) = self { +// fetch.filter_slots(slots) +// } else { +// Slice::new(slots.end, slots.end) +// } +// } + +// unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { +// batch.as_mut().map(|fetch| F::fetch_next(fetch)) +// } +// } + #[derive(Debug, Clone)] /// Returns the entity ids pub struct EntityIds; diff --git a/src/fetch/peek.rs b/src/fetch/peek.rs deleted file mode 100644 index fb1ff7d5..00000000 --- a/src/fetch/peek.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::archetype::Slot; - -/// Specialization of a prepared fetch which allows peeking -pub trait PeekableFetch<'p> { - /// An immutable reference or owned type to the peeked item - type Peek: 'p; - - /// Peek a slot - /// # Safety - /// A peek of the same slot should not alias with a reference returned by - /// [`PreparedFetch::fetch`]. - unsafe fn peek(&'q self, slot: Slot) -> Self::Peek; -} - -impl<'p, F> PeekableFetch<'p> for Option -where - F: PeekableFetch<'p>, -{ - type Peek = Option; - - unsafe fn peek(&'q self, slot: Slot) -> Self::Peek { - self.as_ref().map(|fetch| fetch.peek(slot)) - } -} diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index 60740078..4890eb5b 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -13,18 +13,3 @@ pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item; } - -impl<'q, F> ReadOnlyFetch<'q> for Option -where - F: ReadOnlyFetch<'q>, -{ - unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item { - self.as_ref().map(|fetch| fetch.fetch_shared(slot)) - } - - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - batch - .as_ref() - .map(|v| >::fetch_shared_chunk(v, slot)) - } -} diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 40de00dd..5ea4f11d 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -43,11 +43,13 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { type Chunk = bool; unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { - let res = self.0.filter_slots(slots); - if res.is_empty() { - false - } else { - true + match &mut self.0 { + Some(f) => { + let res = f.filter_slots(slots); + eprintln!("satisfied create_chunk {res:?}"); + !res.is_empty() + } + None => false, } } @@ -56,12 +58,21 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { - let res = self.0.filter_slots(slots); - - if res.is_empty() { - Slice::new(slots.start, (slots.start + 1).min(slots.end)) - } else { - res + match &mut self.0 { + Some(f) => { + let res = f.filter_slots(slots); + eprintln!("satisfied filter_slots {slots:?} => {res:?}"); + + // Something was missed + if res.start != slots.start { + // Catch the negative slice + eprintln!("neg"); + Slice::new(slots.start, res.start) + } else { + res + } + } + None => slots, } } } @@ -153,7 +164,7 @@ mod test { *world.get_mut(ids[1], a()).unwrap() = 5; - assert_eq!( + ::std::assert_eq!( query.collect_vec(&world), [ ("a".into(), false), diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 968623f3..59230e1d 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -738,13 +738,15 @@ mod tests { let world = World::new(); let chunks = FilterIter::new( slots, - filter.prepare(FetchPrepareData { - world: &world, - arch: &archetype, - arch_id: ArchetypeId::MAX, - old_tick: 0, - new_tick: 1, - }), + filter + .prepare(FetchPrepareData { + world: &world, + arch: &archetype, + arch_id: ArchetypeId::MAX, + old_tick: 0, + new_tick: 1, + }) + .unwrap(), ) .flatten() .collect_vec(); diff --git a/src/filter/set.rs b/src/filter/set.rs index 854128b2..30e1c381 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -1,6 +1,6 @@ use crate::{ archetype::{Archetype, Slice}, - fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, UnionFilter}, + fetch::{FetchAccessData, FetchPrepareData, FmtQuery, Opt, PreparedFetch, UnionFilter}, system::Access, Fetch, FetchItem, }; @@ -303,9 +303,10 @@ macro_rules! tuple_impl { unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { let inner = &mut self.0; + let end = Slice::new(slots.end, slots.end); [ - $( inner.$idx.filter_slots(slots)),* + $( inner.$idx.as_mut().map(|v| v.filter_slots(slots)).unwrap_or(end)),* ] .into_iter() .min() @@ -326,14 +327,14 @@ macro_rules! tuple_impl { { unsafe fn filter_union(&mut self, slots: Slice) -> Slice { let inner = &mut self.0; + let end = Slice::new(slots.end, slots.end); [ - $( inner.$idx.filter_slots(slots)),* + $( inner.$idx.as_mut().map(|v| v.filter_slots(slots)).unwrap_or(end)),* ] .into_iter() .min() .unwrap_or_default() - } } }; From be904842eb6642a911ea571ee1f5e16817ee46c4 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 19:06:28 +0200 Subject: [PATCH 49/52] chore: batch => chunk --- flax-derive/src/lib.rs | 9 ++------- src/commands.rs | 8 ++++---- src/fetch/as_deref.rs | 8 ++++---- src/fetch/cloned.rs | 8 ++++---- src/fetch/component.rs | 8 ++++---- src/fetch/component_mut.rs | 4 ++-- src/fetch/copied.rs | 8 ++++---- src/fetch/entity_ref.rs | 10 +++++----- src/fetch/map.rs | 4 ++-- src/fetch/maybe_mut.rs | 20 ++++++++++---------- src/fetch/mod.rs | 20 ++++++++++---------- src/fetch/opt.rs | 12 ++++++------ src/fetch/read_only.rs | 2 +- src/fetch/relations.rs | 8 ++++---- src/fetch/satisfied.rs | 4 ++-- src/fetch/source.rs | 4 ++-- src/filter/change.rs | 12 ++++++------ src/filter/cmp.rs | 8 ++++---- src/filter/constant.rs | 10 +++++----- src/filter/mod.rs | 4 ++-- src/filter/set.rs | 10 +++++----- src/format.rs | 2 +- src/query/iter.rs | 4 ++-- src/world.rs | 24 ++++++++++++------------ 24 files changed, 103 insertions(+), 108 deletions(-) diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index a41e661e..48a509b7 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -90,7 +90,6 @@ fn derive_fetch_struct(params: &Params) -> TokenStream { item_name, prepared_name, q_generics, - wq_generics, field_names, field_types, w_lf, @@ -308,9 +307,9 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { type Chunk = (#(<<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::Chunk,)*); #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { Self::Item { - #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::fetch_next(&mut batch.#field_idx),)* + #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::fetch_next(&mut chunk.#field_idx),)* } } @@ -485,10 +484,6 @@ impl<'a> Params<'a> { self.q_generics.split_for_impl().1 } - fn wq_ty(&self) -> TypeGenerics { - self.wq_generics.split_for_impl().1 - } - fn w_ty(&self) -> TypeGenerics { self.w_generics.split_for_impl().1 } diff --git a/src/commands.rs b/src/commands.rs index d341a760..f35b4829 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -149,15 +149,15 @@ impl CommandBuffer { } /// Spawn a new batch with the given components of the builder - pub fn spawn_batch(&mut self, batch: impl Into) -> &mut Self { - self.commands.push(Command::SpawnBatch(batch.into())); + pub fn spawn_batch(&mut self, chunk: impl Into) -> &mut Self { + self.commands.push(Command::SpawnBatch(chunk.into())); self } /// Spawn a new batch with the given components of the builder - pub fn spawn_batch_at(&mut self, ids: Vec, batch: impl Into) -> &mut Self { - self.commands.push(Command::SpawnBatchAt(batch.into(), ids)); + pub fn spawn_batch_at(&mut self, ids: Vec, chunk: impl Into) -> &mut Self { + self.commands.push(Command::SpawnBatchAt(chunk.into(), ids)); self } diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index b3e0214b..6402e269 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -67,8 +67,8 @@ where self.0.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - F::fetch_next(batch) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + F::fetch_next(chunk) } } @@ -81,7 +81,7 @@ where self.0.fetch_shared(slot) } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: crate::archetype::Slot) -> Self::Item { - F::fetch_shared_chunk(batch, slot) + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: crate::archetype::Slot) -> Self::Item { + F::fetch_shared_chunk(chunk, slot) } } diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index c5058bc4..164cd815 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -77,8 +77,8 @@ where self.0.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - F::fetch_next(batch).clone() + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + F::fetch_next(chunk).clone() } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -96,8 +96,8 @@ where self.0.fetch_shared(slot).clone() } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - F::fetch_shared_chunk(batch, slot).clone() + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_shared_chunk(chunk, slot).clone() } } diff --git a/src/fetch/component.rs b/src/fetch/component.rs index 5821d301..2f28c7f5 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -22,8 +22,8 @@ impl<'w, 'q, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - batch.next().unwrap() + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + chunk.next().unwrap() } } @@ -34,8 +34,8 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for ReadComponent<'w, T> { } #[inline] - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - &batch.as_slice()[slot] + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + &chunk.as_slice()[slot] } } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 4bcd9da0..a733f88a 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -106,8 +106,8 @@ impl<'w, 'q, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { // TODO: raw stepping slice access - batch.next().unwrap() + chunk.next().unwrap() } } diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index 5b3c41af..0e8af385 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -78,8 +78,8 @@ where self.0.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - *F::fetch_next(batch) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + *F::fetch_next(chunk) } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -97,8 +97,8 @@ where *self.0.fetch_shared(slot) } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: crate::archetype::Slot) -> Self::Item { - *F::fetch_shared_chunk(batch, slot) + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: crate::archetype::Slot) -> Self::Item { + *F::fetch_shared_chunk(chunk, slot) } } diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index 1458f4e4..d8cf97a7 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -78,14 +78,14 @@ impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - let slot = batch.slot; + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + let slot = chunk.slot; EntityRef { - arch: batch.arch, - world: batch.world, + arch: chunk.arch, + world: chunk.world, slot, - id: batch.arch.entities[slot], + id: chunk.arch.entities[slot], } } } diff --git a/src/fetch/map.rs b/src/fetch/map.rs index 37c23ecc..56ed3e73 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -69,8 +69,8 @@ where (self.func, self.query.create_chunk(slots)) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - (batch.0)(Q::fetch_next(&mut batch.1)) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + (chunk.0)(Q::fetch_next(&mut chunk.1)) } unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index b8a8bdbb..2c01c9c6 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -107,14 +107,14 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { } } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - let slot = batch.slot; - batch.slot += 1; + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + let slot = chunk.slot; + chunk.slot += 1; MutGuard { slot, - cell: batch.cell, - new_tick: batch.new_tick, - id: batch.ids[slot], + cell: chunk.cell, + new_tick: chunk.new_tick, + id: chunk.ids[slot], _marker: PhantomData, } } @@ -132,12 +132,12 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedMaybeMut<'w, T> { } } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { MutGuard { slot, - cell: batch.cell, - new_tick: batch.new_tick, - id: batch.ids[slot], + cell: chunk.cell, + new_tick: chunk.new_tick, + id: chunk.ids[slot], _marker: PhantomData, } } diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index ed9def3a..9d7b888c 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -141,7 +141,7 @@ pub trait PreparedFetch<'q> { /// prepared archetype. /// /// The callee is responsible for assuring disjoint calls. - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item; + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item; #[inline] /// Filter the slots to visit @@ -174,8 +174,8 @@ where (*self).create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - F::fetch_next(batch) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + F::fetch_next(chunk) } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -253,7 +253,7 @@ impl<'q> PreparedFetch<'q> for () { // } // } -// unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { +// unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { // batch.as_mut().map(|fetch| F::fetch_next(fetch)) // } // } @@ -302,8 +302,8 @@ impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { self.entities[slots.as_range()].iter() } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - *batch.next().unwrap() + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + *chunk.next().unwrap() } } @@ -312,8 +312,8 @@ impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { unsafe fn fetch_shared(&self, slot: usize) -> Self::Item { self.entities[slot] } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - batch.as_slice()[slot] + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + chunk.as_slice()[slot] } } @@ -355,9 +355,9 @@ macro_rules! tuple_impl { type Chunk = ($($ty::Chunk,)*); #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { ($( - $ty::fetch_next(&mut batch.$idx), + $ty::fetch_next(&mut chunk.$idx), )*) } diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 6bb09c65..82523dfb 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -58,8 +58,8 @@ where self.0.as_ref().map(|fetch| fetch.fetch_shared(slot)) } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - batch.as_ref().map(|v| F::fetch_shared_chunk(v, slot)) + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + chunk.as_ref().map(|v| F::fetch_shared_chunk(v, slot)) } } @@ -83,8 +83,8 @@ where self.0.as_mut().map(|v| v.create_chunk(slots)) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - batch.as_mut().map(|v| F::fetch_next(v)) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + chunk.as_mut().map(|v| F::fetch_next(v)) } } @@ -163,8 +163,8 @@ where } } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - match batch { + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + match chunk { Either::Left(v) => F::fetch_next(v), Either::Right(v) => v, } diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index 4890eb5b..e917745d 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -11,5 +11,5 @@ pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { /// # Safety /// Slot must be valid unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item; + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item; } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index 29122953..ae03d6e1 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -95,12 +95,12 @@ where } } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - let slot = batch.slot; - batch.slot += 1; + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + let slot = chunk.slot; + chunk.slot += 1; RelationsIter { - borrows: batch.borrows.iter(), + borrows: chunk.borrows.iter(), slot, } } diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 5ea4f11d..43b84880 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -53,8 +53,8 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { } } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - *batch + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + *chunk } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { diff --git a/src/fetch/source.rs b/src/fetch/source.rs index 32fb020a..39cb04a6 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -171,8 +171,8 @@ where self.fetch.create_chunk(Slice::single(self.slot)) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - Q::fetch_shared_chunk(batch, 0) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + Q::fetch_shared_chunk(chunk, 0) } } diff --git a/src/filter/change.rs b/src/filter/change.rs index 6519e6b3..5aef1280 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -49,8 +49,8 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T } #[inline] - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - batch.as_slice().get_unchecked(slot) + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + chunk.as_slice().get_unchecked(slot) } } @@ -171,8 +171,8 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T type Chunk = slice::Iter<'q, T>; #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - batch.next().unwrap() + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + chunk.next().unwrap() } #[inline] @@ -283,7 +283,7 @@ impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} #[inline] - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item {} + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {} } impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { @@ -303,7 +303,7 @@ impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} } #[cfg(test)] diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index 9b77befb..b88e42de 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -170,8 +170,8 @@ where self.fetch.fetch_shared(slot) } - unsafe fn fetch_shared_chunk(batch: &Self::Chunk, slot: Slot) -> Self::Item { - F::fetch_shared_chunk(batch, slot) + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_shared_chunk(chunk, slot) } } @@ -213,8 +213,8 @@ where } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - Q::fetch_next(batch) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + Q::fetch_next(chunk) } } diff --git a/src/filter/constant.rs b/src/filter/constant.rs index b6bde412..e1dc3cf0 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -48,7 +48,7 @@ impl<'q> PreparedFetch<'q> for Nothing { unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} } /// Yields all entities @@ -87,7 +87,7 @@ impl<'q> PreparedFetch<'q> for All { unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} } impl<'q> FetchItem<'q> for Slice { @@ -127,7 +127,7 @@ impl<'q> PreparedFetch<'q> for Slice { unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} } impl<'w, 'q> FetchItem<'q> for bool { @@ -167,7 +167,7 @@ impl<'q> PreparedFetch<'q> for bool { } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - *batch + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + *chunk } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 59230e1d..a992042f 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -152,8 +152,8 @@ where self.fetch.create_chunk(slots) } - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - Q::fetch_next(batch) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + Q::fetch_next(chunk) } } diff --git a/src/filter/set.rs b/src/filter/set.rs index 30e1c381..0afb9856 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -85,8 +85,8 @@ where } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - (L::fetch_next(&mut batch.0), R::fetch_next(&mut batch.1)) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + (L::fetch_next(&mut chunk.0), R::fetch_next(&mut chunk.1)) } } @@ -150,7 +150,7 @@ where unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} } impl ops::BitOr for Not { @@ -252,8 +252,8 @@ where } #[inline] - unsafe fn fetch_next(batch: &mut Self::Chunk) -> Self::Item { - T::fetch_next(batch) + unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + T::fetch_next(chunk) } } diff --git a/src/format.rs b/src/format.rs index a1db87b8..c1beba72 100644 --- a/src/format.rs +++ b/src/format.rs @@ -31,7 +31,7 @@ where for slot in batch.slots().iter() { assert!( slot < arch.len(), - "batch is larger than archetype, batch: {:?}, arch: {:?}", + "batch is larger than archetype, chunk: {:?}, arch: {:?}", batch.slots(), arch.entities() ); diff --git a/src/query/iter.rs b/src/query/iter.rs index 8a25a2d8..73326901 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -24,10 +24,10 @@ impl<'q, Q: PreparedFetch<'q>> core::fmt::Debug for Chunk<'q, Q> { } impl<'q, Q: PreparedFetch<'q>> Chunk<'q, Q> { - pub(crate) fn new(arch: &'q Archetype, batch: Q::Chunk, slice: Slice) -> Self { + pub(crate) fn new(arch: &'q Archetype, chunk: Q::Chunk, slice: Slice) -> Self { Self { arch, - fetch: batch, + fetch: chunk, pos: slice.start, end: slice.end, } diff --git a/src/world.rs b/src/world.rs index 2a728c21..ca2e60b5 100644 --- a/src/world.rs +++ b/src/world.rs @@ -134,21 +134,21 @@ impl World { } /// Efficiently spawn many entities with the same components at once. - pub fn spawn_batch(&mut self, batch: &mut BatchSpawn) -> Vec { + pub fn spawn_batch(&mut self, chunk: &mut BatchSpawn) -> Vec { self.flush_reserved(); - for component in batch.components() { + for component in chunk.components() { self.init_component(component); } let change_tick = self.advance_change_tick(); - let (arch_id, arch) = self.archetypes.find_create(batch.components()); + let (arch_id, arch) = self.archetypes.find_create(chunk.components()); let base = arch.len(); let store = self.entities.init(EntityKind::empty()); - let ids = (0..batch.len()) + let ids = (0..chunk.len()) .map(|idx| { store.spawn(EntityLocation { slot: base + idx, @@ -159,7 +159,7 @@ impl World { let _ = arch.allocate_n(&ids); - for (_, mut storage) in batch.take_all() { + for (_, mut storage) in chunk.take_all() { unsafe { arch.extend(&mut storage, change_tick) .expect("Component not in archetype"); @@ -824,25 +824,25 @@ impl World { pub fn spawn_batch_at<'a>( &mut self, ids: &'a [Entity], - batch: &mut BatchSpawn, + chunk: &mut BatchSpawn, ) -> Result<&'a [Entity]> { - for component in batch.components() { + for component in chunk.components() { self.init_component(component); } - self.spawn_batch_at_inner(ids, batch) + self.spawn_batch_at_inner(ids, chunk) } /// Does not initialize components fn spawn_batch_at_inner<'a>( &mut self, ids: &'a [Entity], - batch: &mut BatchSpawn, + chunk: &mut BatchSpawn, ) -> Result<&'a [Entity]> { self.flush_reserved(); assert_eq!( ids.len(), - batch.len(), + chunk.len(), "The length of ids must match the number of slots in `batch`" ); @@ -856,7 +856,7 @@ impl World { let change_tick = self.advance_change_tick(); - let (arch_id, arch) = self.archetypes.find_create(batch.components()); + let (arch_id, arch) = self.archetypes.find_create(chunk.components()); let base = arch.len(); for (idx, &id) in ids.iter().enumerate() { @@ -880,7 +880,7 @@ impl World { let arch = self.archetypes.get_mut(arch_id); - for (_, mut storage) in batch.take_all() { + for (_, mut storage) in chunk.take_all() { unsafe { arch.extend(&mut storage, change_tick) .expect("Component not in archetype"); From babbf8e4faabc770fcf54b34a9c9fb456c0dd219 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 19:16:06 +0200 Subject: [PATCH 50/52] chore: improve miri speed --- src/serialize/mod.rs | 8 ++++---- tests/merge.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/serialize/mod.rs b/src/serialize/mod.rs index 6fca6efc..0298bb71 100644 --- a/src/serialize/mod.rs +++ b/src/serialize/mod.rs @@ -207,10 +207,9 @@ mod test { .with(status_effects()) .build(); - let json = serde_json::to_string_pretty( - &serializer.serialize(&world, SerializeFormat::ColumnMajor), - ) - .unwrap(); + let json = + serde_json::to_string(&serializer.serialize(&world, SerializeFormat::ColumnMajor)) + .unwrap(); let new_world: World = deserializer .deserialize(&mut serde_json::Deserializer::from_str(&json[..])) @@ -239,6 +238,7 @@ mod test { let encoded = ron::to_string(&serializer.serialize(&world, SerializeFormat::ColumnMajor)).unwrap(); + let new_world = deserializer .deserialize(&mut ron::Deserializer::from_str(&encoded).unwrap()) .unwrap(); diff --git a/tests/merge.rs b/tests/merge.rs index 242ff095..f0952431 100644 --- a/tests/merge.rs +++ b/tests/merge.rs @@ -246,7 +246,7 @@ fn merge_custom() { .unwrap(); random_entities(&mut rng) - .take(1000) + .take(100) .enumerate() .for_each(|(i, mut v)| { v.set(name(), format!("a.{i}")).spawn(&mut world); From cced257e044ab712ecb7206afba17095ee8fc08d Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Sun, 6 Aug 2023 19:17:58 +0200 Subject: [PATCH 51/52] fix: no-std --- src/fetch/component_mut.rs | 5 ----- src/fetch/satisfied.rs | 5 +---- src/fetch/transform.rs | 2 ++ 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index a733f88a..9c0c2993 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -90,11 +90,6 @@ impl<'w, 'q, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> type Chunk = slice::IterMut<'q, T>; unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { - eprintln!( - "Modified {:?} {}", - &self.arch.entities[slots.as_range()], - self.tick, - ); self.guard .set_modified(&self.arch.entities[slots.as_range()], slots, self.tick); diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 43b84880..9ef6b3fb 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -46,7 +46,6 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { match &mut self.0 { Some(f) => { let res = f.filter_slots(slots); - eprintln!("satisfied create_chunk {res:?}"); !res.is_empty() } None => false, @@ -61,12 +60,10 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { match &mut self.0 { Some(f) => { let res = f.filter_slots(slots); - eprintln!("satisfied filter_slots {slots:?} => {res:?}"); // Something was missed if res.start != slots.start { // Catch the negative slice - eprintln!("neg"); Slice::new(slots.start, res.start) } else { res @@ -164,7 +161,7 @@ mod test { *world.get_mut(ids[1], a()).unwrap() = 5; - ::std::assert_eq!( + assert_eq!( query.collect_vec(&world), [ ("a".into(), false), diff --git a/src/fetch/transform.rs b/src/fetch/transform.rs index d93e1df4..49c0208a 100644 --- a/src/fetch/transform.rs +++ b/src/fetch/transform.rs @@ -311,6 +311,8 @@ mod tests { ); } + #[test] + #[cfg(feature = "derive")] fn test_derive_parse() { use crate::{fetch::Cloned, Component, Fetch}; From 2c9223eb4c65d742249f0f6edc523dec7d70d9c1 Mon Sep 17 00:00:00 2001 From: Tei Roberts Date: Mon, 7 Aug 2023 00:31:02 +0200 Subject: [PATCH 52/52] chore: use advancing ptr --- asteroids/src/main.rs | 2 +- examples/guide/query.rs | 2 +- flax-derive/src/lib.rs | 4 +- src/archetype/guard.rs | 2 +- src/archetype/mod.rs | 4 +- src/fetch/as_deref.rs | 7 +-- src/fetch/cloned.rs | 4 +- src/fetch/component.rs | 17 ++++---- src/fetch/component_mut.rs | 23 +++++----- src/fetch/copied.rs | 6 +-- src/fetch/entity_ref.rs | 11 ++--- src/fetch/map.rs | 6 +-- src/fetch/maybe_mut.rs | 10 ++--- src/fetch/mod.rs | 35 +++++++++------ src/fetch/opt.rs | 8 ++-- src/fetch/read_only.rs | 3 ++ src/fetch/relations.rs | 9 +--- src/fetch/satisfied.rs | 7 ++- src/fetch/source.rs | 2 +- src/filter/change.rs | 28 ++++++------ src/filter/cmp.rs | 4 +- src/filter/constant.rs | 25 ++++++----- src/filter/mod.rs | 6 +-- src/filter/set.rs | 23 ++++++---- src/query/borrow.rs | 8 ++-- src/query/dfs.rs | 4 +- src/query/entity.rs | 4 +- src/query/iter.rs | 46 +++----------------- src/query/planar.rs | 8 ++-- src/query/walk.rs | 3 +- src/schedule/mod.rs | 4 +- src/system/mod.rs | 10 ++--- src/util/mod.rs | 88 ++++++++++++++++++++++++++++++++++++++ tests/access.rs | 8 ++-- tests/entity.rs | 6 +-- tests/filter.rs | 4 +- tests/schedule.rs | 4 +- 37 files changed, 259 insertions(+), 186 deletions(-) diff --git a/asteroids/src/main.rs b/asteroids/src/main.rs index 0c294ef8..36552189 100644 --- a/asteroids/src/main.rs +++ b/asteroids/src/main.rs @@ -113,7 +113,7 @@ async fn main() -> Result<()> { while acc > 0.0 { acc -= dt; - let batches = physics_schedule.batch_info(&mut world); + let batches = physics_schedule.batch_info(&world); tracing::debug!( "Batches: {:#?}", batches diff --git a/examples/guide/query.rs b/examples/guide/query.rs index 3ed516df..91fc5ecb 100644 --- a/examples/guide/query.rs +++ b/examples/guide/query.rs @@ -226,7 +226,7 @@ fn main() -> anyhow::Result<()> { for i in 0..20 { tracing::info!("Frame: {i}"); - tracing::info!("Batches: {:#?}", schedule.batch_info(&mut world)); + tracing::info!("Batches: {:#?}", schedule.batch_info(&world)); schedule.execute_par(&mut world)?; } diff --git a/flax-derive/src/lib.rs b/flax-derive/src/lib.rs index 48a509b7..459e772b 100644 --- a/flax-derive/src/lib.rs +++ b/flax-derive/src/lib.rs @@ -307,9 +307,9 @@ fn derive_prepared_struct(params: &Params) -> TokenStream { type Chunk = (#(<<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::Chunk,)*); #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: #crate_name::archetype::Slot) -> Self::Item { Self::Item { - #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::fetch_next(&mut chunk.#field_idx),)* + #(#field_names: <<#field_types as #crate_name::fetch::Fetch<'w>>::Prepared as #crate_name::fetch::PreparedFetch<'q>>::fetch_next(&mut chunk.#field_idx, slot),)* } } diff --git a/src/archetype/guard.rs b/src/archetype/guard.rs index e70c5a18..9d0fb72d 100644 --- a/src/archetype/guard.rs +++ b/src/archetype/guard.rs @@ -155,7 +155,7 @@ impl<'a, T> Deref for RefMut<'a, T> { #[inline] fn deref(&self) -> &Self::Target { - &self.guard.get() + self.guard.get() } } diff --git a/src/archetype/mod.rs b/src/archetype/mod.rs index 9fbdf6fe..4950a105 100644 --- a/src/archetype/mod.rs +++ b/src/archetype/mod.rs @@ -251,8 +251,8 @@ impl Cell { // } #[inline] - pub fn get_mut<'a, T: ComponentValue>( - &'a self, + pub fn get_mut( + &self, id: Entity, slot: Slot, tick: u32, diff --git a/src/fetch/as_deref.rs b/src/fetch/as_deref.rs index 6402e269..981c61ef 100644 --- a/src/fetch/as_deref.rs +++ b/src/fetch/as_deref.rs @@ -1,5 +1,5 @@ use super::{FetchAccessData, FmtQuery, PreparedFetch, ReadOnlyFetch}; -use crate::{query::ArchetypeSearcher, system::Access, Fetch, FetchItem}; +use crate::{archetype::Slot, query::ArchetypeSearcher, system::Access, Fetch, FetchItem}; use alloc::vec::Vec; use core::{fmt, ops::Deref}; @@ -67,8 +67,9 @@ where self.0.create_chunk(slots) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - F::fetch_next(chunk) + #[inline] + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_next(chunk, slot) } } diff --git a/src/fetch/cloned.rs b/src/fetch/cloned.rs index 164cd815..ad9f31f1 100644 --- a/src/fetch/cloned.rs +++ b/src/fetch/cloned.rs @@ -77,8 +77,8 @@ where self.0.create_chunk(slots) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - F::fetch_next(chunk).clone() + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_next(chunk, slot).clone() } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { diff --git a/src/fetch/component.rs b/src/fetch/component.rs index 2f28c7f5..220880a3 100644 --- a/src/fetch/component.rs +++ b/src/fetch/component.rs @@ -1,8 +1,6 @@ -use core::slice; - use atomic_refcell::AtomicRef; -use crate::{archetype::Slot, system::AccessKind, Component, ComponentValue}; +use crate::{archetype::Slot, system::AccessKind, util::Ptr, Component, ComponentValue}; use super::{read_only::ReadOnlyFetch, *}; @@ -14,16 +12,19 @@ pub struct ReadComponent<'a, T> { impl<'w, 'q, T: 'q> PreparedFetch<'q> for ReadComponent<'w, T> { type Item = &'q T; - type Chunk = slice::Iter<'q, T>; + type Chunk = Ptr<'q, T>; #[inline] unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { - self.borrow[slots.as_range()].iter() + Ptr::new(self.borrow[slots.as_range()].as_ptr()) } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - chunk.next().unwrap() + // See: + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { + let old = chunk.as_ptr(); + chunk.advance(1); + &*old } } @@ -35,7 +36,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for ReadComponent<'w, T> { #[inline] unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { - &chunk.as_slice()[slot] + chunk.add(slot).as_ref() } } diff --git a/src/fetch/component_mut.rs b/src/fetch/component_mut.rs index 9c0c2993..3843d22d 100644 --- a/src/fetch/component_mut.rs +++ b/src/fetch/component_mut.rs @@ -1,13 +1,11 @@ use alloc::vec::Vec; -use core::{ - fmt::{self, Formatter}, - slice, -}; +use core::fmt::{self, Formatter}; use crate::{ - archetype::{Archetype, CellMutGuard, Slice}, + archetype::{Archetype, CellMutGuard, Slice, Slot}, system::{Access, AccessKind}, + util::PtrMut, Component, ComponentValue, Fetch, FetchItem, }; @@ -87,22 +85,21 @@ pub struct WriteComponent<'a, T> { impl<'w, 'q, T: 'q + ComponentValue> PreparedFetch<'q> for WriteComponent<'w, T> { type Item = &'q mut T; - type Chunk = slice::IterMut<'q, T>; + type Chunk = PtrMut<'q, T>; unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { self.guard .set_modified(&self.arch.entities[slots.as_range()], slots, self.tick); // Convert directly into a non-overlapping subslice without reading the whole slice - let ptr = (self.guard.storage().as_ptr() as *mut T).add(slots.start); - - let slice = slice::from_raw_parts_mut(ptr, slots.len()); - slice.iter_mut() + PtrMut::new((self.guard.storage().as_ptr() as *mut T).add(slots.start)) } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - // TODO: raw stepping slice access - chunk.next().unwrap() + // See: + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { + let old = chunk.as_ptr(); + chunk.advance(1); + &mut *old } } diff --git a/src/fetch/copied.rs b/src/fetch/copied.rs index 0e8af385..dd882e0d 100644 --- a/src/fetch/copied.rs +++ b/src/fetch/copied.rs @@ -6,7 +6,7 @@ use core::{ use alloc::vec::Vec; use crate::{ - archetype::{Archetype, Slice}, + archetype::{Archetype, Slice, Slot}, system::Access, Fetch, FetchItem, }; @@ -78,8 +78,8 @@ where self.0.create_chunk(slots) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - *F::fetch_next(chunk) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + *F::fetch_next(chunk, slot) } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { diff --git a/src/fetch/entity_ref.rs b/src/fetch/entity_ref.rs index d8cf97a7..6ec249bc 100644 --- a/src/fetch/entity_ref.rs +++ b/src/fetch/entity_ref.rs @@ -59,33 +59,30 @@ pub struct PreparedEntityRef<'a> { arch: &'a Archetype, } +#[doc(hidden)] pub struct Batch<'a> { pub(crate) world: &'a World, pub(crate) arch: &'a Archetype, - pub(crate) slot: Slot, } impl<'w, 'q> PreparedFetch<'q> for PreparedEntityRef<'w> { type Item = EntityRef<'q>; type Chunk = Batch<'q>; - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { + unsafe fn create_chunk(&'q mut self, _: crate::archetype::Slice) -> Self::Chunk { Batch { world: self.world, arch: self.arch, - slot: slots.start, } } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - let slot = chunk.slot; - + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { EntityRef { arch: chunk.arch, world: chunk.world, slot, - id: chunk.arch.entities[slot], + id: *chunk.arch.entities.get_unchecked(slot), } } } diff --git a/src/fetch/map.rs b/src/fetch/map.rs index 56ed3e73..20da4a5f 100644 --- a/src/fetch/map.rs +++ b/src/fetch/map.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; -use crate::{Fetch, FetchItem}; +use crate::{archetype::Slot, Fetch, FetchItem}; use super::{FmtQuery, PreparedFetch}; @@ -69,8 +69,8 @@ where (self.func, self.query.create_chunk(slots)) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - (chunk.0)(Q::fetch_next(&mut chunk.1)) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + (chunk.0)(Q::fetch_next(&mut chunk.1, slot)) } unsafe fn filter_slots(&mut self, slots: crate::archetype::Slice) -> crate::archetype::Slice { diff --git a/src/fetch/maybe_mut.rs b/src/fetch/maybe_mut.rs index 2c01c9c6..80a09a46 100644 --- a/src/fetch/maybe_mut.rs +++ b/src/fetch/maybe_mut.rs @@ -91,30 +91,26 @@ pub struct Batch<'a> { cell: &'a Cell, new_tick: u32, ids: &'a [Entity], - slot: Slot, } impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedMaybeMut<'w, T> { type Item = MutGuard<'q, T>; type Chunk = Batch<'q>; - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { + unsafe fn create_chunk(&'q mut self, _: crate::archetype::Slice) -> Self::Chunk { Batch { cell: self.cell, new_tick: self.new_tick, ids: self.entities, - slot: slots.start, } } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - let slot = chunk.slot; - chunk.slot += 1; + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { MutGuard { slot, cell: chunk.cell, new_tick: chunk.new_tick, - id: chunk.ids[slot], + id: *chunk.ids.get_unchecked(slot), _marker: PhantomData, } } diff --git a/src/fetch/mod.rs b/src/fetch/mod.rs index 9d7b888c..0fb823f7 100644 --- a/src/fetch/mod.rs +++ b/src/fetch/mod.rs @@ -18,11 +18,12 @@ use crate::{ archetype::{Archetype, Slice, Slot}, filter::RefFetch, system::Access, + util::Ptr, ArchetypeId, ArchetypeSearcher, Entity, World, }; use alloc::vec::Vec; +use core::fmt::Debug; use core::fmt::{self, Formatter}; -use core::{fmt::Debug, slice}; pub use as_deref::*; pub use cloned::*; @@ -131,8 +132,14 @@ pub trait Fetch<'w>: for<'q> FetchItem<'q> { pub trait PreparedFetch<'q> { /// Item returned by fetch type Item: 'q; + /// A chunk accessing a disjoint set of the borrow sequentially type Chunk: 'q; + /// Creates a chunk to access a slice of the borrow + /// + /// # Safety + /// + /// `slots` must be disjoint to all other currently existing chunks unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk; /// Fetch the item from entity at the slot in the prepared storage. @@ -141,7 +148,8 @@ pub trait PreparedFetch<'q> { /// prepared archetype. /// /// The callee is responsible for assuring disjoint calls. - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item; + /// Repeated calls must use increasing adjacent values for `slot` + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item; #[inline] /// Filter the slots to visit @@ -174,8 +182,8 @@ where (*self).create_chunk(slots) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - F::fetch_next(chunk) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + F::fetch_next(chunk, slot) } unsafe fn filter_slots(&mut self, slots: Slice) -> Slice { @@ -230,7 +238,7 @@ impl<'q> PreparedFetch<'q> for () { unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } // impl<'q, F> PreparedFetch<'q> for Option @@ -296,14 +304,16 @@ impl<'w> Fetch<'w> for EntityIds { impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> { type Item = Entity; - type Chunk = slice::Iter<'q, Entity>; + type Chunk = Ptr<'q, Entity>; unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { - self.entities[slots.as_range()].iter() + Ptr::new(self.entities[slots.as_range()].as_ptr()) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - *chunk.next().unwrap() + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { + let old = chunk.as_ptr(); + *chunk = chunk.add(1); + *old } } @@ -312,8 +322,9 @@ impl<'w, 'q> ReadOnlyFetch<'q> for ReadEntities<'w> { unsafe fn fetch_shared(&self, slot: usize) -> Self::Item { self.entities[slot] } + unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { - chunk.as_slice()[slot] + *chunk.add(slot).as_ref() } } @@ -355,9 +366,9 @@ macro_rules! tuple_impl { type Chunk = ($($ty::Chunk,)*); #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { ($( - $ty::fetch_next(&mut chunk.$idx), + $ty::fetch_next(&mut chunk.$idx, slot), )*) } diff --git a/src/fetch/opt.rs b/src/fetch/opt.rs index 82523dfb..8bfe95c1 100644 --- a/src/fetch/opt.rs +++ b/src/fetch/opt.rs @@ -83,8 +83,8 @@ where self.0.as_mut().map(|v| v.create_chunk(slots)) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - chunk.as_mut().map(|v| F::fetch_next(v)) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + chunk.as_mut().map(|v| F::fetch_next(v, slot)) } } @@ -163,9 +163,9 @@ where } } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { match chunk { - Either::Left(v) => F::fetch_next(v), + Either::Left(v) => F::fetch_next(v, slot), Either::Right(v) => v, } } diff --git a/src/fetch/read_only.rs b/src/fetch/read_only.rs index e917745d..f04ae0fe 100644 --- a/src/fetch/read_only.rs +++ b/src/fetch/read_only.rs @@ -11,5 +11,8 @@ pub trait ReadOnlyFetch<'q>: PreparedFetch<'q> { /// # Safety /// Slot must be valid unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item; + /// Use an existing chunk to access an arbitrary slot + /// # Safety + /// Slot must be valid unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item; } diff --git a/src/fetch/relations.rs b/src/fetch/relations.rs index ae03d6e1..af356bb4 100644 --- a/src/fetch/relations.rs +++ b/src/fetch/relations.rs @@ -77,7 +77,6 @@ pub struct PreparedRelations<'a, T> { pub struct Batch<'a, T> { borrows: &'a [(Entity, CellGuard<'a, [T]>)], - slot: Slot, } impl<'w, 'q, T> PreparedFetch<'q> for PreparedRelations<'w, T> @@ -88,17 +87,13 @@ where type Chunk = Batch<'q, T>; - unsafe fn create_chunk(&'q mut self, slots: crate::archetype::Slice) -> Self::Chunk { + unsafe fn create_chunk(&'q mut self, _: crate::archetype::Slice) -> Self::Chunk { Batch { borrows: &self.borrows, - slot: slots.start, } } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - let slot = chunk.slot; - chunk.slot += 1; - + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { RelationsIter { borrows: chunk.borrows.iter(), slot, diff --git a/src/fetch/satisfied.rs b/src/fetch/satisfied.rs index 9ef6b3fb..3bbdd22f 100644 --- a/src/fetch/satisfied.rs +++ b/src/fetch/satisfied.rs @@ -1,6 +1,9 @@ use alloc::vec::Vec; -use crate::{archetype::Slice, Fetch, FetchItem}; +use crate::{ + archetype::{Slice, Slot}, + Fetch, FetchItem, +}; use super::{FmtQuery, PreparedFetch}; @@ -52,7 +55,7 @@ impl<'q, F: PreparedFetch<'q>> PreparedFetch<'q> for PreparedSatisfied { } } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { *chunk } diff --git a/src/fetch/source.rs b/src/fetch/source.rs index 39cb04a6..49318435 100644 --- a/src/fetch/source.rs +++ b/src/fetch/source.rs @@ -171,7 +171,7 @@ where self.fetch.create_chunk(Slice::single(self.slot)) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { Q::fetch_shared_chunk(chunk, 0) } } diff --git a/src/filter/change.rs b/src/filter/change.rs index 5aef1280..01a911da 100644 --- a/src/filter/change.rs +++ b/src/filter/change.rs @@ -1,11 +1,11 @@ use alloc::vec::Vec; use core::fmt::Formatter; -use core::slice; use itertools::Itertools; use crate::archetype::{Archetype, CellGuard, Change, Slot}; use crate::fetch::{FetchAccessData, FetchPrepareData, PreparedFetch, ReadOnlyFetch}; use crate::system::{Access, AccessKind}; +use crate::util::Ptr; use crate::{ archetype::{ChangeKind, ChangeList, Slice}, Component, ComponentValue, Fetch, FetchItem, @@ -50,7 +50,7 @@ impl<'w, 'q, T: ComponentValue> ReadOnlyFetch<'q> for PreparedChangeFilter<'w, T #[inline] unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item { - chunk.as_slice().get_unchecked(slot) + chunk.add(slot).as_ref() } } @@ -168,11 +168,17 @@ impl<'w, T> core::fmt::Debug for PreparedChangeFilter<'w, T> { impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T> { type Item = &'q T; - type Chunk = slice::Iter<'q, T>; + type Chunk = Ptr<'q, T>; + + unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { + Ptr::new(self.data.get()[slots.as_range()].as_ptr()) + } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - chunk.next().unwrap() + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { + let old = chunk.as_ptr(); + chunk.advance(1); + &*old } #[inline] @@ -188,10 +194,6 @@ impl<'w, 'q, T: ComponentValue> PreparedFetch<'q> for PreparedChangeFilter<'w, T cur.intersect(&slots) .unwrap_or(Slice::new(slots.end, slots.end)) } - - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { - self.data.get()[slots.as_range()].iter() - } } #[derive(Clone)] @@ -283,7 +285,7 @@ impl<'q, 'w> ReadOnlyFetch<'q> for PreparedRemoveFilter<'w> { unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {} #[inline] - unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {} + unsafe fn fetch_shared_chunk(_: &Self::Chunk, _: Slot) -> Self::Item {} } impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { @@ -301,9 +303,11 @@ impl<'w, 'q> PreparedFetch<'q> for PreparedRemoveFilter<'w> { .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} + #[inline] + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } #[cfg(test)] diff --git a/src/filter/cmp.rs b/src/filter/cmp.rs index b88e42de..b9ddbc60 100644 --- a/src/filter/cmp.rs +++ b/src/filter/cmp.rs @@ -213,8 +213,8 @@ where } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - Q::fetch_next(chunk) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + Q::fetch_next(chunk, slot) } } diff --git a/src/filter/constant.rs b/src/filter/constant.rs index e1dc3cf0..5482275a 100644 --- a/src/filter/constant.rs +++ b/src/filter/constant.rs @@ -1,5 +1,5 @@ use crate::{ - archetype::{Archetype, Slice}, + archetype::{Archetype, Slice, Slot}, fetch::{FetchAccessData, FetchPrepareData, PreparedFetch}, system::Access, Fetch, FetchItem, @@ -45,10 +45,11 @@ impl<'q> PreparedFetch<'q> for Nothing { Slice::new(slots.end, slots.end) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } /// Yields all entities @@ -84,10 +85,11 @@ impl<'q> PreparedFetch<'q> for All { type Chunk = (); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } impl<'q> FetchItem<'q> for Slice { @@ -125,12 +127,14 @@ impl<'q> PreparedFetch<'q> for Slice { .unwrap_or(Slice::new(slots.end, slots.end)) } - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} + #[inline] + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } -impl<'w, 'q> FetchItem<'q> for bool { +impl<'q> FetchItem<'q> for bool { type Item = bool; } @@ -162,12 +166,13 @@ impl<'q> PreparedFetch<'q> for bool { type Chunk = bool; - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk { + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk { *self } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { + unsafe fn fetch_next(chunk: &mut Self::Chunk, _: Slot) -> Self::Item { *chunk } } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index a992042f..b92ab501 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -152,8 +152,8 @@ where self.fetch.create_chunk(slots) } - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - Q::fetch_next(chunk) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + Q::fetch_next(chunk, slot) } } @@ -550,7 +550,7 @@ impl<'q> PreparedFetch<'q> for BatchSize { unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} #[inline] - unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } impl<'q> FetchItem<'q> for BatchSize { diff --git a/src/filter/set.rs b/src/filter/set.rs index 0afb9856..a4b086f5 100644 --- a/src/filter/set.rs +++ b/src/filter/set.rs @@ -1,6 +1,6 @@ use crate::{ - archetype::{Archetype, Slice}, - fetch::{FetchAccessData, FetchPrepareData, FmtQuery, Opt, PreparedFetch, UnionFilter}, + archetype::{Archetype, Slice, Slot}, + fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, UnionFilter}, system::Access, Fetch, FetchItem, }; @@ -85,8 +85,11 @@ where } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - (L::fetch_next(&mut chunk.0), R::fetch_next(&mut chunk.1)) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + ( + L::fetch_next(&mut chunk.0, slot), + R::fetch_next(&mut chunk.1, slot), + ) } } @@ -148,9 +151,11 @@ where type Chunk = (); - unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {} + #[inline] + unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {} - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {} + #[inline] + unsafe fn fetch_next(_: &mut Self::Chunk, _: Slot) -> Self::Item {} } impl ops::BitOr for Not { @@ -252,8 +257,8 @@ where } #[inline] - unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item { - T::fetch_next(chunk) + unsafe fn fetch_next(chunk: &mut Self::Chunk, slot: Slot) -> Self::Item { + T::fetch_next(chunk, slot) } } @@ -315,7 +320,7 @@ macro_rules! tuple_impl { } #[inline] - unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {} + unsafe fn fetch_next(_: &mut Self::Chunk, _:Slot) -> Self::Item {} #[inline] unsafe fn create_chunk(&mut self, _: Slice) -> Self::Chunk {} diff --git a/src/query/borrow.rs b/src/query/borrow.rs index f5921b53..8319e1e2 100644 --- a/src/query/borrow.rs +++ b/src/query/borrow.rs @@ -15,7 +15,7 @@ pub(crate) struct PreparedArchetype<'w, Q, F> { impl<'w, Q, F> PreparedArchetype<'w, Q, F> { #[inline] - pub fn create_chunk<'q>(&'q mut self, slots: Slice) -> Option> + pub unsafe fn create_chunk<'q>(&'q mut self, slots: Slice) -> Option> where Q: PreparedFetch<'q>, F: PreparedFetch<'q>, @@ -28,10 +28,10 @@ impl<'w, Q, F> PreparedArchetype<'w, Q, F> { // Fetch will never change and all calls are disjoint let fetch = unsafe { &mut *(&mut self.fetch as *mut Filtered) }; - let batch = unsafe { fetch.create_chunk(slots) }; + let chunk = unsafe { fetch.create_chunk(slots) }; - let batch = Chunk::new(self.arch, batch, slots); - Some(batch) + let chunk = Chunk::new(self.arch, chunk, slots); + Some(chunk) } #[inline] diff --git a/src/query/dfs.rs b/src/query/dfs.rs index c4e24cf5..276a7276 100644 --- a/src/query/dfs.rs +++ b/src/query/dfs.rs @@ -222,10 +222,10 @@ where let prepared = (&mut self.prepared[..]) as *mut [_] as *mut PreparedArchetype<_, _>; let arch_index = *dfs.state.archetypes_index.get(&loc.arch_id).unwrap(); - // Fetch will never change and all calls are disjoint + // Fetch will never change and all calls are disjoint as the graph is acyclic let p = unsafe { &mut *prepared.add(arch_index) }; - if let Some(mut chunk) = p.create_chunk(Slice::single(loc.slot)) { + if let Some(mut chunk) = unsafe { p.create_chunk(Slice::single(loc.slot)) } { Self::traverse_batch( self.query_state.world, dfs, diff --git a/src/query/entity.rs b/src/query/entity.rs index 2f818112..cd80ac66 100644 --- a/src/query/entity.rs +++ b/src/query/entity.rs @@ -115,8 +115,8 @@ where Ok((loc, p)) => { // self is a mutable reference, so this is the only reference to the slot unsafe { - let mut batch = p.fetch.create_chunk(Slice::single(loc.slot)); - Ok(::fetch_next(&mut batch)) + let mut chunk = p.fetch.create_chunk(Slice::single(loc.slot)); + Ok(::fetch_next(&mut chunk, loc.slot)) } } Err(e) => Err(e.clone()), diff --git a/src/query/iter.rs b/src/query/iter.rs index 73326901..676125bb 100644 --- a/src/query/iter.rs +++ b/src/query/iter.rs @@ -66,7 +66,7 @@ where None } else { // let fetch = unsafe { &mut *(self.fetch as *mut Q::Batch) }; - let item = unsafe { Q::fetch_next(&mut self.fetch) }; + let item = unsafe { Q::fetch_next(&mut self.fetch, self.pos) }; self.pos += 1; Some(item) } @@ -81,7 +81,7 @@ where if self.pos == self.end { None } else { - let item = unsafe { Q::fetch_next(&mut self.fetch) }; + let item = unsafe { Q::fetch_next(&mut self.fetch, self.pos) }; let id = self.arch.entities[self.pos]; self.pos += 1; Some((id, item)) @@ -93,7 +93,7 @@ where None } else { let slot = self.pos; - let item = unsafe { Q::fetch_next(&mut self.fetch) }; + let item = unsafe { Q::fetch_next(&mut self.fetch, slot) }; let id = self.arch.entities[slot]; self.pos += 1; @@ -114,38 +114,6 @@ pub struct ArchetypeChunks<'q, Q, F> { unsafe impl<'q, Q: 'q, F: 'q> Sync for ArchetypeChunks<'q, Q, F> where &'q mut Filtered: Sync {} unsafe impl<'q, Q: 'q, F: 'q> Send for ArchetypeChunks<'q, Q, F> where &'q mut Filtered: Send {} -impl<'q, Q, F> ArchetypeChunks<'q, Q, F> -where - Q: PreparedFetch<'q>, - F: PreparedFetch<'q>, -{ - fn next_slice(slots: &mut Slice, fetch: &mut Filtered) -> Option { - if slots.is_empty() { - return None; - } - - while !slots.is_empty() { - // Safety - // The yielded slots are split off of `self.slots` - let cur = unsafe { fetch.filter_slots(*slots) }; - - let (_l, m, r) = slots - .split_with(&cur) - .expect("Return value of filter must be a subset of `slots"); - - assert_eq!(cur, m); - - *slots = r; - - if !m.is_empty() { - return Some(m); - } - } - - None - } -} - impl<'q, Q, F> Iterator for ArchetypeChunks<'q, Q, F> where Q: 'q + PreparedFetch<'q>, @@ -161,10 +129,10 @@ where // Get the next chunk let slots = next_slice(&mut self.slots, fetch)?; - // Disjoing chunk - let batch = unsafe { fetch.create_chunk(slots) }; - let batch = Chunk::new(self.arch, batch, slots); + // Safety: Disjoint chunk + let chunk = unsafe { fetch.create_chunk(slots) }; + let chunk = Chunk::new(self.arch, chunk, slots); - Some(batch) + Some(chunk) } } diff --git a/src/query/planar.rs b/src/query/planar.rs index b4dbd4c6..438c20e7 100644 --- a/src/query/planar.rs +++ b/src/query/planar.rs @@ -287,9 +287,11 @@ where // Since `self` is a mutable references the borrow checker // guarantees this borrow is unique let p = &mut self.prepared[idx]; - let mut chunk = p - .create_chunk(Slice::single(slot)) - .ok_or(Error::Filtered(id))?; + // Safety: &mut self + let mut chunk = unsafe { + p.create_chunk(Slice::single(slot)) + .ok_or(Error::Filtered(id))? + }; let item = chunk.next().unwrap(); diff --git a/src/query/walk.rs b/src/query/walk.rs index 78b2ffd4..e0041a40 100644 --- a/src/query/walk.rs +++ b/src/query/walk.rs @@ -242,7 +242,8 @@ where let p = &mut borrow.prepared[index]; - p.create_chunk(Slice::single(self.slot))?.next() + // Safety: &mut borrow + unsafe { p.create_chunk(Slice::single(self.slot))? }.next() } /// Traverse the immediate children of the current node. diff --git a/src/schedule/mod.rs b/src/schedule/mod.rs index 0168f495..c66afd24 100644 --- a/src/schedule/mod.rs +++ b/src/schedule/mod.rs @@ -210,7 +210,7 @@ impl Schedule { } /// Returns information about the current multithreaded batch partioning and system accesses. - pub fn batch_info(&mut self, world: &mut World) -> BatchInfos { + pub fn batch_info(&mut self, world: &World) -> BatchInfos { self.systems = Self::build_dependencies(mem::take(&mut self.systems), world); let batches = self @@ -294,7 +294,7 @@ impl Schedule { fn build_dependencies( systems: Vec>>, - world: &mut World, + world: &World, ) -> Vec>> { let accesses = systems .iter() diff --git a/src/system/mod.rs b/src/system/mod.rs index 66caff4f..fba75ab1 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -2,8 +2,8 @@ mod context; mod traits; use crate::{ - archetype::ArchetypeInfo, fetch::PreparedFetch, filter::Filtered, query::QueryData, - util::TupleCombine, ArchetypeId, CommandBuffer, ComponentKey, Fetch, FetchItem, Query, World, + archetype::ArchetypeInfo, query::QueryData, util::TupleCombine, ArchetypeId, CommandBuffer, + ComponentKey, Fetch, FetchItem, Query, World, }; use alloc::{ boxed::Box, @@ -77,8 +77,8 @@ impl<'a, Func, Q, F> SystemFn<'a, (QueryData<'a, Q, F>,), ()> for ParForEach Q: Fetch<'x>, for<'x> F: Fetch<'x>, - for<'x> as Fetch<'x>>::Prepared: Send, - for<'x, 'y> <>::Prepared as PreparedFetch<'y>>::Chunk: Send, + for<'x> as Fetch<'x>>::Prepared: Send, + for<'x, 'y> <>::Prepared as crate::fetch::PreparedFetch<'y>>::Chunk: Send, for<'x> Func: Fn(>::Item) + Send + Sync, { fn execute(&mut self, mut data: (QueryData,)) { @@ -113,7 +113,7 @@ impl SystemBuilder<(Query,), T> where for<'x> Q: 'static + Fetch<'x> + Send, for<'x> F: 'static + Fetch<'x> + Send, - for<'x> <>::Prepared as PreparedFetch<'x>>::Chunk: Send, + for<'x> <>::Prepared as crate::fetch::PreparedFetch<'x>>::Chunk: Send, // for<'x, 'y> crate::query::Batch<'y, >::Prepared>: Send, { /// Execute a function for each item in the query in parallel batches diff --git a/src/util/mod.rs b/src/util/mod.rs index 6a214a48..08a99df2 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,6 +1,8 @@ // Needed in macro expansion #![allow(unused_parens)] +use core::marker::PhantomData; + use crate::filter::All; /// Allows pushing onto a tuple @@ -92,3 +94,89 @@ impl TupleCombine for All { (value, self) } } + +#[doc(hidden)] +/// A lifetime annotated covariant pointer +pub struct Ptr<'a, T> { + ptr: *const T, + _marker: PhantomData<&'a T>, +} + +impl<'a, T> Ptr<'a, T> { + #[inline] + pub fn new(ptr: *const T) -> Self { + Self { + ptr, + _marker: PhantomData, + } + } + + #[inline] + pub unsafe fn add(&self, count: usize) -> Self { + Self { + ptr: self.ptr.add(count), + _marker: PhantomData, + } + } + + #[inline] + pub unsafe fn advance(&mut self, count: usize) { + self.ptr = self.ptr.add(count); + } + + #[inline] + pub unsafe fn as_ref(&self) -> &'a T { + &*self.ptr + } + + #[inline] + pub fn as_ptr(&self) -> *const T { + self.ptr + } +} + +unsafe impl Sync for Ptr<'_, T> {} +unsafe impl Send for Ptr<'_, T> {} + +#[doc(hidden)] +/// A lifetime annotated invariant mutable pointer +pub struct PtrMut<'a, T> { + ptr: *mut T, + _marker: PhantomData<&'a mut T>, +} + +impl<'a, T> PtrMut<'a, T> { + #[inline] + pub fn new(ptr: *mut T) -> Self { + Self { + ptr, + _marker: PhantomData, + } + } + + #[inline] + pub unsafe fn add(&self, count: usize) -> Self { + Self { + ptr: self.ptr.add(count), + _marker: PhantomData, + } + } + + #[inline] + pub unsafe fn advance(&mut self, count: usize) { + self.ptr = self.ptr.add(count); + } + + #[inline] + pub unsafe fn as_mut(&'a mut self) -> &'a mut T { + &mut *self.ptr + } + + #[inline] + pub fn as_ptr(&self) -> *mut T { + self.ptr + } +} + +unsafe impl Sync for PtrMut<'_, T> {} +unsafe impl Send for PtrMut<'_, T> {} diff --git a/tests/access.rs b/tests/access.rs index a6aeca86..f15440d0 100644 --- a/tests/access.rs +++ b/tests/access.rs @@ -100,7 +100,7 @@ fn access() { ]); assert_eq!( - schedule.batch_info(&mut world).to_names(), + schedule.batch_info(&world).to_names(), [ vec!["regen_system", "weapons", "names"], vec!["blue_system", "red_system"], @@ -111,7 +111,7 @@ fn access() { world.set(spectator, blue_team(), ()).unwrap(); assert_eq!( - schedule.batch_info(&mut world).to_names(), + schedule.batch_info(&world).to_names(), [ vec!["regen_system", "weapons", "names"], vec!["blue_system", "red_system"], @@ -123,7 +123,7 @@ fn access() { world.set(spectator, red_team(), ()).unwrap(); assert_eq!( - schedule.batch_info(&mut world).to_names(), + schedule.batch_info(&world).to_names(), [ vec!["regen_system", "weapons", "names"], vec!["blue_system"], @@ -135,7 +135,7 @@ fn access() { world.remove(spectator, weapon()).unwrap(); assert_eq!( - schedule.batch_info(&mut world).to_names(), + schedule.batch_info(&world).to_names(), [ vec!["regen_system", "weapons", "names"], vec!["blue_system", "red_system"], diff --git a/tests/entity.rs b/tests/entity.rs index 9d39a996..9eca7146 100644 --- a/tests/entity.rs +++ b/tests/entity.rs @@ -8,11 +8,7 @@ component! { #[test] #[cfg(feature = "flume")] fn entity_ref() { - use flax::{ - entity_ids, - events::{Event, EventKind, EventSubscriber}, - Query, - }; + use flax::{entity_ids, Query}; use itertools::Itertools; use pretty_assertions::assert_eq; diff --git a/tests/filter.rs b/tests/filter.rs index f987fc61..32ac5335 100644 --- a/tests/filter.rs +++ b/tests/filter.rs @@ -263,7 +263,7 @@ fn sparse_or() { .boxed(); let mut schedule = Schedule::from([system_a, system_b]); - let batches = schedule.batch_info(&mut world); + let batches = schedule.batch_info(&world); assert_eq!(batches.len(), 2); } @@ -326,6 +326,6 @@ fn sparse_and() { .boxed(); let mut schedule = Schedule::from([system_a, system_b]); - let batches = schedule.batch_info(&mut world); + let batches = schedule.batch_info(&world); assert_eq!(batches.len(), 1); } diff --git a/tests/schedule.rs b/tests/schedule.rs index 45b4ca58..ba69842c 100644 --- a/tests/schedule.rs +++ b/tests/schedule.rs @@ -71,7 +71,7 @@ fn schedule_granularity() { .with_system(ce_system()) .build(); - let batches = schedule.batch_info(&mut world); + let batches = schedule.batch_info(&world); assert_eq!(batches.len(), 1); @@ -83,7 +83,7 @@ fn schedule_granularity() { batch.set(e(), repeat(0.0)).unwrap(); batch.spawn(&mut world); - let batches = schedule.batch_info(&mut world); + let batches = schedule.batch_info(&world); let names = batches.to_names(); assert_eq!(batches.len(), 2, "{names:#?}");