flax/fetch/
mod.rs

1mod as_deref;
2mod cloned;
3mod component;
4mod component_mut;
5mod copied;
6mod entity_ref;
7mod ext;
8mod map;
9mod maybe_mut;
10mod opt;
11mod read_only;
12mod relations;
13mod relations_mut;
14mod satisfied;
15mod source;
16mod transform;
17
18use crate::{
19    archetype::{Archetype, ArchetypeId, Slice, Slot},
20    filter::{RefFetch, StaticFilter},
21    system::Access,
22    util::Ptr,
23    ArchetypeSearcher, Entity, World,
24};
25use alloc::vec::Vec;
26use core::fmt::Debug;
27use core::fmt::{self, Formatter};
28
29pub use as_deref::*;
30pub use cloned::*;
31pub use component::*;
32pub use component_mut::*;
33pub use entity_ref::*;
34pub use ext::FetchExt;
35pub use map::Map;
36pub use maybe_mut::{MaybeMut, MutGuard};
37pub use opt::*;
38pub use read_only::*;
39pub use relations::{nth_relation, relations_like, NthRelation, Relations, RelationsIter};
40pub use relations_mut::{relations_like_mut, RelationsIterMut, RelationsMut};
41pub use satisfied::Satisfied;
42pub use source::Source;
43pub use transform::{Added, Modified, TransformFetch};
44
45#[doc(hidden)]
46pub struct FmtQuery<'r, Q>(pub &'r Q);
47
48impl<'r, 'w, Q> Debug for FmtQuery<'r, Q>
49where
50    Q: Fetch<'w>,
51{
52    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
53        self.0.describe(f)
54    }
55}
56
57/// Represents the world data necessary for declaring fetch access
58#[derive(Copy, Clone)]
59pub struct FetchAccessData<'w> {
60    /// The current world
61    pub world: &'w World,
62    /// The iterated archetype to prepare for
63    pub arch: &'w Archetype,
64    /// The archetype id
65    pub arch_id: ArchetypeId,
66}
67
68impl<'w> From<FetchPrepareData<'w>> for FetchAccessData<'w> {
69    fn from(value: FetchPrepareData<'w>) -> Self {
70        Self {
71            world: value.world,
72            arch: value.arch,
73            arch_id: value.arch_id,
74        }
75    }
76}
77
78/// Represents the world data necessary for preparing a fetch
79#[derive(Copy, Clone)]
80pub struct FetchPrepareData<'w> {
81    /// The current world
82    pub world: &'w World,
83    /// The iterated archetype to prepare for
84    pub arch: &'w Archetype,
85    /// The archetype id
86    pub arch_id: ArchetypeId,
87    /// The tick the previous time the query executed
88    pub old_tick: u32,
89    /// The new tick to write if query is mutable
90    pub new_tick: u32,
91}
92
93/// Trait which gives an associated `Item` fetch type
94pub trait FetchItem<'q> {
95    /// The item yielded by the prepared fetch
96    type Item;
97}
98
99/// A fetch describes a retrieval of data from the world and archetypes during a query.
100///
101/// A fetch is prepared, wherein borrows are acquired and a `PreparedFetch` is returned, which is
102/// used to provide the query with values.
103///
104/// The PreparedFetch can in turn control the ranges of slots which are requested by the query,
105/// e.g; filtering changed components
106pub trait Fetch<'w>: for<'q> FetchItem<'q> {
107    /// true if the fetch mutates any component and thus needs a change event
108    const MUTABLE: bool;
109
110    /// The prepared version of the fetch
111    type Prepared: for<'x> PreparedFetch<'x, Item = <Self as FetchItem<'x>>::Item> + 'w;
112
113    /// Prepares the fetch for an archetype by acquiring borrows.
114    ///
115    /// Returns `None` if the archetype does not match.
116    fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared>;
117
118    /// Returns true if the archetype matches the fetch
119    fn filter_arch(&self, data: FetchAccessData) -> bool;
120
121    /// Returns which components and how will be accessed for an archetype.
122    fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>);
123
124    /// Describes the fetch in a human-readable fashion
125    fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result;
126
127    /// Returns the required component for the fetch.
128    ///
129    /// This is used for the query to determine which archetypes to visit
130    #[inline]
131    fn searcher(&self, _searcher: &mut ArchetypeSearcher) {}
132
133    /// Convert the fetch to a reference type which works with `HRTB`
134    #[inline]
135    fn by_ref(&self) -> RefFetch<Self>
136    where
137        Self: Sized,
138    {
139        RefFetch(self)
140    }
141}
142
143/// Borrowed state for a fetch
144pub trait PreparedFetch<'q> {
145    /// Item returned by fetch
146    type Item: 'q;
147    /// A chunk accessing a disjoint set of the borrow sequentially
148    type Chunk: 'q;
149
150    /// Indicates if the fetch will provide any filtering of slots.
151    ///
152    /// If `false`, this fetch will unconditionally yield.
153    ///
154    /// This is used to influence the default behavior of optional queries.
155    const HAS_FILTER: bool;
156
157    /// Creates a chunk to access a slice of the borrow
158    ///
159    /// # Safety
160    ///
161    /// `slots` must be disjoint to all other currently existing chunks
162    unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk;
163
164    /// Fetch the item from entity at the slot in the prepared storage.
165    /// # Safety
166    /// Must return non-aliased references to the underlying borrow of the
167    /// prepared archetype.
168    ///
169    /// The callee is responsible for assuring disjoint calls.
170    unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item;
171
172    #[inline]
173    /// Filter the slots to visit
174    /// Returns the leftmost subslice of `slots` which should be visited
175    ///
176    /// # Safety
177    /// `slots` must not overlap any alive references returned by `fetch`
178    unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
179        slots
180    }
181}
182
183/// Allows filtering the constituent parts of a fetch using a set union
184pub trait UnionFilter {
185    /// The union may not have the same filter behavior as a normal filter as sub-filters
186    /// are combined using *or* instead of *and*. This means any non-filter will cause the
187    /// whole tuple to always yield.
188    const HAS_UNION_FILTER: bool;
189    // Filter the slots using a union operation of the constituent part
190    ///
191    /// # Safety
192    /// See: [`PreparedFetch::filter_slots`]
193    unsafe fn filter_union(&mut self, slots: Slice) -> Slice;
194}
195
196impl<'q, F> PreparedFetch<'q> for &'q mut F
197where
198    F: PreparedFetch<'q>,
199{
200    type Item = F::Item;
201    type Chunk = F::Chunk;
202
203    const HAS_FILTER: bool = F::HAS_FILTER;
204
205    unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
206        (*self).create_chunk(slots)
207    }
208
209    unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
210        F::fetch_next(chunk)
211    }
212
213    unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
214        (*self).filter_slots(slots)
215    }
216}
217
218impl<'q> FetchItem<'q> for () {
219    type Item = ();
220}
221
222impl UnionFilter for () {
223    const HAS_UNION_FILTER: bool = false;
224
225    unsafe fn filter_union(&mut self, slots: Slice) -> Slice {
226        slots
227    }
228}
229
230impl<'w> Fetch<'w> for () {
231    const MUTABLE: bool = false;
232
233    type Prepared = ();
234
235    fn prepare(&self, _: FetchPrepareData<'w>) -> Option<Self::Prepared> {
236        Some(())
237    }
238
239    fn filter_arch(&self, _: FetchAccessData) -> bool {
240        true
241    }
242
243    fn describe(&self, f: &mut Formatter) -> fmt::Result {
244        write!(f, "()")
245    }
246
247    #[inline]
248    fn access(&self, _: FetchAccessData, _: &mut Vec<Access>) {}
249}
250
251impl<'q> RandomFetch<'q> for () {
252    #[inline]
253    unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {}
254    #[inline]
255    unsafe fn fetch_shared_chunk(_: &Self::Chunk, _: Slot) -> Self::Item {}
256}
257
258impl<'q> PreparedFetch<'q> for () {
259    type Item = ();
260
261    type Chunk = ();
262
263    const HAS_FILTER: bool = false;
264
265    #[inline]
266    unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {}
267
268    #[inline]
269    unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {}
270}
271
272// impl<'q, F> PreparedFetch<'q> for Option<F>
273// where
274//     F: PreparedFetch<'q>,
275// {
276//     type Item = Option<F::Item>;
277//     type Chunk = Option<F::Chunk>;
278
279//     unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
280//         self.as_mut().map(|fetch| fetch.create_chunk(slots))
281//     }
282
283//     #[inline]
284//     unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
285//         if let Some(fetch) = self {
286//             fetch.filter_slots(slots)
287//         } else {
288//             Slice::new(slots.end, slots.end)
289//         }
290//     }
291
292//     unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
293//         batch.as_mut().map(|fetch| F::fetch_next(fetch))
294//     }
295// }
296
297#[derive(Debug, Clone)]
298/// Returns the entity ids
299pub struct EntityIds;
300#[doc(hidden)]
301pub struct ReadEntities<'a> {
302    entities: &'a [Entity],
303}
304
305impl<'q> FetchItem<'q> for EntityIds {
306    type Item = Entity;
307}
308
309impl<'w> Fetch<'w> for EntityIds {
310    const MUTABLE: bool = false;
311
312    type Prepared = ReadEntities<'w>;
313
314    fn prepare(&self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
315        Some(ReadEntities {
316            entities: data.arch.entities(),
317        })
318    }
319
320    fn filter_arch(&self, _: FetchAccessData) -> bool {
321        true
322    }
323
324    fn describe(&self, f: &mut Formatter) -> fmt::Result {
325        f.write_str("entity_ids")
326    }
327
328    #[inline]
329    fn access(&self, _: FetchAccessData, _: &mut Vec<Access>) {}
330}
331
332impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> {
333    type Item = Entity;
334    type Chunk = Ptr<'q, Entity>;
335
336    const HAS_FILTER: bool = false;
337
338    unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
339        Ptr::new(self.entities[slots.as_range()].as_ptr())
340    }
341
342    unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
343        let old = chunk.as_ptr();
344        *chunk = chunk.add(1);
345        *old
346    }
347}
348
349impl<'w, 'q> RandomFetch<'q> for ReadEntities<'w> {
350    #[inline]
351    unsafe fn fetch_shared(&self, slot: usize) -> Self::Item {
352        self.entities[slot]
353    }
354
355    unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {
356        *chunk.add(slot).as_ref()
357    }
358}
359
360// Implement for tuples
361macro_rules! tuple_impl {
362    ($($idx: tt => $ty: ident),*) => {
363        impl<'q, $($ty, )*> FetchItem<'q> for ($($ty,)*)
364        where $($ty: FetchItem<'q>,)*
365        {
366            type Item = ($($ty::Item,)*);
367
368        }
369
370        impl<'q, $($ty, )*> RandomFetch<'q> for ($($ty,)*)
371        where $($ty: RandomFetch<'q>,)*
372        {
373
374            #[inline(always)]
375            unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item {
376                ($(
377                    (self.$idx).fetch_shared(slot),
378                )*)
379            }
380
381            #[inline(always)]
382            unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {
383                ($(
384                    $ty::fetch_shared_chunk(&chunk.$idx, slot),
385                )*)
386            }
387        }
388
389
390        impl<'q, $($ty, )*> PreparedFetch<'q> for ($($ty,)*)
391            where $($ty: PreparedFetch<'q>,)*
392        {
393
394            type Item = ($($ty::Item,)*);
395            type Chunk = ($($ty::Chunk,)*);
396
397            const HAS_FILTER: bool =  $($ty::HAS_FILTER )||*;
398
399            #[inline]
400            unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
401                ($(
402                    $ty::fetch_next(&mut chunk.$idx),
403                )*)
404            }
405
406            #[inline]
407            unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
408                ($((self.$idx).create_chunk(slots),)*)
409            }
410
411            #[inline]
412            unsafe fn filter_slots(&mut self, mut slots: Slice) -> Slice {
413                $(
414
415                    slots = self.$idx.filter_slots(slots);
416                )*
417
418                slots
419            }
420        }
421
422        impl<'q, $($ty, )*> UnionFilter for ($($ty,)*)
423            where $($ty: PreparedFetch<'q>,)*
424        {
425
426            const HAS_UNION_FILTER: bool =  $($ty::HAS_FILTER )&&*;
427
428            #[inline]
429            unsafe fn filter_union(&mut self, slots: Slice) -> Slice {
430                [
431                    // Don't leak union into this
432                    $( self.$idx.filter_slots(slots)),*
433                ]
434                .into_iter()
435                .min()
436                .unwrap_or_default()
437            }
438        }
439
440        impl<'w, $($ty, )*> Fetch<'w> for ($($ty,)*)
441        where $($ty: Fetch<'w>,)*
442        {
443            const MUTABLE: bool =  $($ty::MUTABLE )||*;
444            type Prepared       = ($($ty::Prepared,)*);
445
446            #[inline]
447            fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
448                Some( ($( (self.$idx).prepare(data)?,)*) )
449            }
450
451            #[inline]
452            fn filter_arch(&self, data:FetchAccessData) -> bool {
453                ( $((self.$idx).filter_arch(data)) && * )
454            }
455
456            #[inline]
457            fn describe(&self, f: &mut Formatter) -> fmt::Result {
458                Debug::fmt(&($(FmtQuery(&self.$idx),)*), f)
459            }
460
461            #[inline]
462            fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
463                $( (self.$idx).access(data, dst);)*
464            }
465
466            #[inline]
467            fn searcher(&self, searcher: &mut ArchetypeSearcher) {
468                $((self.$idx).searcher(searcher));*
469            }
470        }
471
472        impl< $($ty: StaticFilter, )*> StaticFilter for ($($ty,)*)
473        {
474            fn filter_static(&self, arch: &Archetype) -> bool {
475                ( $((self.$idx).filter_static(arch)) && * )
476            }
477
478        }
479    };
480}
481
482tuple_impl! { 0 => A }
483tuple_impl! { 0 => A, 1 => B }
484tuple_impl! { 0 => A, 1 => B, 2 => C }
485tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D }
486tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E }
487tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F }
488tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H }
489tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H, 7 => I }
490tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H, 7 => I, 8 => J }