use crate::{
archetype::ChangeKind,
component::ComponentValue,
filter::{ChangeFilter, Filtered, NoEntities, Union},
Component, EntityIds, FetchExt, Mutable,
};
pub trait TransformFetch<Method> {
type Output;
fn transform_fetch(self, method: Method) -> Self::Output;
}
impl<T: ComponentValue> TransformFetch<Modified> for Component<T> {
type Output = ChangeFilter<T>;
fn transform_fetch(self, _: Modified) -> Self::Output {
self.into_change_filter(ChangeKind::Modified)
}
}
impl<T: ComponentValue> TransformFetch<Added> for Component<T> {
type Output = ChangeFilter<T>;
fn transform_fetch(self, _: Added) -> Self::Output {
self.into_change_filter(ChangeKind::Added)
}
}
impl<T: ComponentValue> TransformFetch<Modified> for Mutable<T> {
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Modified) -> Self::Output {
self.filtered(NoEntities)
}
}
impl<T: ComponentValue> TransformFetch<Added> for Mutable<T> {
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Added) -> Self::Output {
self.filtered(NoEntities)
}
}
impl TransformFetch<Modified> for EntityIds {
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Modified) -> Self::Output {
self.filtered(NoEntities)
}
}
impl TransformFetch<Added> for EntityIds {
type Output = Filtered<Self, NoEntities>;
fn transform_fetch(self, _: Added) -> Self::Output {
self.filtered(NoEntities)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Modified;
#[derive(Debug, Clone, Copy)]
pub struct Added;
macro_rules! tuple_impl {
($($idx: tt => $ty: ident),*) => {
impl<$($ty: TransformFetch<Modified>,)*> TransformFetch<Modified> for ($($ty,)*) {
type Output = Union<($($ty::Output,)*)>;
fn transform_fetch(self, method: Modified) -> Self::Output {
Union(($(self.$idx.transform_fetch(method),)*))
}
}
impl<$($ty: TransformFetch<Added>,)*> TransformFetch<Added> for ($($ty,)*) {
type Output = Union<($($ty::Output,)*)>;
fn transform_fetch(self, method: Added) -> Self::Output {
Union(($(self.$idx.transform_fetch(method),)*))
}
}
};
}
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 {
use alloc::string::{String, ToString};
use itertools::Itertools;
use crate::{component, entity_ids, CommandBuffer, Entity, FetchExt, Query, World};
#[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(b(), "There".into())
.spawn(&mut world);
let id4 = Entity::builder()
.set(a(), 2)
.set(b(), "!".into())
.tag(other())
.spawn(&mut world);
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(), None)),
(id2, (&1, &"World".to_string(), None)),
(id4, (&2, &"!".to_string(), Some(&mut ())))
]
);
assert_eq!(query.borrow(&world).iter().collect_vec(), []);
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(), None))]
);
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(), None))]
);
cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap();
assert_eq!(
query.borrow(&world).iter().collect_vec(),
[(id3, (&-1, &":P".to_string(), None))]
);
}
#[test]
#[cfg(feature = "derive")]
fn query_modified_struct() {
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(b(), "There".into())
.set_default(c())
.spawn(&mut world);
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));
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!(*world.get_mut(id2, a()).unwrap(), 1);
assert_eq!(query.collect_vec(&world), []);
*world.get_mut(id2, a()).unwrap() = 5;
assert_eq!(query.collect_vec(&world), [(id2, (5, "World".to_string()))]);
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()))]
);
cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap();
assert_eq!(query.collect_vec(&world), [(id3, (-1, ":P".to_string()))]);
}
#[test]
#[cfg(feature = "derive")]
fn query_inserted_struct() {
use crate::{fetch::Cloned, Component, EntityIds, Fetch, Mutable};
#[derive(Debug)]
struct Custom;
component! {
a: i32,
b: String,
c: Custom,
other: (),
}
#[derive(Fetch)]
#[fetch(item_derives = [Debug], transforms = [Modified, Added])]
struct MyFetch {
#[fetch(ignore)]
id: EntityIds,
a: Component<i32>,
b: Cloned<Component<String>>,
#[fetch(ignore)]
c: Mutable<Custom>,
}
let mut world = World::new();
let id1 = Entity::builder()
.set(a(), 0)
.set(b(), "Hello".into())
.set(c(), Custom)
.spawn(&mut world);
let id2 = Entity::builder()
.set(a(), 1)
.set(b(), "World".into())
.set(c(), Custom)
.spawn(&mut world);
let id3 = Entity::builder()
.set(b(), "There".into())
.set(c(), Custom)
.spawn(&mut world);
let id4 = Entity::builder()
.set(a(), 2)
.set(b(), "!".into())
.set(c(), Custom)
.tag(other())
.spawn(&mut world);
let query = MyFetch {
id: entity_ids(),
a: a(),
b: b().cloned(),
c: c().as_mut(),
}
.added()
.map(|v| (v.id, *v.a, v.b));
let mut query = Query::new(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())]);
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())]);
}
#[test]
#[cfg(feature = "derive")]
fn test_derive_parse() {
use crate::{fetch::Cloned, Component, Fetch};
#[derive(Fetch)]
struct MyFetch {
a: Component<i32>,
b: Cloned<Component<String>>,
}
}
}