Skip to content

Commit

Permalink
fix: filtering for mutable and optional queries
Browse files Browse the repository at this point in the history
  • Loading branch information
ten3roberts committed Mar 29, 2024
1 parent ab1dbb3 commit 60d3a9b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 20 deletions.
45 changes: 26 additions & 19 deletions src/fetch/transform.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use crate::{
archetype::ChangeKind,
component::ComponentValue,
filter::{ChangeFilter, Filtered, Nothing, Union},
filter::{ChangeFilter, Filtered, NoEntities, Union},
Component, EntityIds, FetchExt, Mutable,
};

use super::EntityRefs;

/// Allows transforming a fetch into another.
///
/// For example transforming a tuple or struct fetch into a modified filtering fetch.
Expand Down Expand Up @@ -35,30 +33,30 @@ impl<T: ComponentValue> TransformFetch<Added> for Component<T> {
}

impl<T: ComponentValue> TransformFetch<Modified> for Mutable<T> {
type Output = Filtered<Self, Nothing>;
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Modified) -> Self::Output {
self.filtered(Nothing)
self.filtered(NoEntities)
}
}

impl<T: ComponentValue> TransformFetch<Added> for Mutable<T> {
type Output = Filtered<Self, Nothing>;
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Added) -> Self::Output {
self.filtered(Nothing)
self.filtered(NoEntities)
}
}

impl TransformFetch<Modified> for EntityIds {
type Output = Filtered<Self, Nothing>;
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Modified) -> Self::Output {
self.filtered(Nothing)
self.filtered(NoEntities)
}
}

impl TransformFetch<Added> for EntityIds {
type Output = Filtered<Self, Nothing>;
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Added) -> Self::Output {
self.filtered(Nothing)
self.filtered(NoEntities)
}
}

Expand Down Expand Up @@ -136,14 +134,14 @@ mod tests {
.tag(other())
.spawn(&mut world);

let mut query = Query::new((entity_ids(), (a(), b()).modified()));
let mut query = Query::new((entity_ids(), (a(), b(), other().as_mut().opt()).modified()));

assert_eq!(
query.borrow(&world).iter().collect_vec(),
[
(id1, (&0, &"Hello".to_string())),
(id2, (&1, &"World".to_string())),
(id4, (&2, &"!".to_string()))
(id1, (&0, &"Hello".to_string(), None)),
(id2, (&1, &"World".to_string(), None)),
(id4, (&2, &"!".to_string(), Some(&mut ())))
]
);

Expand All @@ -158,7 +156,7 @@ mod tests {

assert_eq!(
query.borrow(&world).iter().collect_vec(),
[(id2, (&5, &"World".to_string()))]
[(id2, (&5, &"World".to_string(), None))]
);

// Adding the required component to id3 will cause it to be picked up by the query
Expand All @@ -167,62 +165,71 @@ mod tests {

assert_eq!(
query.borrow(&world).iter().collect_vec(),
[(id3, (&-1, &"There".to_string()))]
[(id3, (&-1, &"There".to_string(), None))]
);

cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap();

assert_eq!(
query.borrow(&world).iter().collect_vec(),
[(id3, (&-1, &":P".to_string()))]
[(id3, (&-1, &":P".to_string(), None))]
);
}

#[test]
#[cfg(feature = "derive")]
fn query_modified_struct() {
use crate::{fetch::Cloned, Component, Fetch};
use crate::{fetch::Cloned, Component, Fetch, Mutable, Opt};

component! {
a: i32,
b: String,
other: (),
c: f32,
}

#[derive(Fetch)]
#[fetch(item_derives = [Debug], transforms = [Modified])]
struct MyFetch {
a: Component<i32>,
b: Cloned<Component<String>>,
c: Mutable<f32>,
other: Opt<Mutable<()>>,
}

let mut world = World::new();

let id1 = Entity::builder()
.set(a(), 0)
.set(b(), "Hello".into())
.set_default(c())
.spawn(&mut world);

let id2 = Entity::builder()
.set(a(), 1)
.set(b(), "World".into())
.set_default(c())
.spawn(&mut world);

let id3 = Entity::builder()
// .set(a(), 0)
.set(b(), "There".into())
.set_default(c())
.spawn(&mut world);

// Force to a different archetype
let id4 = Entity::builder()
.set(a(), 2)
.set(b(), "!".into())
.set_default(c())
.tag(other())
.spawn(&mut world);

let query = MyFetch {
a: a(),
b: b().cloned(),
c: c().as_mut(),
other: other().as_mut().opt(),
}
.modified()
.map(|v| (*v.a, v.b));
Expand Down
54 changes: 53 additions & 1 deletion src/filter/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl<'a> Fetch<'a> for Nothing {

#[inline(always)]
fn prepare(&self, _: FetchPrepareData) -> Option<Self::Prepared> {
Some(Nothing)
unreachable!()
}

#[inline(always)]
Expand Down Expand Up @@ -109,6 +109,58 @@ impl<'q> PreparedFetch<'q> for All {
unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {}
}

#[doc(hidden)]
#[derive(Debug, Clone)]
/// A filter that yields archetypes but no entities
pub struct NoEntities;

impl<'q> FetchItem<'q> for NoEntities {
type Item = ();
}

impl<'a> Fetch<'a> for NoEntities {
const MUTABLE: bool = false;

type Prepared = NoEntities;

#[inline(always)]
fn prepare(&self, _: FetchPrepareData) -> Option<Self::Prepared> {
Some(NoEntities)
}

#[inline(always)]
fn filter_arch(&self, _: FetchAccessData) -> bool {
true
}

fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "false")
}

fn access(&self, _data: FetchAccessData, _dst: &mut Vec<Access>) {}
}

impl StaticFilter for NoEntities {
fn filter_static(&self, _: &crate::archetype::Archetype) -> bool {
false
}
}

impl<'q> PreparedFetch<'q> for NoEntities {
type Item = ();
type Chunk = ();

const HAS_FILTER: bool = true;
unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
Slice::new(slots.end, slots.end)
}

#[inline]
unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {}

#[inline]
unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {}
}
impl<'w> FetchItem<'w> for Entity {
type Item = Entity;
}
Expand Down
1 change: 1 addition & 0 deletions src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{

pub use change::ChangeFilter;
pub use cmp::{Cmp, Equal, Greater, GreaterEq, Less, LessEq};
pub(crate) use constant::NoEntities;
pub use constant::{All, Nothing};
pub use set::{And, Not, Or, Union};

Expand Down

0 comments on commit 60d3a9b

Please sign in to comment.