cecs/
query_set.rs

1#[cfg(test)]
2mod test;
3
4use std::{any::TypeId, collections::HashSet, marker::PhantomData};
5
6use crate::{
7    prelude::{Filter, Query},
8    query::{QueryFragment, WorldQuery},
9};
10
11/// A QuerySet can be used when a system needs multiple, coupled queries.
12///
13/// ## Limitations
14///
15/// Currently if a sub-query needs mutable access to a component, then all sub-queries to the same
16/// component must also be mutable.
17///
18/// The way we implement fetch can actually break Rust's aliasing semantics. The programmer must
19/// ensure that using different queries does not result in mutable aliasing (fetching the same
20/// component on the same entity twice at the same time).
21///
22/// ```
23/// use cecs::prelude::*;
24/// #[derive(Default, Clone)]
25/// struct Foo {
26///     value: i32,
27/// }
28///
29/// #[derive(Default, Clone)]
30/// struct Bar;
31///
32/// fn sys<'a>(
33///     mut q: QuerySet<(
34///         Query<'a, (&'a mut Foo, &'a Bar)>,
35///         Query<'a, &'a mut Foo>,
36///     )>,
37/// ) {
38///     for foo in q.q1_mut().iter_mut() {
39///         assert_eq!(foo.value, 0);
40///         foo.value = 42;
41///     }
42///
43///     // notice how foo is not changed in this loop, but q0 still has to request mutable access
44///     for (foo, _bar) in q.q0().iter() {
45///         assert_eq!(foo.value, 42);
46///     }
47/// }
48/// let mut world = World::new(4);
49/// world.run_system(sys).unwrap();
50/// ```
51pub struct QuerySet<Inner> {
52    world: std::ptr::NonNull<crate::World>,
53    _m: PhantomData<Inner>,
54}
55
56unsafe impl<T> Send for QuerySet<T> {}
57unsafe impl<T> Sync for QuerySet<T> {}
58
59macro_rules! impl_tuple {
60    ($($idx: tt , $t: ident , $f: ident , $q: ident , $q_mut: ident , $set: ident);+ $(;)?) => {
61        impl<'a, $($t, $f),*> QuerySet<($(Query<'a, $t, $f>),*)>
62        where
63            $(
64            $t: QueryFragment,
65            $f: Filter,
66            )*
67        {
68            $(
69                pub fn $q<'b>(&'b self) -> Query<'b, $t, $f>
70                    where 'a: 'b
71                {
72                    unsafe {Query::new(self.world.as_ref())}
73                }
74
75                pub fn $q_mut<'b>(&'b mut self) -> Query<'b, $t, $f>
76                    where 'a: 'b
77                {
78                    unsafe {Query::new(self.world.as_ref())}
79                }
80            )*
81        }
82
83        unsafe impl<'a, $($t, $f),*> WorldQuery<'a> for QuerySet<($(Query<'a, $t, $f>),*)>
84        where
85            $(
86            $t: QueryFragment,
87            $f: Filter,
88            )*
89        {
90            fn new(db: &'a crate::World, _system_idx: usize) -> Self {
91                Self {
92                    world: std::ptr::NonNull::from(db),
93                    _m: PhantomData,
94                }
95            }
96
97            fn exclusive() -> bool {false}
98
99            fn read_only() -> bool {
100                true
101                $(
102                    &&
103                    <$t as QueryFragment>::read_only()
104                )*
105            }
106
107            fn components_mut(set: &mut HashSet<TypeId>) {
108                // sub queries may have overlapping type (that's the point of the QuerySet)
109                // types_mut will panic in this case, so we'll try all in isolation, then
110                // add the types to the output
111                $(
112                    let mut $set = set.clone();
113                    <$t as QueryFragment>::types_mut(&mut $set);
114                )*
115
116                $(
117                    set.extend($set.into_iter());
118                )*
119            }
120
121            fn components_const(set: &mut HashSet<TypeId>) {
122                $(
123                    <$t as QueryFragment>::types_const(set);
124                )*
125                // remove mutable components from the const compoennts
126                let mut mutable_components = HashSet::new();
127                let mut tmp = HashSet::new();
128                $(
129                    tmp.clear();
130                    // types_mut may check the set for duplicate components, so always pass an
131                    // empty set here
132                    <$t as QueryFragment>::types_mut(&mut tmp);
133                    mutable_components.extend(tmp.drain());
134                )*
135                set.retain(|t| !mutable_components.contains(t));
136            }
137        }
138    };
139}
140
141impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1;);
142impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2;);
143impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3;);
144impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3; 4 , T4 , F4 , q4 , q4_mut , set4;);
145impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3; 4 , T4 , F4 , q4 , q4_mut , set4; 5 , T5 , F5 , q5 , q5_mut , set5;);
146impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3; 4 , T4 , F4 , q4 , q4_mut , set4; 5 , T5 , F5 , q5 , q5_mut , set5; 6 , T6 , F6 , q6 , q6_mut , set6;);
147impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3; 4 , T4 , F4 , q4 , q4_mut , set4; 5 , T5 , F5 , q5 , q5_mut , set5; 6 , T6 , F6 , q6 , q6_mut , set6; 7 , T7 , F7 , q7 , q7_mut , set7;);
148impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3; 4 , T4 , F4 , q4 , q4_mut , set4; 5 , T5 , F5 , q5 , q5_mut , set5; 6 , T6 , F6 , q6 , q6_mut , set6; 7 , T7 , F7 , q7 , q7_mut , set7; 8 , T8 , F8 , q8 , q8_mut , set8;);
149impl_tuple!(0 , T0 , F0 , q0 , q0_mut , set0; 1 , T1 , F1 , q1 , q1_mut , set1; 2 , T2 , F2 , q2 , q2_mut , set2; 3 , T3 , F3 , q3 , q3_mut , set3; 4 , T4 , F4 , q4 , q4_mut , set4; 5 , T5 , F5 , q5 , q5_mut , set5; 6 , T6 , F6 , q6 , q6_mut , set6; 7 , T7 , F7 , q7 , q7_mut , set7; 8 , T8 , F8 , q8 , q8_mut , set8; 9 , T9 , F9 , q9 , q9_mut , set9;);