flax/filter/
set.rs

1use crate::{
2    archetype::{Archetype, Slice},
3    fetch::{FetchAccessData, FetchPrepareData, FmtQuery, PreparedFetch, UnionFilter},
4    filter::StaticFilter,
5    system::Access,
6    Fetch, FetchItem,
7};
8use alloc::vec::Vec;
9use core::{
10    fmt::{self, Formatter},
11    ops,
12};
13
14/// And combinator
15///
16/// **Note**: A normal tuple will and-combine and can thus be used instead.
17///
18/// The difference is that additional *bitops* such as `|` and `~` for convenience works on this type
19/// to combine it with other filters. This is because of orphan rules.
20#[derive(Debug, Clone)]
21pub struct And<L, R>(pub L, pub R);
22
23impl<'q, L, R> FetchItem<'q> for And<L, R>
24where
25    L: FetchItem<'q>,
26    R: FetchItem<'q>,
27{
28    type Item = (L::Item, R::Item);
29}
30
31impl<'w, L, R> Fetch<'w> for And<L, R>
32where
33    L: Fetch<'w>,
34    R: Fetch<'w>,
35{
36    const MUTABLE: bool = false;
37
38    type Prepared = And<L::Prepared, R::Prepared>;
39
40    #[inline]
41    fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
42        Some(And(self.0.prepare(data)?, self.1.prepare(data)?))
43    }
44
45    fn filter_arch(&self, data: FetchAccessData) -> bool {
46        self.0.filter_arch(data) && self.1.filter_arch(data)
47    }
48
49    fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
50        self.0.access(data, dst);
51        self.1.access(data, dst);
52    }
53
54    fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result {
55        self.0.describe(f)?;
56        f.write_str(" & ")?;
57        self.1.describe(f)?;
58
59        Ok(())
60    }
61
62    fn searcher(&self, searcher: &mut crate::ArchetypeSearcher) {
63        self.0.searcher(searcher);
64        self.1.searcher(searcher);
65    }
66}
67
68impl<'q, L, R> PreparedFetch<'q> for And<L, R>
69where
70    L: PreparedFetch<'q>,
71    R: PreparedFetch<'q>,
72{
73    type Item = (L::Item, R::Item);
74    type Chunk = (L::Chunk, R::Chunk);
75
76    const HAS_FILTER: bool = L::HAS_FILTER || R::HAS_FILTER;
77
78    #[inline]
79    unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
80        let l = self.0.filter_slots(slots);
81
82        self.1.filter_slots(l)
83    }
84
85    unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
86        (self.0.create_chunk(slots), self.1.create_chunk(slots))
87    }
88
89    #[inline]
90    unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
91        (L::fetch_next(&mut chunk.0), R::fetch_next(&mut chunk.1))
92    }
93}
94
95#[derive(Debug, Clone)]
96/// Or filter combinator
97pub struct Or<T>(pub T);
98
99#[derive(Debug, Clone)]
100/// Negate a filter
101pub struct Not<T>(pub T);
102
103impl<'q, T> FetchItem<'q> for Not<T> {
104    type Item = ();
105}
106
107impl<'w, T> Fetch<'w> for Not<T>
108where
109    T: Fetch<'w>,
110{
111    const MUTABLE: bool = true;
112
113    type Prepared = Not<Option<T::Prepared>>;
114
115    fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
116        Some(Not(self.0.prepare(data)))
117    }
118
119    fn filter_arch(&self, data: FetchAccessData) -> bool {
120        !self.0.filter_arch(data)
121    }
122
123    #[inline]
124    fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
125        self.0.access(data, dst)
126    }
127
128    fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result {
129        write!(f, "!{:?}", FmtQuery(&self.0))
130    }
131}
132
133impl<'q, F> PreparedFetch<'q> for Not<Option<F>>
134where
135    F: PreparedFetch<'q>,
136{
137    type Item = ();
138    type Chunk = ();
139
140    const HAS_FILTER: bool = F::HAS_FILTER;
141
142    #[inline]
143    unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
144        if let Some(fetch) = &mut self.0 {
145            let v = fetch.filter_slots(slots);
146
147            slots.difference(v).unwrap()
148        } else {
149            slots
150        }
151    }
152
153    #[inline]
154    unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {}
155
156    #[inline]
157    unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {}
158}
159
160impl<R, T> ops::BitOr<R> for Not<T> {
161    type Output = Or<(Self, R)>;
162
163    fn bitor(self, rhs: R) -> Self::Output {
164        Or((self, rhs))
165    }
166}
167
168impl<R, T> ops::BitAnd<R> for Not<T> {
169    type Output = (Self, R);
170
171    fn bitand(self, rhs: R) -> Self::Output {
172        (self, rhs)
173    }
174}
175
176impl<T> ops::Not for Not<T> {
177    type Output = T;
178
179    fn not(self) -> Self::Output {
180        self.0
181    }
182}
183
184/// Unionized the slot-level filter of two fetches, but requires the individual fetches to still
185/// match.
186///
187/// This allows the filters to return fetch items side by side like the wrapped
188/// fetch would, since all constituent fetches are satisfied, but not necessarily all their entities.
189///
190/// This is most useful for change queries, where you care about about *any* change, but still
191/// require the entity to have all the components, and have them returned despite not all having
192/// changed.
193///
194/// For this to implement `Fetch`, `T::Prepared` must implement `UnionFilter`.
195#[derive(Debug, Clone)]
196pub struct Union<T>(pub T);
197
198impl<'q, T> FetchItem<'q> for Union<T>
199where
200    T: FetchItem<'q>,
201{
202    type Item = T::Item;
203}
204
205impl<'w, T> Fetch<'w> for Union<T>
206where
207    T: Fetch<'w>,
208    T::Prepared: UnionFilter,
209{
210    const MUTABLE: bool = T::MUTABLE;
211
212    type Prepared = Union<T::Prepared>;
213
214    fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
215        Some(Union(self.0.prepare(data)?))
216    }
217
218    fn filter_arch(&self, data: FetchAccessData) -> bool {
219        self.0.filter_arch(data)
220    }
221
222    fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
223        self.0.access(data, dst)
224    }
225
226    fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result {
227        f.debug_tuple("Union").field(&FmtQuery(&self.0)).finish()
228    }
229}
230
231impl<T> UnionFilter for Union<T>
232where
233    T: UnionFilter,
234{
235    const HAS_UNION_FILTER: bool = T::HAS_UNION_FILTER;
236
237    unsafe fn filter_union(&mut self, slots: Slice) -> Slice {
238        self.0.filter_union(slots)
239    }
240}
241
242impl<'q, T> PreparedFetch<'q> for Union<T>
243where
244    T: PreparedFetch<'q> + UnionFilter,
245{
246    type Item = T::Item;
247    const HAS_FILTER: bool = T::HAS_UNION_FILTER;
248
249    #[inline]
250    unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
251        self.filter_union(slots)
252    }
253
254    type Chunk = T::Chunk;
255
256    #[inline]
257    unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
258        self.0.create_chunk(slots)
259    }
260
261    #[inline]
262    unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
263        T::fetch_next(chunk)
264    }
265}
266
267macro_rules! tuple_impl {
268    ($($idx: tt => $ty: ident),*) => {
269        // Or
270        impl<'w, 'q, $($ty, )*> FetchItem<'q> for Or<($($ty,)*)> {
271            type Item = ();
272        }
273
274        impl<'w, $($ty, )*> Fetch<'w> for Or<($($ty,)*)>
275        where $($ty: Fetch<'w>,)*
276        {
277            const MUTABLE: bool =  $($ty::MUTABLE )||*;
278            type Prepared       = Or<($(Option<$ty::Prepared>,)*)>;
279
280            fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
281                let inner = &self.0;
282                Some( Or(($(inner.$idx.prepare(data),)*)) )
283            }
284
285            fn filter_arch(&self, data: FetchAccessData) -> bool {
286                let inner = &self.0;
287                $(inner.$idx.filter_arch(data))||*
288            }
289
290            fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
291                 $(self.0.$idx.access(data, dst);)*
292            }
293
294            fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result {
295                let mut s = f.debug_tuple("Or");
296                    let inner = &self.0;
297                $(
298                    s.field(&FmtQuery(&inner.$idx));
299                )*
300                s.finish()
301            }
302        }
303
304        impl<$($ty: StaticFilter, )*> StaticFilter for Or<($($ty,)*)> {
305            fn filter_static(&self, arch: &Archetype) -> bool {
306                let inner = &self.0;
307                $(inner.$idx.filter_static(arch))||*
308            }
309        }
310
311        impl<'w, 'q, $($ty, )*> PreparedFetch<'q> for Or<($(Option<$ty>,)*)>
312        where 'w: 'q, $($ty: PreparedFetch<'q>,)*
313        {
314            type Item = ();
315            type Chunk = ();
316
317            // && because `x || true` == true
318            const HAS_FILTER: bool =  $($ty::HAS_FILTER )&&*;
319
320            unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
321                let inner = &mut self.0;
322                let end = Slice::new(slots.end, slots.end);
323
324                [
325                    $( inner.$idx.as_mut().map(|v| v.filter_slots(slots)).unwrap_or(end)),*
326                ]
327                .into_iter()
328                .min()
329                .unwrap_or_default()
330
331            }
332
333            #[inline]
334            unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {}
335
336            #[inline]
337            unsafe fn create_chunk(&mut self, _: Slice) -> Self::Chunk {}
338
339        }
340
341        impl<'q, $($ty, )*> UnionFilter for Or<($(Option<$ty>,)*)>
342        where $($ty: PreparedFetch<'q>,)*
343        {
344            const HAS_UNION_FILTER: bool =  $($ty::HAS_FILTER )&&*;
345
346            unsafe fn filter_union(&mut self, slots: Slice) -> Slice {
347                let inner = &mut self.0;
348                let end = Slice::new(slots.end, slots.end);
349
350                [
351                    $( inner.$idx.as_mut().map(|v| v.filter_slots(slots)).unwrap_or(end)),*
352                ]
353                .into_iter()
354                .min()
355                .unwrap_or_default()
356            }
357        }
358    };
359
360
361}
362
363tuple_impl! { 0 => A }
364tuple_impl! { 0 => A, 1 => B }
365tuple_impl! { 0 => A, 1 => B, 2 => C }
366tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D }
367tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E }
368tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F }
369tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H }
370
371#[cfg(test)]
372mod tests {
373    use itertools::Itertools;
374
375    use crate::filter::{FilterIter, Nothing};
376
377    use super::*;
378
379    #[test]
380    fn union() {
381        let fetch = Union((
382            Slice::new(0, 2),
383            Nothing,
384            Slice::new(7, 16),
385            Slice::new(3, 10),
386        ));
387
388        let fetch = FilterIter::new(Slice::new(0, 100), fetch);
389
390        assert_eq!(
391            fetch.collect_vec(),
392            [Slice::new(0, 2), Slice::new(3, 10), Slice::new(10, 16)]
393        );
394    }
395}