1use std::any::TypeId;
4use std::marker::PhantomData;
5use std::ops::{Deref, DerefMut};
6
7use crate::archetype::{Archetype, ArchetypeLayout, ArchetypeStore, Column};
8use crate::component::Component;
9use crate::entity::Entity;
10
11pub struct Mut<'w, T> {
24 value: &'w mut T,
25 changed_tick: *mut u64,
26 tick: u64,
27}
28
29impl<T> Mut<'_, T> {
30 pub fn set_changed(&mut self) {
36 unsafe {
38 *self.changed_tick = self.tick;
39 }
40 }
41}
42
43impl<T> Deref for Mut<'_, T> {
44 type Target = T;
45 fn deref(&self) -> &T {
46 self.value
47 }
48}
49
50impl<T> DerefMut for Mut<'_, T> {
51 fn deref_mut(&mut self) -> &mut T {
52 unsafe {
56 *self.changed_tick = self.tick;
57 }
58 self.value
59 }
60}
61
62pub trait QuerySpec {
64 type Item<'w>;
65
66 type State<'w>;
67
68 fn matches(layout: &ArchetypeLayout) -> bool;
69
70 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>>;
71
72 fn len(state: &Self::State<'_>) -> usize;
73
74 fn entity(state: &Self::State<'_>, row: usize) -> Entity;
75
76 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w>;
77}
78
79pub trait QuerySpecMut {
81 type Item<'w>;
82
83 type State<'w>;
84
85 fn matches(layout: &ArchetypeLayout) -> bool;
86
87 fn init_state<'w>(archetype: &'w mut Archetype, tick: u64) -> Option<Self::State<'w>>;
88
89 fn len(state: &Self::State<'_>) -> usize;
90
91 fn entity(state: &Self::State<'_>, row: usize) -> Entity;
92
93 unsafe fn fetch<'w>(state: &mut Self::State<'w>, row: usize) -> Self::Item<'w>;
99}
100
101pub trait QueryFilter {
103 fn matches(layout: &ArchetypeLayout) -> bool;
104}
105
106pub struct NoFilter;
108
109impl QueryFilter for NoFilter {
110 fn matches(_layout: &ArchetypeLayout) -> bool {
111 true
112 }
113}
114
115pub struct With<T>(PhantomData<T>);
117
118impl<T: Component> QueryFilter for With<T> {
119 fn matches(layout: &ArchetypeLayout) -> bool {
120 layout.contains(TypeId::of::<T>())
121 }
122}
123
124pub struct Without<T>(PhantomData<T>);
126
127impl<T: Component> QueryFilter for Without<T> {
128 fn matches(layout: &ArchetypeLayout) -> bool {
129 !layout.contains(TypeId::of::<T>())
130 }
131}
132
133impl<A, B> QueryFilter for (A, B)
134where
135 A: QueryFilter,
136 B: QueryFilter,
137{
138 fn matches(layout: &ArchetypeLayout) -> bool {
139 A::matches(layout) && B::matches(layout)
140 }
141}
142
143impl<A, B, C> QueryFilter for (A, B, C)
144where
145 A: QueryFilter,
146 B: QueryFilter,
147 C: QueryFilter,
148{
149 fn matches(layout: &ArchetypeLayout) -> bool {
150 A::matches(layout) && B::matches(layout) && C::matches(layout)
151 }
152}
153
154pub struct QueryIter<'w, Q, F = NoFilter>
156where
157 Q: QuerySpec,
158 F: QueryFilter,
159{
160 store: &'w ArchetypeStore,
161 archetype_index: usize,
162 row: usize,
163 current: Option<Q::State<'w>>,
164 _filter: PhantomData<F>,
165}
166
167impl<'w, Q, F> QueryIter<'w, Q, F>
168where
169 Q: QuerySpec,
170 F: QueryFilter,
171{
172 pub(crate) fn new(store: &'w ArchetypeStore) -> Self {
173 Self {
174 store,
175 archetype_index: 0,
176 row: 0,
177 current: None,
178 _filter: PhantomData,
179 }
180 }
181
182 fn remaining(&self) -> usize {
183 let current = self
184 .current
185 .as_ref()
186 .map_or(0, |state| Q::len(state) - self.row);
187 let future: usize = self
188 .store
189 .iter()
190 .skip(self.archetype_index)
191 .filter(|archetype| Q::matches(archetype.layout()) && F::matches(archetype.layout()))
192 .map(|archetype| archetype.len())
193 .sum();
194 current + future
195 }
196}
197
198impl<'w, Q, F> Iterator for QueryIter<'w, Q, F>
199where
200 Q: QuerySpec + 'w,
201 F: QueryFilter,
202{
203 type Item = (Entity, Q::Item<'w>);
204
205 fn next(&mut self) -> Option<Self::Item> {
206 loop {
207 if let Some(state) = self.current.as_ref() {
208 if self.row < Q::len(state) {
209 let row = self.row;
210 self.row += 1;
211 return Some((Q::entity(state, row), Q::fetch(state, row)));
212 }
213 self.current = None;
214 }
215
216 let archetype = self.store.get_by_index(self.archetype_index)?;
217 self.archetype_index += 1;
218
219 if !Q::matches(archetype.layout()) || !F::matches(archetype.layout()) {
220 continue;
221 }
222
223 self.current = Q::init_state(archetype);
224 self.row = 0;
225 }
226 }
227
228 fn size_hint(&self) -> (usize, Option<usize>) {
229 let remaining = self.remaining();
230 (remaining, Some(remaining))
231 }
232}
233
234impl<'w, Q, F> ExactSizeIterator for QueryIter<'w, Q, F>
235where
236 Q: QuerySpec + 'w,
237 F: QueryFilter,
238{
239 fn len(&self) -> usize {
240 self.remaining()
241 }
242}
243
244pub struct QueryIterMut<'w, Q, F = NoFilter>
246where
247 Q: QuerySpecMut,
248 F: QueryFilter,
249{
250 store: *mut ArchetypeStore,
251 archetype_len: usize,
252 archetype_index: usize,
253 row: usize,
254 tick: u64,
255 current: Option<Q::State<'w>>,
256 _filter: PhantomData<F>,
257 _marker: PhantomData<&'w mut ArchetypeStore>,
258}
259
260impl<'w, Q, F> QueryIterMut<'w, Q, F>
261where
262 Q: QuerySpecMut,
263 F: QueryFilter,
264{
265 pub(crate) fn new(store: &'w mut ArchetypeStore, tick: u64) -> Self {
266 Self {
267 archetype_len: store.len(),
268 store,
269 archetype_index: 0,
270 row: 0,
271 tick,
272 current: None,
273 _filter: PhantomData,
274 _marker: PhantomData,
275 }
276 }
277
278 pub(crate) unsafe fn new_from_ptr(store: *mut ArchetypeStore, tick: u64) -> Self {
292 Self {
293 archetype_len: unsafe { (*store).len() },
294 store,
295 archetype_index: 0,
296 row: 0,
297 tick,
298 current: None,
299 _filter: PhantomData,
300 _marker: PhantomData,
301 }
302 }
303
304 fn remaining(&self) -> usize {
305 let current = self
306 .current
307 .as_ref()
308 .map_or(0, |state| Q::len(state) - self.row);
309 let future: usize = unsafe { &*self.store }
312 .iter()
313 .skip(self.archetype_index)
314 .filter(|archetype| Q::matches(archetype.layout()) && F::matches(archetype.layout()))
315 .map(|archetype| archetype.len())
316 .sum();
317 current + future
318 }
319}
320
321impl<'w, Q, F> Iterator for QueryIterMut<'w, Q, F>
322where
323 Q: QuerySpecMut + 'w,
324 F: QueryFilter,
325{
326 type Item = (Entity, Q::Item<'w>);
327
328 fn next(&mut self) -> Option<Self::Item> {
329 loop {
330 if let Some(state) = self.current.as_mut() {
331 if self.row < Q::len(state) {
332 let row = self.row;
333 self.row += 1;
334 let entity = Q::entity(state, row);
335 let item = unsafe { Q::fetch(state, row) };
343 return Some((entity, item));
344 }
345 self.current = None;
346 }
347
348 if self.archetype_index >= self.archetype_len {
349 return None;
350 }
351
352 let archetype =
367 unsafe { ArchetypeStore::get_by_index_mut_ptr(self.store, self.archetype_index)? };
368 self.archetype_index += 1;
369
370 if !Q::matches(archetype.layout()) || !F::matches(archetype.layout()) {
371 continue;
372 }
373
374 self.current = Q::init_state(archetype, self.tick);
375 self.row = 0;
376 }
377 }
378
379 fn size_hint(&self) -> (usize, Option<usize>) {
380 let remaining = self.remaining();
381 (remaining, Some(remaining))
382 }
383}
384
385impl<'w, Q, F> ExactSizeIterator for QueryIterMut<'w, Q, F>
386where
387 Q: QuerySpecMut + 'w,
388 F: QueryFilter,
389{
390 fn len(&self) -> usize {
391 self.remaining()
392 }
393}
394
395pub type Query2Iter<'w, A, B, F = NoFilter> = QueryIter<'w, (&'w A, &'w B), F>;
396pub type Query2MutIter<'w, A, B, F = NoFilter> = QueryIterMut<'w, (&'w mut A, &'w mut B), F>;
397pub type Query3Iter<'w, A, B, C, F = NoFilter> = QueryIter<'w, (&'w A, &'w B, &'w C), F>;
398pub type Query3MutIter<'w, A, B, C, F = NoFilter> =
399 QueryIterMut<'w, (&'w mut A, &'w mut B, &'w mut C), F>;
400
401#[doc(hidden)]
402pub struct OptionalMutState<'w, T> {
403 entities: &'w [Entity],
404 data: *mut T,
406 changed_ticks: *mut u64,
408 tick: u64,
409 _marker: PhantomData<&'w mut T>,
410}
411
412#[doc(hidden)]
413pub struct SingleMutState<'w, T> {
414 entities: &'w [Entity],
415 data: *mut T,
416 changed_ticks: *mut u64,
417 tick: u64,
418 len: usize,
419 _marker: PhantomData<&'w mut T>,
420}
421
422#[doc(hidden)]
423pub struct PairMutState<'w, A, B> {
424 entities: &'w [Entity],
425 col_a: *mut A,
426 col_b: *mut B,
427 changed_ticks_a: *mut u64,
428 changed_ticks_b: *mut u64,
429 tick: u64,
430 len: usize,
431 _marker: PhantomData<&'w mut (A, B)>,
432}
433
434#[doc(hidden)]
435pub struct TripleMutState<'w, A, B, C> {
436 entities: &'w [Entity],
437 col_a: *mut A,
438 col_b: *mut B,
439 col_c: *mut C,
440 changed_ticks_a: *mut u64,
441 changed_ticks_b: *mut u64,
442 changed_ticks_c: *mut u64,
443 tick: u64,
444 len: usize,
445 _marker: PhantomData<&'w mut (A, B, C)>,
446}
447
448impl<T: Component> QuerySpec for &T {
449 type Item<'w> = &'w T;
450
451 type State<'w> = (&'w [Entity], &'w Column<T>);
452
453 fn matches(layout: &ArchetypeLayout) -> bool {
454 layout.contains(TypeId::of::<T>())
455 }
456
457 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>> {
458 Some((archetype.entities(), archetype.column::<T>()?))
459 }
460
461 fn len(state: &Self::State<'_>) -> usize {
462 state.0.len()
463 }
464
465 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
466 state.0[row]
467 }
468
469 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w> {
470 state.1.get(row).unwrap()
471 }
472}
473
474impl<T: Component> QuerySpec for Option<&T> {
477 type Item<'w> = Option<&'w T>;
478
479 type State<'w> = (&'w [Entity], Option<&'w Column<T>>);
480
481 fn matches(_layout: &ArchetypeLayout) -> bool {
482 true
483 }
484
485 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>> {
486 Some((archetype.entities(), archetype.column::<T>()))
487 }
488
489 fn len(state: &Self::State<'_>) -> usize {
490 state.0.len()
491 }
492
493 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
494 state.0[row]
495 }
496
497 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w> {
498 state.1.as_ref().and_then(|col| col.get(row))
499 }
500}
501
502impl<A: Component, B: Component> QuerySpec for (&A, &B) {
503 type Item<'w> = (&'w A, &'w B);
504
505 type State<'w> = (&'w [Entity], &'w Column<A>, &'w Column<B>);
506
507 fn matches(layout: &ArchetypeLayout) -> bool {
508 layout.contains(TypeId::of::<A>()) && layout.contains(TypeId::of::<B>())
509 }
510
511 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>> {
512 Some((
513 archetype.entities(),
514 archetype.column::<A>()?,
515 archetype.column::<B>()?,
516 ))
517 }
518
519 fn len(state: &Self::State<'_>) -> usize {
520 state.0.len()
521 }
522
523 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
524 state.0[row]
525 }
526
527 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w> {
528 (state.1.get(row).unwrap(), state.2.get(row).unwrap())
529 }
530}
531
532impl<A: Component, B: Component> QuerySpec for (&A, Option<&B>) {
533 type Item<'w> = (&'w A, Option<&'w B>);
534
535 type State<'w> = (&'w [Entity], &'w Column<A>, Option<&'w Column<B>>);
536
537 fn matches(layout: &ArchetypeLayout) -> bool {
538 layout.contains(TypeId::of::<A>())
539 }
540
541 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>> {
542 Some((
543 archetype.entities(),
544 archetype.column::<A>()?,
545 archetype.column::<B>(),
546 ))
547 }
548
549 fn len(state: &Self::State<'_>) -> usize {
550 state.0.len()
551 }
552
553 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
554 state.0[row]
555 }
556
557 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w> {
558 (
559 state.1.get(row).unwrap(),
560 state.2.as_ref().and_then(|col| col.get(row)),
561 )
562 }
563}
564
565impl<A: Component, B: Component, C: Component> QuerySpec for (&A, &B, &C) {
566 type Item<'w> = (&'w A, &'w B, &'w C);
567
568 type State<'w> = (&'w [Entity], &'w Column<A>, &'w Column<B>, &'w Column<C>);
569
570 fn matches(layout: &ArchetypeLayout) -> bool {
571 layout.contains(TypeId::of::<A>())
572 && layout.contains(TypeId::of::<B>())
573 && layout.contains(TypeId::of::<C>())
574 }
575
576 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>> {
577 Some((
578 archetype.entities(),
579 archetype.column::<A>()?,
580 archetype.column::<B>()?,
581 archetype.column::<C>()?,
582 ))
583 }
584
585 fn len(state: &Self::State<'_>) -> usize {
586 state.0.len()
587 }
588
589 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
590 state.0[row]
591 }
592
593 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w> {
594 (
595 state.1.get(row).unwrap(),
596 state.2.get(row).unwrap(),
597 state.3.get(row).unwrap(),
598 )
599 }
600}
601
602impl<A: Component, B: Component, C: Component, D: Component> QuerySpec
603 for (&A, Option<&B>, Option<&C>, Option<&D>)
604{
605 type Item<'w> = (&'w A, Option<&'w B>, Option<&'w C>, Option<&'w D>);
606
607 type State<'w> = (
608 &'w [Entity],
609 &'w Column<A>,
610 Option<&'w Column<B>>,
611 Option<&'w Column<C>>,
612 Option<&'w Column<D>>,
613 );
614
615 fn matches(layout: &ArchetypeLayout) -> bool {
616 layout.contains(TypeId::of::<A>())
617 }
618
619 fn init_state<'w>(archetype: &'w Archetype) -> Option<Self::State<'w>> {
620 Some((
621 archetype.entities(),
622 archetype.column::<A>()?,
623 archetype.column::<B>(),
624 archetype.column::<C>(),
625 archetype.column::<D>(),
626 ))
627 }
628
629 fn len(state: &Self::State<'_>) -> usize {
630 state.0.len()
631 }
632
633 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
634 state.0[row]
635 }
636
637 fn fetch<'w>(state: &Self::State<'w>, row: usize) -> Self::Item<'w> {
638 (
639 state.1.get(row).unwrap(),
640 state.2.as_ref().and_then(|col| col.get(row)),
641 state.3.as_ref().and_then(|col| col.get(row)),
642 state.4.as_ref().and_then(|col| col.get(row)),
643 )
644 }
645}
646
647impl<T: Component> QuerySpecMut for &mut T {
648 type Item<'w> = Mut<'w, T>;
649
650 type State<'w> = SingleMutState<'w, T>;
651
652 fn matches(layout: &ArchetypeLayout) -> bool {
653 layout.contains(TypeId::of::<T>())
654 }
655
656 fn init_state<'w>(archetype: &'w mut Archetype, tick: u64) -> Option<Self::State<'w>> {
657 let (entities, column) = archetype.entities_and_column_mut::<T>()?;
658 Some(SingleMutState {
659 entities,
660 data: column.as_mut_ptr(),
661 changed_ticks: column.changed_ticks_mut_ptr(),
662 tick,
663 len: column.len(),
664 _marker: PhantomData,
665 })
666 }
667
668 fn len(state: &Self::State<'_>) -> usize {
669 state.len
670 }
671
672 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
673 state.entities[row]
674 }
675
676 unsafe fn fetch<'w>(state: &mut Self::State<'w>, row: usize) -> Self::Item<'w> {
677 unsafe {
682 Mut {
683 value: &mut *state.data.add(row),
684 changed_tick: state.changed_ticks.add(row),
685 tick: state.tick,
686 }
687 }
688 }
689}
690
691impl<T: Component> QuerySpecMut for Option<&mut T> {
694 type Item<'w> = Option<Mut<'w, T>>;
695
696 type State<'w> = OptionalMutState<'w, T>;
697
698 fn matches(_layout: &ArchetypeLayout) -> bool {
699 true
700 }
701
702 fn init_state<'w>(archetype: &'w mut Archetype, tick: u64) -> Option<Self::State<'w>> {
703 let entities = archetype.entities() as *const [Entity];
704 let (data, changed_ticks) = match archetype.column_mut::<T>() {
705 Some(col) => (col.as_mut_ptr(), col.changed_ticks_mut_ptr()),
706 None => (std::ptr::null_mut(), std::ptr::null_mut()),
707 };
708 Some(OptionalMutState {
711 entities: unsafe { &*entities },
712 data,
713 changed_ticks,
714 tick,
715 _marker: PhantomData,
716 })
717 }
718
719 fn len(state: &Self::State<'_>) -> usize {
720 state.entities.len()
721 }
722
723 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
724 state.entities[row]
725 }
726
727 unsafe fn fetch<'w>(state: &mut Self::State<'w>, row: usize) -> Self::Item<'w> {
728 if state.data.is_null() {
729 None
730 } else {
731 unsafe {
733 Some(Mut {
734 value: &mut *state.data.add(row),
735 changed_tick: state.changed_ticks.add(row),
736 tick: state.tick,
737 })
738 }
739 }
740 }
741}
742
743impl<A: Component, B: Component> QuerySpecMut for (&mut A, &mut B) {
744 type Item<'w> = (Mut<'w, A>, Mut<'w, B>);
745
746 type State<'w> = PairMutState<'w, A, B>;
747
748 fn matches(layout: &ArchetypeLayout) -> bool {
749 layout.contains(TypeId::of::<A>()) && layout.contains(TypeId::of::<B>())
750 }
751
752 fn init_state<'w>(archetype: &'w mut Archetype, tick: u64) -> Option<Self::State<'w>> {
753 let (entities, col_a, col_b) = archetype.entities_and_two_columns_mut::<A, B>()?;
754 Some(PairMutState {
755 entities,
756 col_a: col_a.as_mut_ptr(),
757 col_b: col_b.as_mut_ptr(),
758 changed_ticks_a: col_a.changed_ticks_mut_ptr(),
759 changed_ticks_b: col_b.changed_ticks_mut_ptr(),
760 tick,
761 len: entities.len(),
762 _marker: PhantomData,
763 })
764 }
765
766 fn len(state: &Self::State<'_>) -> usize {
767 state.len
768 }
769
770 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
771 state.entities[row]
772 }
773
774 unsafe fn fetch<'w>(state: &mut Self::State<'w>, row: usize) -> Self::Item<'w> {
775 unsafe {
778 (
779 Mut {
780 value: &mut *state.col_a.add(row),
781 changed_tick: state.changed_ticks_a.add(row),
782 tick: state.tick,
783 },
784 Mut {
785 value: &mut *state.col_b.add(row),
786 changed_tick: state.changed_ticks_b.add(row),
787 tick: state.tick,
788 },
789 )
790 }
791 }
792}
793
794impl<A: Component, B: Component, C: Component> QuerySpecMut for (&mut A, &mut B, &mut C) {
795 type Item<'w> = (Mut<'w, A>, Mut<'w, B>, Mut<'w, C>);
796
797 type State<'w> = TripleMutState<'w, A, B, C>;
798
799 fn matches(layout: &ArchetypeLayout) -> bool {
800 layout.contains(TypeId::of::<A>())
801 && layout.contains(TypeId::of::<B>())
802 && layout.contains(TypeId::of::<C>())
803 }
804
805 fn init_state<'w>(archetype: &'w mut Archetype, tick: u64) -> Option<Self::State<'w>> {
806 let (entities, col_a, col_b, col_c) =
807 archetype.entities_and_three_columns_mut::<A, B, C>()?;
808 Some(TripleMutState {
809 entities,
810 col_a: col_a.as_mut_ptr(),
811 col_b: col_b.as_mut_ptr(),
812 col_c: col_c.as_mut_ptr(),
813 changed_ticks_a: col_a.changed_ticks_mut_ptr(),
814 changed_ticks_b: col_b.changed_ticks_mut_ptr(),
815 changed_ticks_c: col_c.changed_ticks_mut_ptr(),
816 tick,
817 len: entities.len(),
818 _marker: PhantomData,
819 })
820 }
821
822 fn len(state: &Self::State<'_>) -> usize {
823 state.len
824 }
825
826 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
827 state.entities[row]
828 }
829
830 unsafe fn fetch<'w>(state: &mut Self::State<'w>, row: usize) -> Self::Item<'w> {
831 unsafe {
834 (
835 Mut {
836 value: &mut *state.col_a.add(row),
837 changed_tick: state.changed_ticks_a.add(row),
838 tick: state.tick,
839 },
840 Mut {
841 value: &mut *state.col_b.add(row),
842 changed_tick: state.changed_ticks_b.add(row),
843 tick: state.tick,
844 },
845 Mut {
846 value: &mut *state.col_c.add(row),
847 changed_tick: state.changed_ticks_c.add(row),
848 tick: state.tick,
849 },
850 )
851 }
852 }
853}
854
855pub struct ChangedIter<'w, T: Component> {
861 store: &'w ArchetypeStore,
862 archetype_index: usize,
863 row: usize,
864 since_tick: u64,
865 current: Option<(&'w [Entity], &'w Column<T>)>,
866}
867
868impl<'w, T: Component> ChangedIter<'w, T> {
869 pub(crate) fn new(store: &'w ArchetypeStore, since_tick: u64) -> Self {
870 Self {
871 store,
872 archetype_index: 0,
873 row: 0,
874 since_tick,
875 current: None,
876 }
877 }
878}
879
880impl<'w, T: Component> Iterator for ChangedIter<'w, T> {
881 type Item = (Entity, &'w T);
882
883 fn next(&mut self) -> Option<Self::Item> {
884 loop {
885 if let Some((entities, col)) = &self.current {
886 while self.row < entities.len() {
887 let row = self.row;
888 self.row += 1;
889 if col.changed_tick(row) > self.since_tick {
890 return Some((entities[row], col.get(row).unwrap()));
891 }
892 }
893 self.current = None;
894 }
895
896 let archetype = self.store.get_by_index(self.archetype_index)?;
897 self.archetype_index += 1;
898
899 if !archetype.layout().contains(TypeId::of::<T>()) {
900 continue;
901 }
902
903 if let (Some(col), entities) = (archetype.column::<T>(), archetype.entities()) {
904 self.current = Some((entities, col));
905 self.row = 0;
906 }
907 }
908 }
909}
910
911pub struct AddedIter<'w, T: Component> {
913 store: &'w ArchetypeStore,
914 archetype_index: usize,
915 row: usize,
916 since_tick: u64,
917 current: Option<(&'w [Entity], &'w Column<T>)>,
918}
919
920impl<'w, T: Component> AddedIter<'w, T> {
921 pub(crate) fn new(store: &'w ArchetypeStore, since_tick: u64) -> Self {
922 Self {
923 store,
924 archetype_index: 0,
925 row: 0,
926 since_tick,
927 current: None,
928 }
929 }
930}
931
932impl<'w, T: Component> Iterator for AddedIter<'w, T> {
933 type Item = (Entity, &'w T);
934
935 fn next(&mut self) -> Option<Self::Item> {
936 loop {
937 if let Some((entities, col)) = &self.current {
938 while self.row < entities.len() {
939 let row = self.row;
940 self.row += 1;
941 if col.added_tick(row) > self.since_tick {
942 return Some((entities[row], col.get(row).unwrap()));
943 }
944 }
945 self.current = None;
946 }
947
948 let archetype = self.store.get_by_index(self.archetype_index)?;
949 self.archetype_index += 1;
950
951 if !archetype.layout().contains(TypeId::of::<T>()) {
952 continue;
953 }
954
955 if let (Some(col), entities) = (archetype.column::<T>(), archetype.entities()) {
956 self.current = Some((entities, col));
957 self.row = 0;
958 }
959 }
960 }
961}
962
963#[doc(hidden)]
964pub struct PairMutOptionalState<'w, A, B> {
965 entities: &'w [Entity],
966 col_a: *mut A,
967 col_b: *mut B,
968 changed_ticks_a: *mut u64,
969 changed_ticks_b: *mut u64,
970 tick: u64,
971 len: usize,
972 _marker: PhantomData<&'w mut (A, B)>,
973}
974
975impl<A: Component, B: Component> QuerySpecMut for (&mut A, Option<&mut B>) {
976 type Item<'w> = (Mut<'w, A>, Option<Mut<'w, B>>);
977
978 type State<'w> = PairMutOptionalState<'w, A, B>;
979
980 fn matches(layout: &ArchetypeLayout) -> bool {
981 layout.contains(TypeId::of::<A>())
982 }
983
984 fn init_state<'w>(archetype: &'w mut Archetype, tick: u64) -> Option<Self::State<'w>> {
985 assert_ne!(
986 TypeId::of::<A>(),
987 TypeId::of::<B>(),
988 "cannot borrow the same column mutably twice"
989 );
990 let (entities, col_a, col_b) =
991 archetype.entities_and_required_optional_columns_mut::<A, B>()?;
992 let col_a_ptr = col_a.as_mut_ptr();
993 let changed_ticks_a = col_a.changed_ticks_mut_ptr();
994 let len = col_a.len();
995 let (col_b_ptr, changed_ticks_b) = match col_b {
996 Some(col) => (col.as_mut_ptr(), col.changed_ticks_mut_ptr()),
997 None => (std::ptr::null_mut(), std::ptr::null_mut()),
998 };
999 Some(PairMutOptionalState {
1000 entities,
1001 col_a: col_a_ptr,
1002 col_b: col_b_ptr,
1003 changed_ticks_a,
1004 changed_ticks_b,
1005 tick,
1006 len,
1007 _marker: PhantomData,
1008 })
1009 }
1010
1011 fn len(state: &Self::State<'_>) -> usize {
1012 state.len
1013 }
1014
1015 fn entity(state: &Self::State<'_>, row: usize) -> Entity {
1016 state.entities[row]
1017 }
1018
1019 unsafe fn fetch<'w>(state: &mut Self::State<'w>, row: usize) -> Self::Item<'w> {
1020 unsafe {
1023 let a = Mut {
1024 value: &mut *state.col_a.add(row),
1025 changed_tick: state.changed_ticks_a.add(row),
1026 tick: state.tick,
1027 };
1028 let b = if state.col_b.is_null() {
1029 None
1030 } else {
1031 Some(Mut {
1032 value: &mut *state.col_b.add(row),
1033 changed_tick: state.changed_ticks_b.add(row),
1034 tick: state.tick,
1035 })
1036 };
1037 (a, b)
1038 }
1039 }
1040}
1041
1042#[cfg(test)]
1043mod tests {
1044 use crate::World;
1045
1046 #[derive(Debug, Clone, PartialEq)]
1047 struct Pos {
1048 x: f32,
1049 y: f32,
1050 }
1051 impl crate::Component for Pos {}
1052
1053 #[derive(Debug, Clone, PartialEq)]
1054 struct Vel {
1055 x: f32,
1056 y: f32,
1057 }
1058 impl crate::Component for Vel {}
1059
1060 #[derive(Debug, Clone, PartialEq)]
1061 struct Name(String);
1062 impl crate::Component for Name {}
1063
1064 #[derive(Debug, Clone, PartialEq)]
1065 struct Health(i32);
1066 impl crate::Component for Health {}
1067
1068 #[test]
1071 fn optional_query_returns_some_when_present() {
1072 let mut world = World::new();
1073 world.spawn((Pos { x: 1.0, y: 2.0 },));
1074
1075 let results: Vec<_> = world.query::<Option<&Pos>>().collect();
1076 assert_eq!(results.len(), 1);
1077 assert_eq!(results[0].1, Some(&Pos { x: 1.0, y: 2.0 }));
1078 }
1079
1080 #[test]
1081 fn optional_query_returns_none_when_absent() {
1082 let mut world = World::new();
1083 world.spawn((Vel { x: 1.0, y: 0.0 },));
1084
1085 let results: Vec<_> = world.query::<Option<&Pos>>().collect();
1086 assert_eq!(results.len(), 1);
1087 assert_eq!(results[0].1, None);
1088 }
1089
1090 #[test]
1093 fn required_plus_optional_both_present() {
1094 let mut world = World::new();
1095 world.spawn((Pos { x: 1.0, y: 0.0 }, Vel { x: 2.0, y: 0.0 }));
1096
1097 let results: Vec<_> = world.query::<(&Pos, Option<&Vel>)>().collect();
1098 assert_eq!(results.len(), 1);
1099 assert_eq!(results[0].1.0, &Pos { x: 1.0, y: 0.0 });
1100 assert_eq!(results[0].1.1, Some(&Vel { x: 2.0, y: 0.0 }));
1101 }
1102
1103 #[test]
1104 fn required_plus_optional_absent() {
1105 let mut world = World::new();
1106 world.spawn((Pos { x: 1.0, y: 0.0 },));
1107
1108 let results: Vec<_> = world.query::<(&Pos, Option<&Vel>)>().collect();
1109 assert_eq!(results.len(), 1);
1110 assert_eq!(results[0].1.1, None);
1111 }
1112
1113 #[test]
1114 fn required_plus_optional_filters_by_required() {
1115 let mut world = World::new();
1116 world.spawn((Pos { x: 1.0, y: 0.0 },));
1117 world.spawn((Vel { x: 2.0, y: 0.0 },)); let results: Vec<_> = world.query::<(&Pos, Option<&Vel>)>().collect();
1120 assert_eq!(results.len(), 1);
1121 }
1122
1123 #[test]
1126 fn four_tuple_all_present() {
1127 let mut world = World::new();
1128 world.spawn((
1129 Pos { x: 1.0, y: 0.0 },
1130 Vel { x: 2.0, y: 0.0 },
1131 Name("a".into()),
1132 Health(100),
1133 ));
1134
1135 let results: Vec<_> = world
1136 .query::<(&Pos, Option<&Vel>, Option<&Name>, Option<&Health>)>()
1137 .collect();
1138 assert_eq!(results.len(), 1);
1139 let (pos, vel, name, hp) = &results[0].1;
1140 assert_eq!(*pos, &Pos { x: 1.0, y: 0.0 });
1141 assert!(vel.is_some());
1142 assert!(name.is_some());
1143 assert!(hp.is_some());
1144 }
1145
1146 #[test]
1147 fn four_tuple_mixed_presence() {
1148 let mut world = World::new();
1149 world.spawn((Pos { x: 1.0, y: 0.0 }, Health(50)));
1151 world.spawn((
1153 Pos { x: 2.0, y: 0.0 },
1154 Vel { x: 1.0, y: 0.0 },
1155 Name("b".into()),
1156 ));
1157
1158 let mut results: Vec<_> = world
1159 .query::<(&Pos, Option<&Vel>, Option<&Name>, Option<&Health>)>()
1160 .map(|(_, (pos, vel, name, hp))| (pos.x, vel.is_some(), name.is_some(), hp.is_some()))
1161 .collect();
1162 results.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
1163
1164 assert_eq!(results.len(), 2);
1165 assert_eq!(results[0], (1.0, false, false, true));
1166 assert_eq!(results[1], (2.0, true, true, false));
1167 }
1168
1169 #[test]
1172 fn optional_mut_modifies_when_present() {
1173 let mut world = World::new();
1174 world.spawn((Pos { x: 1.0, y: 0.0 }, Vel { x: 0.0, y: 0.0 }));
1175
1176 for (_, vel) in world.query_mut::<Option<&mut Vel>>() {
1177 if let Some(mut v) = vel {
1178 v.x += 10.0;
1179 }
1180 }
1181
1182 let vel = world.query::<&Vel>().next().unwrap().1;
1183 assert_eq!(vel.x, 10.0);
1184 }
1185
1186 #[test]
1187 fn optional_mut_skips_when_absent() {
1188 let mut world = World::new();
1189 world.spawn((Pos { x: 1.0, y: 0.0 },));
1190
1191 let mut count = 0;
1192 for (_, vel) in world.query_mut::<Option<&mut Vel>>() {
1193 count += 1;
1194 assert!(vel.is_none());
1195 }
1196 assert_eq!(count, 1);
1197 }
1198
1199 #[test]
1202 fn required_mut_plus_optional_mut() {
1203 let mut world = World::new();
1204 world.spawn((Pos { x: 1.0, y: 0.0 }, Vel { x: 0.0, y: 0.0 }));
1205 world.spawn((Pos { x: 2.0, y: 0.0 },)); for (_, (mut pos, vel)) in world.query_mut::<(&mut Pos, Option<&mut Vel>)>() {
1208 pos.x += 100.0;
1209 if let Some(mut v) = vel {
1210 v.x += 50.0;
1211 }
1212 }
1213
1214 let mut results: Vec<_> = world.query::<&Pos>().map(|(_, p)| p.x).collect();
1215 results.sort_by(|a, b| a.partial_cmp(b).unwrap());
1216 assert_eq!(results, vec![101.0, 102.0]);
1217
1218 let vel = world.query::<&Vel>().next().unwrap().1;
1219 assert_eq!(vel.x, 50.0);
1220 }
1221
1222 #[test]
1225 fn optional_query_spans_multiple_archetypes() {
1226 let mut world = World::new();
1227 world.spawn((Pos { x: 1.0, y: 0.0 },));
1229 world.spawn((Pos { x: 2.0, y: 0.0 }, Vel { x: 5.0, y: 0.0 }));
1231 world.spawn((Pos { x: 3.0, y: 0.0 }, Name("c".into())));
1233
1234 let mut results: Vec<_> = world
1235 .query::<(&Pos, Option<&Vel>)>()
1236 .map(|(_, (pos, vel))| (pos.x, vel.map(|v| v.x)))
1237 .collect();
1238 results.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
1239
1240 assert_eq!(results.len(), 3);
1241 assert_eq!(results[0], (1.0, None));
1242 assert_eq!(results[1], (2.0, Some(5.0)));
1243 assert_eq!(results[2], (3.0, None));
1244 }
1245}