Skip to main content

ecsx/query/
mod.rs

1#[cfg(feature = "std")]
2use core::any::Any;
3use core::any::TypeId;
4use core::marker::PhantomData;
5use core::ptr::NonNull;
6use core::slice::Iter as SliceIter;
7#[cfg(feature = "std")]
8use std::sync::{Arc, RwLock};
9
10use crate::alloc::boxed::Box;
11#[cfg(feature = "std")]
12use hashbrown::hash_map;
13
14#[cfg(feature = "std")]
15use crate::TypeIdMap;
16use crate::archetype::Archetype;
17use crate::entities::EntityMeta;
18use crate::{Component, Entity, Substrate};
19
20/// A collection of component types to fetch from a [`Substrate`](crate::Substrate)
21///
22/// See [`Substrate::query`] for detailed discussion.
23///
24/// The interface of this trait is a private implementation detail.
25pub trait Query {
26    /// Type of results yielded by the query
27    ///
28    /// This is usually the same type as the query itself, except with an appropriate lifetime.
29    type Item<'a>;
30
31    #[doc(hidden)]
32    type Fetch: Fetch;
33
34    #[doc(hidden)]
35    /// Access the `n`th item in this archetype, an entity with generation `generation`, without bounds checking
36    ///
37    /// # Safety
38    /// - Must only be called after [`Fetch::borrow`] or with exclusive access to the archetype
39    /// - [`Fetch::release`] must not be called while `'a` is still live
40    /// - Bounds-checking must be performed externally
41    /// - Any resulting borrows must be legal (e.g. no &mut to something another iterator might access)
42    unsafe fn get<'a>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'a>;
43}
44
45/// Marker trait indicating whether a given [`Query`] will not produce unique references
46#[allow(clippy::missing_safety_doc)]
47pub unsafe trait QueryShared {}
48
49/// Streaming iterators over contiguous homogeneous ranges of components
50#[allow(clippy::missing_safety_doc)]
51pub unsafe trait Fetch: Clone + Sized + 'static {
52    /// The type of the data which can be cached to speed up retrieving
53    /// the relevant type states from a matching [`Archetype`]
54    type State: Copy + Send + Sync;
55
56    /// A value on which `get` may never be called
57    fn dangling() -> Self;
58
59    /// How this query will access `archetype`, if at all
60    fn access(archetype: &Archetype) -> Option<Access>;
61
62    /// Acquire dynamic borrows from `archetype`
63    fn borrow(archetype: &Archetype, state: Self::State);
64    /// Look up state for `archetype` if it should be traversed
65    fn prepare(archetype: &Archetype) -> Option<Self::State>;
66    /// Construct a `Fetch` for `archetype` based on the associated state
67    fn execute(archetype: &Archetype, state: Self::State) -> Self;
68    /// Release dynamic borrows acquired by `borrow`
69    fn release(archetype: &Archetype, state: Self::State);
70
71    /// Invoke `f` for every component type that may be borrowed and whether the borrow is unique
72    fn for_each_borrow(f: impl FnMut(TypeId, bool));
73}
74
75/// Type of access a [`Query`] may have to an [`Archetype`]
76#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
77pub enum Access {
78    /// Read entity IDs only, no components
79    Iterate,
80    /// Read components
81    Read,
82    /// Read and write components
83    Write,
84}
85
86impl Query for Entity {
87    type Item<'q> = Entity;
88    type Fetch = FetchEntity;
89
90    unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
91        let id = fetch.0.as_ptr().add(n).read();
92        Entity {
93            id,
94            generation: meta.get_unchecked(id as usize).generation,
95        }
96    }
97}
98unsafe impl QueryShared for Entity {}
99
100#[doc(hidden)]
101#[derive(Clone)]
102pub struct FetchEntity(NonNull<u32>);
103
104unsafe impl Fetch for FetchEntity {
105    type State = ();
106
107    fn dangling() -> Self {
108        Self(NonNull::dangling())
109    }
110
111    fn access(_: &Archetype) -> Option<Access> {
112        Some(Access::Iterate)
113    }
114
115    fn borrow(_: &Archetype, (): Self::State) {}
116
117    fn prepare(_: &Archetype) -> Option<Self::State> {
118        Some(())
119    }
120
121    fn execute(archetype: &Archetype, (): Self::State) -> Self {
122        Self(archetype.entities())
123    }
124
125    fn release(_: &Archetype, (): Self::State) {}
126
127    fn for_each_borrow(_: impl FnMut(TypeId, bool)) {}
128}
129
130impl<T: Component> Query for &'_ T {
131    type Item<'q> = &'q T;
132
133    type Fetch = FetchRead<T>;
134
135    unsafe fn get<'q>(_: &[EntityMeta], fetch: &FetchRead<T>, n: usize) -> &'q T {
136        &*fetch.0.as_ptr().add(n)
137    }
138}
139
140unsafe impl<T> QueryShared for &'_ T {}
141
142#[doc(hidden)]
143pub struct FetchRead<T>(NonNull<T>);
144
145unsafe impl<T: Component> Fetch for FetchRead<T> {
146    type State = usize;
147
148    fn dangling() -> Self {
149        Self(NonNull::dangling())
150    }
151
152    fn access(archetype: &Archetype) -> Option<Access> {
153        if archetype.has::<T>() {
154            Some(Access::Read)
155        } else {
156            None
157        }
158    }
159
160    fn borrow(archetype: &Archetype, state: Self::State) {
161        archetype.borrow::<T>(state);
162    }
163    fn prepare(archetype: &Archetype) -> Option<Self::State> {
164        archetype.get_state::<T>()
165    }
166    fn execute(archetype: &Archetype, state: Self::State) -> Self {
167        unsafe { Self(archetype.get_base(state)) }
168    }
169    fn release(archetype: &Archetype, state: Self::State) {
170        archetype.release::<T>(state);
171    }
172
173    fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
174        f(TypeId::of::<T>(), false);
175    }
176}
177
178impl<T> Clone for FetchRead<T> {
179    #[inline]
180    fn clone(&self) -> Self {
181        Self(self.0)
182    }
183}
184
185impl<T: Component> Query for &'_ mut T {
186    type Item<'q> = &'q mut T;
187
188    type Fetch = FetchWrite<T>;
189
190    unsafe fn get<'q>(_: &[EntityMeta], fetch: &FetchWrite<T>, n: usize) -> &'q mut T {
191        &mut *fetch.0.as_ptr().add(n)
192    }
193}
194
195#[doc(hidden)]
196pub struct FetchWrite<T>(NonNull<T>);
197
198unsafe impl<T: Component> Fetch for FetchWrite<T> {
199    type State = usize;
200
201    fn dangling() -> Self {
202        Self(NonNull::dangling())
203    }
204
205    fn access(archetype: &Archetype) -> Option<Access> {
206        if archetype.has::<T>() {
207            Some(Access::Write)
208        } else {
209            None
210        }
211    }
212
213    fn borrow(archetype: &Archetype, state: Self::State) {
214        archetype.borrow_mut::<T>(state);
215    }
216    #[allow(clippy::needless_question_mark)]
217    fn prepare(archetype: &Archetype) -> Option<Self::State> {
218        Some(archetype.get_state::<T>()?)
219    }
220    fn execute(archetype: &Archetype, state: Self::State) -> Self {
221        unsafe { Self(archetype.get_base::<T>(state)) }
222    }
223    fn release(archetype: &Archetype, state: Self::State) {
224        archetype.release_mut::<T>(state);
225    }
226
227    fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
228        f(TypeId::of::<T>(), true);
229    }
230}
231
232impl<T> Clone for FetchWrite<T> {
233    #[inline]
234    fn clone(&self) -> Self {
235        Self(self.0)
236    }
237}
238
239impl<T: Query> Query for Option<T> {
240    type Item<'q> = Option<T::Item<'q>>;
241
242    type Fetch = TryFetch<T::Fetch>;
243
244    unsafe fn get<'q>(
245        meta: &[EntityMeta],
246        fetch: &TryFetch<T::Fetch>,
247        n: usize,
248    ) -> Option<T::Item<'q>> {
249        Some(T::get(meta, fetch.0.as_ref()?, n))
250    }
251}
252
253unsafe impl<T: QueryShared> QueryShared for Option<T> {}
254
255#[doc(hidden)]
256#[derive(Clone)]
257pub struct TryFetch<T>(Option<T>);
258
259unsafe impl<T: Fetch> Fetch for TryFetch<T> {
260    type State = Option<T::State>;
261
262    fn dangling() -> Self {
263        Self(None)
264    }
265
266    fn access(archetype: &Archetype) -> Option<Access> {
267        Some(T::access(archetype).unwrap_or(Access::Iterate))
268    }
269
270    fn borrow(archetype: &Archetype, state: Self::State) {
271        if let Some(state) = state {
272            T::borrow(archetype, state);
273        }
274    }
275    fn prepare(archetype: &Archetype) -> Option<Self::State> {
276        Some(T::prepare(archetype))
277    }
278    fn execute(archetype: &Archetype, state: Self::State) -> Self {
279        Self(state.map(|state| T::execute(archetype, state)))
280    }
281    fn release(archetype: &Archetype, state: Self::State) {
282        if let Some(state) = state {
283            T::release(archetype, state);
284        }
285    }
286
287    fn for_each_borrow(f: impl FnMut(TypeId, bool)) {
288        T::for_each_borrow(f);
289    }
290}
291
292/// Holds an `L`, or an `R`, or both
293#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
294pub enum Or<L, R> {
295    /// Just an `L`
296    Left(L),
297    /// Just an `R`
298    Right(R),
299    /// Both an `L` and an `R`
300    Both(L, R),
301}
302
303impl<L, R> Or<L, R> {
304    /// Construct an `Or<L, R>` if at least one argument is `Some`
305    pub fn new(l: Option<L>, r: Option<R>) -> Option<Self> {
306        match (l, r) {
307            (None, None) => None,
308            (Some(l), None) => Some(Or::Left(l)),
309            (None, Some(r)) => Some(Or::Right(r)),
310            (Some(l), Some(r)) => Some(Or::Both(l, r)),
311        }
312    }
313
314    /// Destructure into two `Option`s, where either or both are `Some`
315    pub fn split(self) -> (Option<L>, Option<R>) {
316        match self {
317            Or::Left(l) => (Some(l), None),
318            Or::Right(r) => (None, Some(r)),
319            Or::Both(l, r) => (Some(l), Some(r)),
320        }
321    }
322
323    /// Extract `L` regardless of whether `R` is present
324    pub fn left(self) -> Option<L> {
325        match self {
326            Or::Left(l) => Some(l),
327            Or::Both(l, _) => Some(l),
328            _ => None,
329        }
330    }
331
332    /// Extract `R` regardless of whether `L` is present
333    pub fn right(self) -> Option<R> {
334        match self {
335            Or::Right(r) => Some(r),
336            Or::Both(_, r) => Some(r),
337            _ => None,
338        }
339    }
340
341    /// Transform `L` with `f` and `R` with `g`
342    pub fn map<L1, R1, F, G>(self, f: F, g: G) -> Or<L1, R1>
343    where
344        F: FnOnce(L) -> L1,
345        G: FnOnce(R) -> R1,
346    {
347        match self {
348            Or::Left(l) => Or::Left(f(l)),
349            Or::Right(r) => Or::Right(g(r)),
350            Or::Both(l, r) => Or::Both(f(l), g(r)),
351        }
352    }
353
354    /// Convert from `&Or<L, R>` to `Or<&L, &R>`
355    pub fn as_ref(&self) -> Or<&L, &R> {
356        match *self {
357            Or::Left(ref l) => Or::Left(l),
358            Or::Right(ref r) => Or::Right(r),
359            Or::Both(ref l, ref r) => Or::Both(l, r),
360        }
361    }
362
363    /// Convert from `&mut Or<L, R>` to `Or<&mut L, &mut R>`
364    pub fn as_mut(&mut self) -> Or<&mut L, &mut R> {
365        match *self {
366            Or::Left(ref mut l) => Or::Left(l),
367            Or::Right(ref mut r) => Or::Right(r),
368            Or::Both(ref mut l, ref mut r) => Or::Both(l, r),
369        }
370    }
371}
372
373impl<L, R> Or<&'_ L, &'_ R>
374where
375    L: Clone,
376    R: Clone,
377{
378    /// Maps an `Or<&L, &R>` to an `Or<L, R>` by cloning its contents
379    pub fn cloned(self) -> Or<L, R> {
380        self.map(Clone::clone, Clone::clone)
381    }
382}
383
384impl<L: Query, R: Query> Query for Or<L, R> {
385    type Item<'q> = Or<L::Item<'q>, R::Item<'q>>;
386
387    type Fetch = FetchOr<L::Fetch, R::Fetch>;
388
389    unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
390        fetch
391            .0
392            .as_ref()
393            .map(|l| L::get(meta, l, n), |r| R::get(meta, r, n))
394    }
395}
396
397unsafe impl<L: QueryShared, R: QueryShared> QueryShared for Or<L, R> {}
398
399#[doc(hidden)]
400#[derive(Clone)]
401pub struct FetchOr<L, R>(Or<L, R>);
402
403unsafe impl<L: Fetch, R: Fetch> Fetch for FetchOr<L, R> {
404    type State = Or<L::State, R::State>;
405
406    fn dangling() -> Self {
407        Self(Or::Left(L::dangling()))
408    }
409
410    fn access(archetype: &Archetype) -> Option<Access> {
411        L::access(archetype).max(R::access(archetype))
412    }
413
414    fn borrow(archetype: &Archetype, state: Self::State) {
415        state.map(|l| L::borrow(archetype, l), |r| R::borrow(archetype, r));
416    }
417
418    fn prepare(archetype: &Archetype) -> Option<Self::State> {
419        Or::new(L::prepare(archetype), R::prepare(archetype))
420    }
421
422    fn execute(archetype: &Archetype, state: Self::State) -> Self {
423        Self(state.map(|l| L::execute(archetype, l), |r| R::execute(archetype, r)))
424    }
425
426    fn release(archetype: &Archetype, state: Self::State) {
427        state.map(|l| L::release(archetype, l), |r| R::release(archetype, r));
428    }
429
430    fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
431        L::for_each_borrow(&mut f);
432        R::for_each_borrow(&mut f);
433    }
434}
435
436/// Transforms query `Q` by skipping entities satisfying query `R`
437///
438/// See also `QueryBorrow::without`.
439///
440/// # Example
441/// ```
442/// # use ecsx::*;
443/// let mut world = Substrate::new();
444/// let a = world.spawn((123, true, "abc"));
445/// let b = world.spawn((456, false));
446/// let c = world.spawn((42, "def"));
447/// let entities = world.query::<Without<(Entity, &i32), &bool>>()
448///     .iter()
449///     .map(|(e, &i)| (e, i))
450///     .collect::<Vec<_>>();
451/// assert_eq!(entities, &[(c, 42)]);
452/// ```
453pub struct Without<Q, R>(PhantomData<(Q, fn(R))>);
454
455impl<Q: Query, R: Query> Query for Without<Q, R> {
456    type Item<'q> = Q::Item<'q>;
457
458    type Fetch = FetchWithout<Q::Fetch, R::Fetch>;
459
460    unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
461        Q::get(meta, &fetch.0, n)
462    }
463}
464
465unsafe impl<Q: QueryShared, R> QueryShared for Without<Q, R> {}
466
467#[doc(hidden)]
468pub struct FetchWithout<F, G>(F, PhantomData<fn(G)>);
469
470unsafe impl<F: Fetch, G: Fetch> Fetch for FetchWithout<F, G> {
471    type State = F::State;
472
473    fn dangling() -> Self {
474        Self(F::dangling(), PhantomData)
475    }
476
477    fn access(archetype: &Archetype) -> Option<Access> {
478        if G::access(archetype).is_some() {
479            None
480        } else {
481            F::access(archetype)
482        }
483    }
484
485    fn borrow(archetype: &Archetype, state: Self::State) {
486        F::borrow(archetype, state)
487    }
488    fn prepare(archetype: &Archetype) -> Option<Self::State> {
489        if G::access(archetype).is_some() {
490            return None;
491        }
492        F::prepare(archetype)
493    }
494    fn execute(archetype: &Archetype, state: Self::State) -> Self {
495        Self(F::execute(archetype, state), PhantomData)
496    }
497    fn release(archetype: &Archetype, state: Self::State) {
498        F::release(archetype, state)
499    }
500
501    fn for_each_borrow(f: impl FnMut(TypeId, bool)) {
502        F::for_each_borrow(f);
503    }
504}
505
506impl<F: Clone, G> Clone for FetchWithout<F, G> {
507    #[inline]
508    fn clone(&self) -> Self {
509        Self(self.0.clone(), PhantomData)
510    }
511}
512
513/// Transforms query `Q` by skipping entities not satisfying query `R`
514///
515/// See also `QueryBorrow::with`.
516///
517/// # Example
518/// ```
519/// # use ecsx::*;
520/// let mut world = Substrate::new();
521/// let a = world.spawn((123, true, "abc"));
522/// let b = world.spawn((456, false));
523/// let c = world.spawn((42, "def"));
524/// let entities = world.query::<With<(Entity, &i32), &bool>>()
525///     .iter()
526///     .map(|(e, &i)| (e, i))
527///     .collect::<Vec<_>>();
528/// assert_eq!(entities.len(), 2);
529/// assert!(entities.contains(&(a, 123)));
530/// assert!(entities.contains(&(b, 456)));
531/// ```
532pub struct With<Q, R>(PhantomData<(Q, fn(R))>);
533
534impl<Q: Query, R: Query> Query for With<Q, R> {
535    type Item<'q> = Q::Item<'q>;
536
537    type Fetch = FetchWith<Q::Fetch, R::Fetch>;
538
539    unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
540        Q::get(meta, &fetch.0, n)
541    }
542}
543
544unsafe impl<Q: QueryShared, R> QueryShared for With<Q, R> {}
545
546#[doc(hidden)]
547pub struct FetchWith<F, G>(F, PhantomData<fn(G)>);
548
549unsafe impl<F: Fetch, G: Fetch> Fetch for FetchWith<F, G> {
550    type State = F::State;
551
552    fn dangling() -> Self {
553        Self(F::dangling(), PhantomData)
554    }
555
556    fn access(archetype: &Archetype) -> Option<Access> {
557        if G::access(archetype).is_some() {
558            F::access(archetype)
559        } else {
560            None
561        }
562    }
563
564    fn borrow(archetype: &Archetype, state: Self::State) {
565        F::borrow(archetype, state)
566    }
567    fn prepare(archetype: &Archetype) -> Option<Self::State> {
568        G::access(archetype)?;
569        F::prepare(archetype)
570    }
571    fn execute(archetype: &Archetype, state: Self::State) -> Self {
572        Self(F::execute(archetype, state), PhantomData)
573    }
574    fn release(archetype: &Archetype, state: Self::State) {
575        F::release(archetype, state)
576    }
577
578    fn for_each_borrow(f: impl FnMut(TypeId, bool)) {
579        F::for_each_borrow(f);
580    }
581}
582
583impl<F: Clone, G> Clone for FetchWith<F, G> {
584    #[inline]
585    fn clone(&self) -> Self {
586        Self(self.0.clone(), PhantomData)
587    }
588}
589
590/// A query that matches all entities, yielding `bool`s indicating whether each satisfies query `Q`
591///
592/// Does not borrow any components, making it faster and more concurrency-friendly than `Option<Q>`.
593///
594/// # Example
595/// ```
596/// # use ecsx::*;
597/// let mut world = Substrate::new();
598/// let a = world.spawn((123, true, "abc"));
599/// let b = world.spawn((456, false));
600/// let c = world.spawn((42, "def"));
601/// let entities = world.query::<(Entity, Satisfies<&bool>)>()
602///     .iter()
603///     .collect::<Vec<_>>();
604/// assert_eq!(entities.len(), 3);
605/// assert!(entities.contains(&(a, true)));
606/// assert!(entities.contains(&(b, true)));
607/// assert!(entities.contains(&(c, false)));
608/// ```
609pub struct Satisfies<Q>(PhantomData<Q>);
610
611impl<Q: Query> Query for Satisfies<Q> {
612    type Item<'q> = bool;
613
614    type Fetch = FetchSatisfies<Q::Fetch>;
615
616    unsafe fn get<'q>(_: &[EntityMeta], fetch: &Self::Fetch, _: usize) -> Self::Item<'q> {
617        fetch.0
618    }
619}
620
621unsafe impl<Q> QueryShared for Satisfies<Q> {}
622
623#[doc(hidden)]
624pub struct FetchSatisfies<F>(bool, PhantomData<F>);
625
626unsafe impl<F: Fetch> Fetch for FetchSatisfies<F> {
627    type State = bool;
628
629    fn dangling() -> Self {
630        Self(false, PhantomData)
631    }
632
633    fn access(_archetype: &Archetype) -> Option<Access> {
634        Some(Access::Iterate)
635    }
636
637    fn borrow(_archetype: &Archetype, _state: Self::State) {}
638    fn prepare(archetype: &Archetype) -> Option<Self::State> {
639        Some(F::prepare(archetype).is_some())
640    }
641    fn execute(_archetype: &Archetype, state: Self::State) -> Self {
642        Self(state, PhantomData)
643    }
644    fn release(_archetype: &Archetype, _state: Self::State) {}
645
646    fn for_each_borrow(_: impl FnMut(TypeId, bool)) {}
647}
648
649impl<T> Clone for FetchSatisfies<T> {
650    #[inline]
651    fn clone(&self) -> Self {
652        Self(self.0, PhantomData)
653    }
654}
655
656/// A borrow of a [`Substrate`](crate::Substrate) sufficient to execute the query `Q`
657///
658/// Note that borrows are not released until this object is dropped.
659pub struct QueryBorrow<'w, Q: Query> {
660    world: &'w Substrate,
661    cache: Option<CachedQuery<Q::Fetch>>,
662}
663
664impl<'w, Q: Query> QueryBorrow<'w, Q> {
665    pub(crate) fn new(world: &'w Substrate) -> Self {
666        Self { world, cache: None }
667    }
668
669    /// Execute the query
670    // The lifetime narrowing here is required for soundness.
671    pub fn iter(&mut self) -> QueryIter<'_, Q> {
672        let cache = self.borrow().clone();
673        unsafe { QueryIter::new(self.world, cache) }
674    }
675
676    /// Provide random access to the query results
677    pub fn view(&mut self) -> View<'_, Q> {
678        let cache = self.borrow().clone();
679        unsafe {
680            View::new(
681                self.world.entities_meta(),
682                self.world.archetypes_inner(),
683                cache,
684            )
685        }
686    }
687
688    /// Like `iter`, but returns child iterators of at most `batch_size` elements
689    ///
690    /// Useful for distributing work over a threadpool.
691    // The lifetime narrowing here is required for soundness.
692    pub fn iter_batched(&mut self, batch_size: u32) -> BatchedIter<'_, Q> {
693        let cache = self.borrow().clone();
694        unsafe {
695            BatchedIter::new(
696                self.world.entities_meta(),
697                self.world.archetypes_inner(),
698                batch_size,
699                cache,
700            )
701        }
702    }
703
704    fn borrow(&mut self) -> &CachedQuery<Q::Fetch> {
705        if self.cache.is_none() {
706            let cache = CachedQuery::get(self.world);
707            cache.borrow(self.world.archetypes_inner());
708            self.cache = Some(cache);
709        }
710
711        self.cache.as_ref().unwrap()
712    }
713
714    /// Transform the query into one that requires another query be satisfied
715    ///
716    /// Convenient when the values of the components in the other query are not of interest.
717    ///
718    /// Equivalent to using a query type wrapped in `With`.
719    ///
720    /// # Example
721    /// ```
722    /// # use ecsx::*;
723    /// let mut world = Substrate::new();
724    /// let a = world.spawn((123, true, "abc"));
725    /// let b = world.spawn((456, false));
726    /// let c = world.spawn((42, "def"));
727    /// let entities = world.query::<(Entity, &i32)>()
728    ///     .with::<&bool>()
729    ///     .iter()
730    ///     .map(|(e, &i)| (e, i)) // Copy out of the world
731    ///     .collect::<Vec<_>>();
732    /// assert_eq!(entities.len(), 2);
733    /// assert!(entities.contains(&(a, 123)));
734    /// assert!(entities.contains(&(b, 456)));
735    /// ```
736    pub fn with<R: Query>(self) -> QueryBorrow<'w, With<Q, R>> {
737        self.transform()
738    }
739
740    /// Transform the query into one that skips entities satisfying another
741    ///
742    /// Equivalent to using a query type wrapped in `Without`.
743    ///
744    /// # Example
745    /// ```
746    /// # use ecsx::*;
747    /// let mut world = Substrate::new();
748    /// let a = world.spawn((123, true, "abc"));
749    /// let b = world.spawn((456, false));
750    /// let c = world.spawn((42, "def"));
751    /// let entities = world.query::<(Entity, &i32)>()
752    ///     .without::<&bool>()
753    ///     .iter()
754    ///     .map(|(e, &i)| (e, i)) // Copy out of the world
755    ///     .collect::<Vec<_>>();
756    /// assert_eq!(entities, &[(c, 42)]);
757    /// ```
758    pub fn without<R: Query>(self) -> QueryBorrow<'w, Without<Q, R>> {
759        self.transform()
760    }
761
762    /// Helper to change the type of the query
763    fn transform<R: Query>(self) -> QueryBorrow<'w, R> {
764        QueryBorrow {
765            world: self.world,
766            cache: None,
767        }
768    }
769}
770
771unsafe impl<Q: Query> Send for QueryBorrow<'_, Q> where for<'a> Q::Item<'a>: Send {}
772unsafe impl<Q: Query> Sync for QueryBorrow<'_, Q> where for<'a> Q::Item<'a>: Send {}
773
774impl<Q: Query> Drop for QueryBorrow<'_, Q> {
775    fn drop(&mut self) {
776        if let Some(cache) = &self.cache {
777            cache.release_borrow(self.world.archetypes_inner());
778        }
779    }
780}
781
782impl<'q, Q: Query> IntoIterator for &'q mut QueryBorrow<'_, Q> {
783    type Item = Q::Item<'q>;
784    type IntoIter = QueryIter<'q, Q>;
785
786    fn into_iter(self) -> Self::IntoIter {
787        self.iter()
788    }
789}
790
791/// Iterator over the set of entities with the components in `Q`
792pub struct QueryIter<'q, Q: Query> {
793    world: &'q Substrate,
794    archetypes: ArchetypeIter<Q>,
795    iter: ChunkIter<Q>,
796}
797
798impl<'q, Q: Query> QueryIter<'q, Q> {
799    /// # Safety
800    ///
801    /// `'q` must be sufficient to guarantee that `Q` cannot violate borrow safety, either with
802    /// dynamic borrow checks or by representing exclusive access to the `Substrate`. `cache` must be
803    /// from `world`.
804    unsafe fn new(world: &'q Substrate, cache: CachedQuery<Q::Fetch>) -> Self {
805        Self {
806            world,
807            archetypes: ArchetypeIter::new(world, cache),
808            iter: ChunkIter::empty(),
809        }
810    }
811}
812
813unsafe impl<Q: Query> Send for QueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
814unsafe impl<Q: Query> Sync for QueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
815
816impl<'q, Q: Query> Iterator for QueryIter<'q, Q> {
817    type Item = Q::Item<'q>;
818
819    #[inline(always)]
820    fn next(&mut self) -> Option<Self::Item> {
821        loop {
822            match unsafe { self.iter.next(self.world.entities_meta()) } {
823                None => {
824                    // Safety: `self.world` is the same one we passed to `ArchetypeIter::new` just above
825                    unsafe {
826                        self.iter = self.archetypes.next(self.world)?;
827                    }
828                    continue;
829                }
830                Some(components) => {
831                    return Some(components);
832                }
833            }
834        }
835    }
836
837    fn size_hint(&self) -> (usize, Option<usize>) {
838        let n = self.len();
839        (n, Some(n))
840    }
841
842    // We're implementing this because some `Iterator`-consuming methods are
843    // implemented using `Iterator::fold`. With an optmized version implemented
844    // without actually calling `Iterator::next`, they all benefit from
845    // improved performance. See `for_each_100k` bench.
846    //
847    // TODO: Once `Try` is stable, implement `Iterator::try_fold` instead. This
848    // will make *all* `Iterator`-consuming methods rely on that
849    // implementation.
850    fn fold<B, F>(mut self, mut init: B, mut f: F) -> B
851    where
852        Self: Sized,
853        F: FnMut(B, Self::Item) -> B,
854    {
855        loop {
856            while let Some(components) = unsafe { self.iter.next(self.world.entities_meta()) } {
857                init = f(init, components);
858            }
859
860            if let Some(iter) = unsafe { self.archetypes.next(self.world) } {
861                self.iter = iter;
862            } else {
863                break init;
864            }
865        }
866    }
867}
868
869impl<Q: Query> ExactSizeIterator for QueryIter<'_, Q> {
870    fn len(&self) -> usize {
871        self.archetypes.entity_len(self.world) + self.iter.remaining()
872    }
873}
874
875/// A query builder that's convertible directly into an iterator
876pub struct QueryMut<'q, Q: Query> {
877    world: &'q mut Substrate,
878    _marker: PhantomData<fn() -> Q>,
879}
880
881impl<'q, Q: Query> QueryMut<'q, Q> {
882    pub(crate) fn new(world: &'q mut Substrate) -> Self {
883        assert_borrow::<Q>();
884        Self {
885            world,
886            _marker: PhantomData,
887        }
888    }
889
890    /// Provide random access to the query results
891    pub fn view(&mut self) -> View<'_, Q> {
892        let cache = CachedQuery::get(self.world);
893        unsafe {
894            View::new(
895                self.world.entities_meta(),
896                self.world.archetypes_inner(),
897                cache,
898            )
899        }
900    }
901
902    /// Transform the query into one that requires another query be satisfied
903    ///
904    /// See `QueryBorrow::with`
905    pub fn with<R: Query>(self) -> QueryMut<'q, With<Q, R>> {
906        self.transform()
907    }
908
909    /// Transform the query into one that skips entities satisfying another
910    ///
911    /// See `QueryBorrow::without`
912    pub fn without<R: Query>(self) -> QueryMut<'q, Without<Q, R>> {
913        self.transform()
914    }
915
916    /// Helper to change the type of the query
917    fn transform<R: Query>(self) -> QueryMut<'q, R> {
918        QueryMut {
919            world: self.world,
920            _marker: PhantomData,
921        }
922    }
923
924    /// Like `into_iter`, but returns child iterators of at most `batch_size` elements
925    ///
926    /// Useful for distributing work over a threadpool.
927    pub fn into_iter_batched(self, batch_size: u32) -> BatchedIter<'q, Q> {
928        let cache = CachedQuery::get(self.world);
929        unsafe {
930            BatchedIter::new(
931                self.world.entities_meta(),
932                self.world.archetypes_inner(),
933                batch_size,
934                cache,
935            )
936        }
937    }
938}
939
940impl<'q, Q: Query> IntoIterator for QueryMut<'q, Q> {
941    type Item = <QueryIter<'q, Q> as Iterator>::Item;
942    type IntoIter = QueryIter<'q, Q>;
943
944    #[inline]
945    fn into_iter(self) -> Self::IntoIter {
946        let cache = CachedQuery::get(self.world);
947        unsafe { QueryIter::new(self.world, cache) }
948    }
949}
950
951/// Check that Q doesn't alias a `&mut T` on its own. Currently over-conservative for `Or` queries.
952pub(crate) fn assert_borrow<Q: Query>() {
953    // This looks like an ugly O(n^2) loop, but everything's constant after inlining, so in
954    // practice LLVM optimizes it out entirely.
955    let mut i = 0;
956    Q::Fetch::for_each_borrow(|a, unique| {
957        if unique {
958            let mut j = 0;
959            Q::Fetch::for_each_borrow(|b, _| {
960                if i != j {
961                    core::assert!(a != b, "query violates a unique borrow");
962                }
963                j += 1;
964            })
965        }
966        i += 1;
967    });
968}
969
970struct ChunkIter<Q: Query> {
971    fetch: Q::Fetch,
972    position: usize,
973    len: usize,
974}
975
976impl<Q: Query> ChunkIter<Q> {
977    fn new(archetype: &Archetype, fetch: Q::Fetch) -> Self {
978        Self {
979            fetch,
980            position: 0,
981            len: archetype.len() as usize,
982        }
983    }
984
985    fn empty() -> Self {
986        Self {
987            fetch: Q::Fetch::dangling(),
988            position: 0,
989            len: 0,
990        }
991    }
992
993    #[inline]
994    unsafe fn next<'a>(&mut self, meta: &[EntityMeta]) -> Option<Q::Item<'a>> {
995        if self.position == self.len {
996            return None;
997        }
998        let item = Q::get(meta, &self.fetch, self.position);
999        self.position += 1;
1000        Some(item)
1001    }
1002
1003    fn remaining(&self) -> usize {
1004        self.len - self.position
1005    }
1006}
1007
1008/// Batched version of [`QueryIter`]
1009pub struct BatchedIter<'q, Q: Query> {
1010    _marker: PhantomData<&'q Q>,
1011    meta: &'q [EntityMeta],
1012    archetypes: &'q [Archetype],
1013    index_iter: core::ops::Range<usize>,
1014    batch_size: u32,
1015    cache: CachedQuery<Q::Fetch>,
1016    batch: u32,
1017}
1018
1019impl<'q, Q: Query> BatchedIter<'q, Q> {
1020    /// # Safety
1021    ///
1022    /// `'q` must be sufficient to guarantee that `Q` cannot violate borrow safety, either with
1023    /// dynamic borrow checks or by representing exclusive access to the `Substrate`.
1024    unsafe fn new(
1025        meta: &'q [EntityMeta],
1026        archetypes: &'q [Archetype],
1027        batch_size: u32,
1028        cache: CachedQuery<Q::Fetch>,
1029    ) -> Self {
1030        Self {
1031            _marker: PhantomData,
1032            meta,
1033            archetypes,
1034            index_iter: (0..cache.archetype_count(archetypes)),
1035            batch_size,
1036            cache,
1037            batch: 0,
1038        }
1039    }
1040}
1041
1042unsafe impl<Q: Query> Send for BatchedIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
1043unsafe impl<Q: Query> Sync for BatchedIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
1044
1045impl<'q, Q: Query> Iterator for BatchedIter<'q, Q> {
1046    type Item = Batch<'q, Q>;
1047
1048    fn next(&mut self) -> Option<Self::Item> {
1049        loop {
1050            let mut indices = self.index_iter.clone();
1051            let index = indices.next()?;
1052            let Some((archetype, state)) =
1053                (unsafe { self.cache.get_state(self.archetypes, index) })
1054            else {
1055                // Skip this archetype entirely
1056                self.index_iter = indices;
1057                continue;
1058            };
1059            let offset = self.batch_size * self.batch;
1060            if offset >= archetype.len() {
1061                // We've yielded the contents of this archetype already
1062                self.index_iter = indices;
1063                self.batch = 0;
1064                continue;
1065            }
1066            let fetch = Q::Fetch::execute(archetype, state);
1067            self.batch += 1;
1068            let mut state = ChunkIter::new(archetype, fetch);
1069            state.position = offset as usize;
1070            state.len = (offset + self.batch_size.min(archetype.len() - offset)) as usize;
1071            return Some(Batch {
1072                meta: self.meta,
1073                state,
1074            });
1075        }
1076    }
1077}
1078
1079/// A sequence of entities yielded by [`BatchedIter`]
1080pub struct Batch<'q, Q: Query> {
1081    meta: &'q [EntityMeta],
1082    state: ChunkIter<Q>,
1083}
1084
1085impl<'q, Q: Query> Iterator for Batch<'q, Q> {
1086    type Item = Q::Item<'q>;
1087
1088    fn next(&mut self) -> Option<Self::Item> {
1089        unsafe { self.state.next(self.meta) }
1090    }
1091}
1092
1093unsafe impl<Q: Query> Send for Batch<'_, Q> where for<'a> Q::Item<'a>: Send {}
1094unsafe impl<Q: Query> Sync for Batch<'_, Q> where for<'a> Q::Item<'a>: Send {}
1095
1096macro_rules! tuple_impl {
1097    ($($name: ident),*) => {
1098        unsafe impl<$($name: Fetch),*> Fetch for ($($name,)*) {
1099            type State = ($($name::State,)*);
1100
1101            #[allow(clippy::unused_unit)]
1102            fn dangling() -> Self {
1103                ($($name::dangling(),)*)
1104            }
1105
1106            #[allow(unused_variables, unused_mut)]
1107            fn access(archetype: &Archetype) -> Option<Access> {
1108                let mut access = Access::Iterate;
1109                $(
1110                    access = access.max($name::access(archetype)?);
1111                )*
1112                Some(access)
1113            }
1114
1115            #[allow(unused_variables, non_snake_case, clippy::unused_unit)]
1116            fn borrow(archetype: &Archetype, state: Self::State) {
1117                let ($($name,)*) = state;
1118                $($name::borrow(archetype, $name);)*
1119            }
1120            #[allow(unused_variables)]
1121            #[cold]
1122            fn prepare(archetype: &Archetype) -> Option<Self::State> {
1123                Some(($($name::prepare(archetype)?,)*))
1124            }
1125            #[allow(unused_variables, non_snake_case, clippy::unused_unit)]
1126            #[inline(always)]
1127            fn execute(archetype: &Archetype, state: Self::State) -> Self {
1128                let ($($name,)*) = state;
1129                ($($name::execute(archetype, $name),)*)
1130            }
1131            #[allow(unused_variables, non_snake_case, clippy::unused_unit)]
1132            fn release(archetype: &Archetype, state: Self::State) {
1133                let ($($name,)*) = state;
1134                $($name::release(archetype, $name);)*
1135            }
1136
1137            #[allow(unused_variables, unused_mut, clippy::unused_unit)]
1138            fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
1139                $($name::for_each_borrow(&mut f);)*
1140            }
1141        }
1142
1143        impl<$($name: Query),*> Query for ($($name,)*) {
1144            type Item<'q> = ($($name::Item<'q>,)*);
1145
1146            type Fetch = ($($name::Fetch,)*);
1147
1148            #[allow(unused_variables, clippy::unused_unit)]
1149            unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
1150                #[allow(non_snake_case)]
1151                let ($(ref $name,)*) = *fetch;
1152                ($($name::get(meta, $name, n),)*)
1153            }
1154        }
1155
1156        unsafe impl<$($name: QueryShared),*> QueryShared for ($($name,)*) {}
1157    };
1158}
1159
1160//smaller_tuples_too!(tuple_impl, B, A);
1161smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
1162
1163/// A prepared query can be stored independently of the [`Substrate`] to fractionally reduce query
1164/// set-up costs.
1165///
1166/// Prepared queries are less convenient and usually do not measurably impact performance. Regular
1167/// queries should be preferred unless end-to-end performance measurements clearly indicate
1168/// otherwise.
1169pub struct PreparedQuery<Q: Query> {
1170    memo: (u64, u32),
1171    state: Box<[(usize, <Q::Fetch as Fetch>::State)]>,
1172    fetch: Box<[Option<Q::Fetch>]>,
1173}
1174
1175impl<Q: Query> Default for PreparedQuery<Q> {
1176    fn default() -> Self {
1177        Self::new()
1178    }
1179}
1180
1181impl<Q: Query> PreparedQuery<Q> {
1182    /// Create a prepared query which is not yet attached to any world
1183    pub fn new() -> Self {
1184        Self {
1185            // This memo will not match any world as the first ID will be 1.
1186            memo: (0, 0),
1187            state: Default::default(),
1188            fetch: Default::default(),
1189        }
1190    }
1191
1192    #[cold]
1193    fn prepare(world: &Substrate) -> Self {
1194        let memo = world.memo();
1195
1196        let state = world
1197            .archetypes()
1198            .enumerate()
1199            .filter_map(|(idx, x)| Q::Fetch::prepare(x).map(|state| (idx, state)))
1200            .collect();
1201
1202        let fetch = world.archetypes().map(|_| None).collect();
1203
1204        Self { memo, state, fetch }
1205    }
1206
1207    /// Query `world`, using dynamic borrow checking
1208    ///
1209    /// This will panic if it would violate an existing unique reference
1210    /// or construct an invalid unique reference.
1211    pub fn query<'q>(&'q mut self, world: &'q Substrate) -> PreparedQueryBorrow<'q, Q> {
1212        if self.memo != world.memo() {
1213            *self = Self::prepare(world);
1214        }
1215
1216        let meta = world.entities_meta();
1217        let archetypes = world.archetypes_inner();
1218
1219        PreparedQueryBorrow::new(meta, archetypes, &self.state, &mut self.fetch)
1220    }
1221
1222    /// Query a uniquely borrowed world
1223    ///
1224    /// Avoids the cost of the dynamic borrow checking performed by [`query`][Self::query].
1225    pub fn query_mut<'q>(&'q mut self, world: &'q mut Substrate) -> PreparedQueryIter<'q, Q> {
1226        assert_borrow::<Q>();
1227
1228        if self.memo != world.memo() {
1229            *self = Self::prepare(world);
1230        }
1231
1232        let meta = world.entities_meta();
1233        let archetypes = world.archetypes_inner();
1234
1235        unsafe { PreparedQueryIter::new(meta, archetypes, self.state.iter()) }
1236    }
1237
1238    /// Provide random access to query results for a uniquely borrow world
1239    pub fn view_mut<'q>(&'q mut self, world: &'q mut Substrate) -> PreparedView<'q, Q> {
1240        assert_borrow::<Q>();
1241
1242        if self.memo != world.memo() {
1243            *self = Self::prepare(world);
1244        }
1245
1246        let meta = world.entities_meta();
1247        let archetypes = world.archetypes_inner();
1248
1249        unsafe { PreparedView::new(meta, archetypes, self.state.iter(), &mut self.fetch) }
1250    }
1251}
1252
1253/// Combined borrow of a [`PreparedQuery`] and a [`Substrate`]
1254pub struct PreparedQueryBorrow<'q, Q: Query> {
1255    meta: &'q [EntityMeta],
1256    archetypes: &'q [Archetype],
1257    state: &'q [(usize, <Q::Fetch as Fetch>::State)],
1258    fetch: &'q mut [Option<Q::Fetch>],
1259}
1260
1261impl<'q, Q: Query> PreparedQueryBorrow<'q, Q> {
1262    fn new(
1263        meta: &'q [EntityMeta],
1264        archetypes: &'q [Archetype],
1265        state: &'q [(usize, <Q::Fetch as Fetch>::State)],
1266        fetch: &'q mut [Option<Q::Fetch>],
1267    ) -> Self {
1268        for (idx, state) in state {
1269            if archetypes[*idx].is_empty() {
1270                continue;
1271            }
1272            Q::Fetch::borrow(&archetypes[*idx], *state);
1273        }
1274
1275        Self {
1276            meta,
1277            archetypes,
1278            state,
1279            fetch,
1280        }
1281    }
1282
1283    /// Execute the prepared query
1284    // The lifetime narrowing here is required for soundness.
1285    pub fn iter(&mut self) -> PreparedQueryIter<'_, Q> {
1286        unsafe { PreparedQueryIter::new(self.meta, self.archetypes, self.state.iter()) }
1287    }
1288
1289    /// Provides random access to the results of the prepared query
1290    pub fn view(&mut self) -> PreparedView<'_, Q> {
1291        unsafe { PreparedView::new(self.meta, self.archetypes, self.state.iter(), self.fetch) }
1292    }
1293}
1294
1295impl<Q: Query> Drop for PreparedQueryBorrow<'_, Q> {
1296    fn drop(&mut self) {
1297        for (idx, state) in self.state {
1298            if self.archetypes[*idx].is_empty() {
1299                continue;
1300            }
1301            Q::Fetch::release(&self.archetypes[*idx], *state);
1302        }
1303    }
1304}
1305
1306/// Iterates over all entities matching a [`PreparedQuery`]
1307pub struct PreparedQueryIter<'q, Q: Query> {
1308    meta: &'q [EntityMeta],
1309    archetypes: &'q [Archetype],
1310    state: SliceIter<'q, (usize, <Q::Fetch as Fetch>::State)>,
1311    iter: ChunkIter<Q>,
1312}
1313
1314impl<'q, Q: Query> PreparedQueryIter<'q, Q> {
1315    /// # Safety
1316    ///
1317    /// `'q` must be sufficient to guarantee that `Q` cannot violate borrow safety, either with
1318    /// dynamic borrow checks or by representing exclusive access to the `Substrate`.
1319    unsafe fn new(
1320        meta: &'q [EntityMeta],
1321        archetypes: &'q [Archetype],
1322        state: SliceIter<'q, (usize, <Q::Fetch as Fetch>::State)>,
1323    ) -> Self {
1324        Self {
1325            meta,
1326            archetypes,
1327            state,
1328            iter: ChunkIter::empty(),
1329        }
1330    }
1331}
1332
1333unsafe impl<Q: Query> Send for PreparedQueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
1334unsafe impl<Q: Query> Sync for PreparedQueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
1335
1336impl<'q, Q: Query> Iterator for PreparedQueryIter<'q, Q> {
1337    type Item = Q::Item<'q>;
1338
1339    #[inline(always)]
1340    fn next(&mut self) -> Option<Self::Item> {
1341        loop {
1342            match unsafe { self.iter.next(self.meta) } {
1343                None => {
1344                    let (idx, state) = self.state.next()?;
1345                    let archetype = &self.archetypes[*idx];
1346                    self.iter = ChunkIter::new(archetype, Q::Fetch::execute(archetype, *state));
1347                    continue;
1348                }
1349                Some(components) => {
1350                    return Some(components);
1351                }
1352            }
1353        }
1354    }
1355
1356    fn size_hint(&self) -> (usize, Option<usize>) {
1357        let n = self.len();
1358        (n, Some(n))
1359    }
1360}
1361
1362impl<Q: Query> ExactSizeIterator for PreparedQueryIter<'_, Q> {
1363    fn len(&self) -> usize {
1364        self.state
1365            .clone()
1366            .map(|(idx, _)| self.archetypes[*idx].len() as usize)
1367            .sum::<usize>()
1368            + self.iter.remaining()
1369    }
1370}
1371
1372/// Provides random access to the results of a query
1373///
1374/// Views borrow all components that they expose, from when the view is created until it's
1375/// dropped. As with any borrowing pattern, they should usually be short-lived to avoid conflicts
1376/// with distant code that might want to borrow the same components.
1377pub struct View<'q, Q: Query> {
1378    meta: &'q [EntityMeta],
1379    archetypes: &'q [Archetype],
1380    fetch: Box<[Option<Q::Fetch>]>,
1381}
1382
1383unsafe impl<Q: Query> Send for View<'_, Q> where for<'a> Q::Item<'a>: Send {}
1384unsafe impl<Q: Query> Sync for View<'_, Q> where for<'a> Q::Item<'a>: Send {}
1385
1386impl<'q, Q: Query> View<'q, Q> {
1387    /// # Safety
1388    ///
1389    /// `'q` must be sufficient to guarantee that `Q` cannot violate borrow safety, either with
1390    /// dynamic borrow checks or by representing exclusive access to the `Substrate`.
1391    pub(crate) unsafe fn new(
1392        meta: &'q [EntityMeta],
1393        archetypes: &'q [Archetype],
1394        cache: CachedQuery<Q::Fetch>,
1395    ) -> Self {
1396        Self {
1397            meta,
1398            archetypes,
1399            fetch: cache.fetch_all(archetypes),
1400        }
1401    }
1402
1403    /// Retrieve the query results corresponding to `entity`
1404    ///
1405    /// Will yield `None` if the entity does not exist or does not match the query.
1406    ///
1407    /// Does not require exclusive access to the map, but is defined only for queries yielding only shared references.
1408    pub fn get(&self, entity: Entity) -> Option<Q::Item<'_>>
1409    where
1410        Q: QueryShared,
1411    {
1412        let meta = self.meta.get(entity.id as usize)?;
1413        if meta.generation != entity.generation {
1414            return None;
1415        }
1416
1417        self.fetch[meta.location.archetype as usize]
1418            .as_ref()
1419            .map(|fetch| unsafe { Q::get(self.meta, fetch, meta.location.index as usize) })
1420    }
1421
1422    /// Retrieve the query results corresponding to `entity`
1423    ///
1424    /// Will yield `None` if the entity does not exist or does not match the query.
1425    pub fn get_mut(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
1426        unsafe { self.get_unchecked(entity) }
1427    }
1428
1429    /// Equivalent to `get(entity).is_some()`, but does not require `Q: QueryShared`
1430    pub fn contains(&self, entity: Entity) -> bool {
1431        let Some(meta) = self.meta.get(entity.id as usize) else {
1432            return false;
1433        };
1434        if meta.generation != entity.generation {
1435            return false;
1436        }
1437        self.fetch[meta.location.archetype as usize].is_some()
1438    }
1439
1440    /// Like `get_mut`, but allows simultaneous access to multiple entities
1441    ///
1442    /// # Safety
1443    ///
1444    /// Must not be invoked while any unique borrow of the fetched components of `entity` is live.
1445    pub unsafe fn get_unchecked(&self, entity: Entity) -> Option<Q::Item<'_>> {
1446        let meta = self.meta.get(entity.id as usize)?;
1447        if meta.generation != entity.generation {
1448            return None;
1449        }
1450
1451        self.fetch[meta.location.archetype as usize]
1452            .as_ref()
1453            .map(|fetch| Q::get(self.meta, fetch, meta.location.index as usize))
1454    }
1455
1456    /// Like `get_mut`, but allows checked simultaneous access to multiple entities
1457    ///
1458    /// For N > 3, the check for distinct entities will clone the array and take O(N log N) time.
1459    ///
1460    /// # Examples
1461    ///
1462    /// ```
1463    /// # use ecsx::Substrate;
1464    /// let mut world = Substrate::new();
1465    ///
1466    /// let a = world.spawn((1, 1.0));
1467    /// let b = world.spawn((2, 4.0));
1468    /// let c = world.spawn((3, 9.0));
1469    ///
1470    /// let mut query = world.query_mut::<&mut i32>();
1471    /// let mut view = query.view();
1472    /// let [a,b,c] = view.get_disjoint_mut([a, b, c]);
1473    ///
1474    /// assert_eq!(*a.unwrap(), 1);
1475    /// assert_eq!(*b.unwrap(), 2);
1476    /// assert_eq!(*c.unwrap(), 3);
1477    /// ```
1478    pub fn get_disjoint_mut<const N: usize>(
1479        &mut self,
1480        entities: [Entity; N],
1481    ) -> [Option<Q::Item<'_>>; N] {
1482        assert_distinct(&entities);
1483
1484        let mut items = [(); N].map(|()| None);
1485
1486        for (item, entity) in items.iter_mut().zip(entities) {
1487            unsafe {
1488                *item = self.get_unchecked(entity);
1489            }
1490        }
1491
1492        items
1493    }
1494
1495    #[doc(hidden)]
1496    #[deprecated(since = "0.11.0", note = "renamed to `get_disjoint_mut`")]
1497    pub fn get_many_mut<const N: usize>(
1498        &mut self,
1499        entities: [Entity; N],
1500    ) -> [Option<Q::Item<'_>>; N] {
1501        self.get_disjoint_mut(entities)
1502    }
1503
1504    /// Iterate over all entities satisfying `Q`
1505    ///
1506    /// Equivalent to [`QueryBorrow::iter`].
1507    pub fn iter_mut(&mut self) -> ViewIter<'_, Q> {
1508        ViewIter {
1509            meta: self.meta,
1510            archetypes: self.archetypes.iter(),
1511            fetches: self.fetch.iter(),
1512            iter: ChunkIter::empty(),
1513        }
1514    }
1515}
1516
1517impl<'a, Q: Query> IntoIterator for &'a mut View<'_, Q> {
1518    type IntoIter = ViewIter<'a, Q>;
1519    type Item = Q::Item<'a>;
1520
1521    #[inline]
1522    fn into_iter(self) -> Self::IntoIter {
1523        self.iter_mut()
1524    }
1525}
1526
1527pub struct ViewIter<'a, Q: Query> {
1528    meta: &'a [EntityMeta],
1529    archetypes: SliceIter<'a, Archetype>,
1530    fetches: SliceIter<'a, Option<Q::Fetch>>,
1531    iter: ChunkIter<Q>,
1532}
1533
1534impl<'a, Q: Query> Iterator for ViewIter<'a, Q> {
1535    type Item = Q::Item<'a>;
1536
1537    #[inline(always)]
1538    fn next(&mut self) -> Option<Self::Item> {
1539        loop {
1540            match unsafe { self.iter.next(self.meta) } {
1541                None => {
1542                    let archetype = self.archetypes.next()?;
1543                    let fetch = self.fetches.next()?;
1544                    self.iter = fetch
1545                        .clone()
1546                        .map_or(ChunkIter::empty(), |fetch| ChunkIter::new(archetype, fetch));
1547                    continue;
1548                }
1549                Some(components) => {
1550                    return Some(components);
1551                }
1552            }
1553        }
1554    }
1555}
1556
1557/// Provides random access to the results of a prepared query
1558pub struct PreparedView<'q, Q: Query> {
1559    meta: &'q [EntityMeta],
1560    archetypes: &'q [Archetype],
1561    fetch: &'q mut [Option<Q::Fetch>],
1562}
1563
1564unsafe impl<Q: Query> Send for PreparedView<'_, Q> where for<'a> Q::Item<'a>: Send {}
1565unsafe impl<Q: Query> Sync for PreparedView<'_, Q> where for<'a> Q::Item<'a>: Send {}
1566
1567impl<'q, Q: Query> PreparedView<'q, Q> {
1568    /// # Safety
1569    ///
1570    /// `'q` must be sufficient to guarantee that `Q` cannot violate borrow safety, either with
1571    /// dynamic borrow checks or by representing exclusive access to the `Substrate`.
1572    unsafe fn new(
1573        meta: &'q [EntityMeta],
1574        archetypes: &'q [Archetype],
1575        state: SliceIter<'q, (usize, <Q::Fetch as Fetch>::State)>,
1576        fetch: &'q mut [Option<Q::Fetch>],
1577    ) -> Self {
1578        fetch.iter_mut().for_each(|fetch| *fetch = None);
1579
1580        for (idx, state) in state {
1581            let archetype = &archetypes[*idx];
1582            fetch[*idx] = Some(Q::Fetch::execute(archetype, *state));
1583        }
1584
1585        Self {
1586            meta,
1587            archetypes,
1588            fetch,
1589        }
1590    }
1591
1592    /// Retrieve the query results corresponding to `entity`
1593    ///
1594    /// Will yield `None` if the entity does not exist or does not match the query.
1595    ///
1596    /// Does not require exclusive access to the map, but is defined only for queries yielding only shared references.
1597    pub fn get(&self, entity: Entity) -> Option<Q::Item<'_>>
1598    where
1599        Q: QueryShared,
1600    {
1601        let meta = self.meta.get(entity.id as usize)?;
1602        if meta.generation != entity.generation {
1603            return None;
1604        }
1605
1606        self.fetch[meta.location.archetype as usize]
1607            .as_ref()
1608            .map(|fetch| unsafe { Q::get(self.meta, fetch, meta.location.index as usize) })
1609    }
1610
1611    /// Retrieve the query results corresponding to `entity`
1612    ///
1613    /// Will yield `None` if the entity does not exist or does not match the query.
1614    pub fn get_mut(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
1615        unsafe { self.get_unchecked(entity) }
1616    }
1617
1618    /// Equivalent to `get(entity).is_some()`, but does not require `Q: QueryShared`
1619    pub fn contains(&self, entity: Entity) -> bool {
1620        let Some(meta) = self.meta.get(entity.id as usize) else {
1621            return false;
1622        };
1623        if meta.generation != entity.generation {
1624            return false;
1625        }
1626        self.fetch[meta.location.archetype as usize].is_some()
1627    }
1628
1629    /// Like `get_mut`, but allows simultaneous access to multiple entities
1630    ///
1631    /// # Safety
1632    ///
1633    /// Must not be invoked while any unique borrow of the fetched components of `entity` is live.
1634    pub unsafe fn get_unchecked(&self, entity: Entity) -> Option<Q::Item<'_>> {
1635        let meta = self.meta.get(entity.id as usize)?;
1636        if meta.generation != entity.generation {
1637            return None;
1638        }
1639
1640        self.fetch[meta.location.archetype as usize]
1641            .as_ref()
1642            .map(|fetch| Q::get(self.meta, fetch, meta.location.index as usize))
1643    }
1644
1645    /// Like `get_mut`, but allows checked simultaneous access to multiple entities
1646    ///
1647    /// See [`View::get_disjoint_mut`] for details.
1648    pub fn get_disjoint_mut<const N: usize>(
1649        &mut self,
1650        entities: [Entity; N],
1651    ) -> [Option<Q::Item<'_>>; N] {
1652        assert_distinct(&entities);
1653
1654        let mut items = [(); N].map(|()| None);
1655
1656        for (item, entity) in items.iter_mut().zip(entities) {
1657            unsafe {
1658                *item = self.get_unchecked(entity);
1659            }
1660        }
1661
1662        items
1663    }
1664
1665    #[doc(hidden)]
1666    #[deprecated(since = "0.11.0", note = "renamed to `get_disjoint_mut`")]
1667    pub fn get_many_mut<const N: usize>(
1668        &mut self,
1669        entities: [Entity; N],
1670    ) -> [Option<Q::Item<'_>>; N] {
1671        self.get_disjoint_mut(entities)
1672    }
1673
1674    /// Iterate over all entities satisfying `Q`
1675    ///
1676    /// Equivalent to [`PreparedQueryBorrow::iter`].
1677    pub fn iter_mut(&mut self) -> ViewIter<'_, Q> {
1678        ViewIter {
1679            meta: self.meta,
1680            archetypes: self.archetypes.iter(),
1681            fetches: self.fetch.iter(),
1682            iter: ChunkIter::empty(),
1683        }
1684    }
1685}
1686
1687impl<'a, Q: Query> IntoIterator for &'a mut PreparedView<'_, Q> {
1688    type IntoIter = ViewIter<'a, Q>;
1689    type Item = Q::Item<'a>;
1690
1691    #[inline]
1692    fn into_iter(self) -> Self::IntoIter {
1693        self.iter_mut()
1694    }
1695}
1696
1697/// A borrow of a [`Substrate`](crate::Substrate) sufficient to random-access the results of the query `Q`.
1698///
1699/// Note that borrows are not released until this object is dropped.
1700///
1701/// This struct is a thin wrapper around [`View`]. See it for more documentation.
1702pub struct ViewBorrow<'w, Q: Query> {
1703    view: View<'w, Q>,
1704    cache: CachedQuery<Q::Fetch>,
1705}
1706
1707impl<'w, Q: Query> ViewBorrow<'w, Q> {
1708    pub(crate) fn new(world: &'w Substrate) -> Self {
1709        let cache = CachedQuery::get(world);
1710        cache.borrow(world.archetypes_inner());
1711        let view = unsafe {
1712            View::<Q>::new(
1713                world.entities_meta(),
1714                world.archetypes_inner(),
1715                cache.clone(),
1716            )
1717        };
1718
1719        Self { view, cache }
1720    }
1721
1722    /// Retrieve the query results corresponding to `entity`
1723    ///
1724    /// Will yield `None` if the entity does not exist or does not match the query.
1725    ///
1726    /// Does not require exclusive access to the map, but is defined only for queries yielding only shared references.
1727    ///
1728    /// See [`View::get``].
1729    pub fn get(&self, entity: Entity) -> Option<Q::Item<'_>>
1730    where
1731        Q: QueryShared,
1732    {
1733        self.view.get(entity)
1734    }
1735
1736    /// Retrieve the query results corresponding to `entity`
1737    ///
1738    /// Will yield `None` if the entity does not exist or does not match the query.
1739    ///
1740    /// See [`View::get_mut``].
1741    pub fn get_mut(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
1742        self.view.get_mut(entity)
1743    }
1744
1745    /// Equivalent to `get(entity).is_some()`, but does not require `Q: QueryShared`
1746    ///
1747    /// See [`View::contains``].
1748    pub fn contains(&self, entity: Entity) -> bool {
1749        self.view.contains(entity)
1750    }
1751
1752    /// Like `get_mut`, but allows simultaneous access to multiple entities
1753    ///
1754    /// See [`View::get_unchecked``].
1755    ///
1756    /// # Safety
1757    ///
1758    /// Must not be invoked while any unique borrow of the fetched components of `entity` is live.
1759    pub unsafe fn get_unchecked(&self, entity: Entity) -> Option<Q::Item<'_>> {
1760        self.view.get_unchecked(entity)
1761    }
1762
1763    /// Like `get_mut`, but allows checked simultaneous access to multiple entities
1764    ///
1765    /// For N > 3, the check for distinct entities will clone the array and take O(N log N) time.
1766    ///
1767    /// See [`View::get_disjoint_mut``].
1768    ///
1769    /// # Examples
1770    ///
1771    /// ```
1772    /// # use ecsx::Substrate;
1773    /// let mut world = Substrate::new();
1774    ///
1775    /// let a = world.spawn((1, 1.0));
1776    /// let b = world.spawn((2, 4.0));
1777    /// let c = world.spawn((3, 9.0));
1778    ///
1779    /// let mut view = world.view_mut::<&mut i32>();
1780    /// let [a, b, c] = view.get_disjoint_mut([a, b, c]);
1781    ///
1782    /// assert_eq!(*a.unwrap(), 1);
1783    /// assert_eq!(*b.unwrap(), 2);
1784    /// assert_eq!(*c.unwrap(), 3);
1785    /// ```
1786    pub fn get_disjoint_mut<const N: usize>(
1787        &mut self,
1788        entities: [Entity; N],
1789    ) -> [Option<Q::Item<'_>>; N] {
1790        self.view.get_disjoint_mut(entities)
1791    }
1792
1793    #[doc(hidden)]
1794    #[deprecated(since = "0.11.0", note = "renamed to `get_disjoint_mut`")]
1795    pub fn get_many_mut<const N: usize>(
1796        &mut self,
1797        entities: [Entity; N],
1798    ) -> [Option<Q::Item<'_>>; N] {
1799        self.view.get_disjoint_mut(entities)
1800    }
1801
1802    /// Iterate over all entities satisfying `Q`
1803    ///
1804    /// See [`View::iter_mut``]
1805    pub fn iter_mut(&mut self) -> ViewIter<'_, Q> {
1806        self.view.iter_mut()
1807    }
1808}
1809
1810impl<Q: Query> Drop for ViewBorrow<'_, Q> {
1811    fn drop(&mut self) {
1812        self.cache.release_borrow(self.view.archetypes);
1813    }
1814}
1815
1816impl<'a, Q: Query> IntoIterator for &'a mut ViewBorrow<'_, Q> {
1817    type IntoIter = ViewIter<'a, Q>;
1818    type Item = Q::Item<'a>;
1819
1820    #[inline]
1821    fn into_iter(self) -> Self::IntoIter {
1822        self.iter_mut()
1823    }
1824}
1825
1826pub(crate) fn assert_distinct<const N: usize>(entities: &[Entity; N]) {
1827    match N {
1828        1 => (),
1829        2 => assert_ne!(entities[0], entities[1]),
1830        3 => {
1831            assert_ne!(entities[0], entities[1]);
1832            assert_ne!(entities[1], entities[2]);
1833            assert_ne!(entities[2], entities[0]);
1834        }
1835        _ => {
1836            let mut entities = *entities;
1837            entities.sort_unstable();
1838            for index in 0..N - 1 {
1839                assert_ne!(entities[index], entities[index + 1]);
1840            }
1841        }
1842    }
1843}
1844
1845#[cfg(feature = "std")]
1846pub(crate) type QueryCache = RwLock<TypeIdMap<Arc<dyn Any + Send + Sync>>>;
1847
1848#[cfg(feature = "std")]
1849struct CachedQueryInner<F: Fetch> {
1850    state: Box<[(usize, F::State)]>,
1851    // In theory we could drop the cache eagerly when invalidated rather than tracking this, but
1852    // this is harder to screw up.
1853    archetypes_generation: crate::ArchetypesGeneration,
1854}
1855
1856#[cfg(feature = "std")]
1857impl<F: Fetch> CachedQueryInner<F> {
1858    fn new(world: &Substrate) -> Self {
1859        Self {
1860            state: world
1861                .archetypes()
1862                .enumerate()
1863                .filter_map(|(idx, x)| F::prepare(x).map(|state| (idx, state)))
1864                .collect(),
1865            archetypes_generation: world.archetypes_generation(),
1866        }
1867    }
1868}
1869
1870pub(crate) struct CachedQuery<F: Fetch> {
1871    #[cfg(feature = "std")]
1872    inner: Arc<CachedQueryInner<F>>,
1873    #[cfg(not(feature = "std"))]
1874    _marker: PhantomData<F>,
1875}
1876
1877impl<F: Fetch> CachedQuery<F> {
1878    pub(crate) fn get(world: &Substrate) -> Self {
1879        #[cfg(feature = "std")]
1880        {
1881            let existing_cache = world
1882                .query_cache()
1883                .read()
1884                .unwrap()
1885                .get(&TypeId::of::<F>())
1886                .map(|x| Arc::downcast::<CachedQueryInner<F>>(x.clone()).unwrap())
1887                .filter(|x| x.archetypes_generation == world.archetypes_generation());
1888            let inner = existing_cache.unwrap_or_else(
1889                #[cold]
1890                || {
1891                    let mut cache = world.query_cache().write().unwrap();
1892                    let entry = cache.entry(TypeId::of::<F>());
1893                    let cached = match entry {
1894                        hash_map::Entry::Vacant(e) => {
1895                            let fresh = Arc::new(CachedQueryInner::<F>::new(world));
1896                            e.insert(fresh.clone());
1897                            fresh
1898                        }
1899                        hash_map::Entry::Occupied(mut e) => {
1900                            let value =
1901                                Arc::downcast::<CachedQueryInner<F>>(e.get().clone()).unwrap();
1902                            match value.archetypes_generation == world.archetypes_generation() {
1903                                false => {
1904                                    let fresh = Arc::new(CachedQueryInner::<F>::new(world));
1905                                    e.insert(fresh.clone());
1906                                    fresh
1907                                }
1908                                true => value,
1909                            }
1910                        }
1911                    };
1912                    cached
1913                },
1914            );
1915            Self { inner }
1916        }
1917        #[cfg(not(feature = "std"))]
1918        {
1919            _ = world;
1920            Self {
1921                _marker: PhantomData,
1922            }
1923        }
1924    }
1925
1926    fn archetype_count(&self, archetypes: &[Archetype]) -> usize {
1927        #[cfg(feature = "std")]
1928        {
1929            _ = archetypes;
1930            self.inner.state.len()
1931        }
1932        #[cfg(not(feature = "std"))]
1933        {
1934            archetypes.len()
1935        }
1936    }
1937
1938    /// Returns `None` if this index should be skipped.
1939    ///
1940    /// # Safety
1941    /// - `index` must be <= the value returned by `archetype_count`
1942    /// - `archetypes` must match that passed to `archetype_count` and the world passed to `get`
1943    unsafe fn get_state<'a>(
1944        &self,
1945        archetypes: &'a [Archetype],
1946        index: usize,
1947    ) -> Option<(&'a Archetype, F::State)> {
1948        #[cfg(feature = "std")]
1949        unsafe {
1950            let &(archetype, state) = self.inner.state.get_unchecked(index);
1951            let archetype = archetypes.get_unchecked(archetype);
1952            Some((archetype, state))
1953        }
1954        #[cfg(not(feature = "std"))]
1955        {
1956            let archetype = unsafe { archetypes.get_unchecked(index) };
1957            let state = F::prepare(archetype)?;
1958            Some((archetype, state))
1959        }
1960    }
1961
1962    /// Returns `None` if this index should be skipped.
1963    ///
1964    /// # Safety
1965    /// - `index` must be <= the value returned by `archetype_count`
1966    /// - `archetypes` must match that passed to `archetype_count` and the world passed to `get`
1967    unsafe fn get_archetype<'a>(
1968        &self,
1969        archetypes: &'a [Archetype],
1970        index: usize,
1971    ) -> Option<&'a Archetype> {
1972        #[cfg(feature = "std")]
1973        unsafe {
1974            let &(archetype, _) = self.inner.state.get_unchecked(index);
1975            let archetype = archetypes.get_unchecked(archetype);
1976            Some(archetype)
1977        }
1978        #[cfg(not(feature = "std"))]
1979        {
1980            let x = unsafe { archetypes.get_unchecked(index) };
1981            if F::access(x).is_none() {
1982                return None;
1983            }
1984            Some(x)
1985        }
1986    }
1987
1988    fn borrow(&self, archetypes: &[Archetype]) {
1989        #[cfg(feature = "std")]
1990        {
1991            for &(archetype, state) in &self.inner.state {
1992                let archetype = unsafe { archetypes.get_unchecked(archetype) };
1993                if archetype.is_empty() {
1994                    continue;
1995                }
1996                F::borrow(archetype, state);
1997            }
1998        }
1999
2000        #[cfg(not(feature = "std"))]
2001        {
2002            for x in archetypes {
2003                if x.is_empty() {
2004                    continue;
2005                }
2006                // TODO: Release prior borrows on failure?
2007                if let Some(state) = F::prepare(x) {
2008                    F::borrow(x, state);
2009                }
2010            }
2011        }
2012    }
2013
2014    fn release_borrow(&self, archetypes: &[Archetype]) {
2015        #[cfg(feature = "std")]
2016        {
2017            for &(archetype, state) in &self.inner.state {
2018                let archetype = unsafe { archetypes.get_unchecked(archetype) };
2019                if archetype.is_empty() {
2020                    continue;
2021                }
2022                F::release(archetype, state);
2023            }
2024        }
2025
2026        #[cfg(not(feature = "std"))]
2027        {
2028            for x in archetypes {
2029                if x.is_empty() {
2030                    continue;
2031                }
2032                if let Some(state) = F::prepare(x) {
2033                    F::release(x, state);
2034                }
2035            }
2036        }
2037    }
2038
2039    fn fetch_all(&self, archetypes: &[Archetype]) -> Box<[Option<F>]> {
2040        #[cfg(feature = "std")]
2041        {
2042            let mut fetch = (0..archetypes.len()).map(|_| None).collect::<Box<[_]>>();
2043            for &(archetype_index, state) in &self.inner.state {
2044                let archetype = &archetypes[archetype_index];
2045                fetch[archetype_index] = Some(F::execute(archetype, state));
2046            }
2047            fetch
2048        }
2049        #[cfg(not(feature = "std"))]
2050        {
2051            archetypes
2052                .iter()
2053                .map(|archetype| F::prepare(archetype).map(|state| F::execute(archetype, state)))
2054                .collect()
2055        }
2056    }
2057}
2058
2059impl<F: Fetch> Clone for CachedQuery<F> {
2060    fn clone(&self) -> Self {
2061        Self {
2062            #[cfg(feature = "std")]
2063            inner: self.inner.clone(),
2064            #[cfg(not(feature = "std"))]
2065            _marker: PhantomData,
2066        }
2067    }
2068}
2069
2070struct ArchetypeIter<Q: Query> {
2071    archetypes: core::ops::Range<usize>,
2072    cache: CachedQuery<Q::Fetch>,
2073}
2074
2075impl<Q: Query> ArchetypeIter<Q> {
2076    fn new(world: &Substrate, cache: CachedQuery<Q::Fetch>) -> Self {
2077        Self {
2078            archetypes: 0..cache.archetype_count(world.archetypes_inner()),
2079            cache,
2080        }
2081    }
2082
2083    /// Safety: `world` must be the same as passed to `new`
2084    unsafe fn next(&mut self, world: &Substrate) -> Option<ChunkIter<Q>> {
2085        loop {
2086            let Some((archetype, state)) = self
2087                .cache
2088                .get_state(world.archetypes_inner(), self.archetypes.next()?)
2089            else {
2090                continue;
2091            };
2092            let fetch = Q::Fetch::execute(archetype, state);
2093            return Some(ChunkIter::new(archetype, fetch));
2094        }
2095    }
2096
2097    fn entity_len(&self, world: &Substrate) -> usize {
2098        self.archetypes
2099            .clone()
2100            .filter_map(|x| unsafe { self.cache.get_archetype(world.archetypes_inner(), x) })
2101            .map(|x| x.len() as usize)
2102            .sum()
2103    }
2104}
2105
2106#[cfg(test)]
2107mod tests;