1use crate::entity::entity_set::entity_set::{EntitySet, EntitySetInner};
14use crate::entity::entity_set::source_iterator::{PopulationRangeIterator, SourceIterator};
15use crate::entity::entity_set::source_set::SourceSet;
16use crate::entity::{Entity, EntityId, PopulationIterator};
17use crate::hashing::IndexSet;
18#[cfg(feature = "profiling")]
19use crate::profiling::{QueryExecutionProfile, QueryProfileHandle};
20
21enum EntitySetIteratorInner<'a, E: Entity> {
22 Source(SourceIterator<'a, E>),
23 IntersectionSources {
27 driver: SourceIterator<'a, E>,
28 filters: Vec<SourceSet<'a, E>>,
29 },
30 Intersection {
31 driver: Box<EntitySetIteratorInner<'a, E>>,
32 filters: Vec<EntitySet<'a, E>>,
33 },
34 Difference {
35 left: Box<EntitySetIteratorInner<'a, E>>,
36 right: EntitySet<'a, E>,
37 },
38 Union {
39 left: Box<EntitySetIteratorInner<'a, E>>,
40 right: UnionRightState<'a, E>,
41 },
42}
43
44enum UnionRightState<'a, E: Entity> {
45 Pending(Option<EntitySet<'a, E>>),
46 Active(Box<EntitySetIteratorInner<'a, E>>),
47}
48
49impl<'a, E: Entity> EntitySetIteratorInner<'a, E> {
50 fn empty_source() -> Self {
51 Self::Source(SourceIterator::PopulationRange(
52 PopulationRangeIterator::new(0..0),
53 ))
54 }
55
56 fn from_entity_set(set: EntitySet<'a, E>) -> Self {
57 match set.inner {
58 EntitySetInner::Source(source) => {
59 if source.try_len() == Some(0) {
60 Self::empty_source()
61 } else {
62 Self::Source(source.into_iter())
63 }
64 }
65 EntitySetInner::Intersection(mut sets) => {
66 if sets.is_empty() {
67 return Self::empty_source();
68 }
69 if sets.len() == 1 {
70 return Self::from_entity_set(sets.pop().unwrap());
71 }
72
73 if sets.iter().all(EntitySet::is_source_leaf) {
74 let mut set_iter = sets.into_iter();
77
78 let first = set_iter.next().unwrap().into_source_leaf().unwrap();
79 let driver = first.into_iter();
80
81 let filters = set_iter
82 .map(|set| set.into_source_leaf().unwrap())
83 .collect();
84
85 return Self::IntersectionSources { driver, filters };
86 }
87
88 let mut set_iter = sets.into_iter();
92 let driver = Box::new(Self::from_entity_set(set_iter.next().unwrap()));
93 Self::Intersection {
94 driver,
95 filters: set_iter.collect(),
96 }
97 }
98 EntitySetInner::Difference(left, right) => Self::Difference {
99 left: Box::new(Self::from_entity_set(*left)),
100 right: *right,
101 },
102 EntitySetInner::Union(left, right) => Self::Union {
103 left: Box::new(Self::from_entity_set(*left)),
104 right: UnionRightState::Pending(Some(*right)),
105 },
106 }
107 }
108
109 fn contains(&self, entity_id: EntityId<E>) -> bool {
110 match self {
111 Self::Source(iter) => iter.contains(entity_id),
112 Self::IntersectionSources { driver, filters } => {
113 driver.contains(entity_id) && filters.iter().all(|set| set.contains(entity_id))
114 }
115 Self::Intersection { driver, filters } => {
116 driver.contains(entity_id) && filters.iter().all(|set| set.contains(entity_id))
117 }
118 Self::Difference { left, right } => {
119 left.contains(entity_id) && !right.contains(entity_id)
120 }
121 Self::Union { left, right } => left.contains(entity_id) || right.contains(entity_id),
122 }
123 }
124}
125
126impl<'a, E: Entity> UnionRightState<'a, E> {
127 fn contains(&self, entity_id: EntityId<E>) -> bool {
128 match self {
129 Self::Pending(Some(set)) => set.contains(entity_id),
130 Self::Pending(None) => false,
131 Self::Active(iter) => iter.contains(entity_id),
132 }
133 }
134}
135
136impl<'a, E: Entity> EntitySetIteratorInner<'a, E> {
137 #[inline]
138 fn next_inner(&mut self) -> Option<EntityId<E>> {
139 match self {
140 Self::Source(source) => source.next(),
141 Self::IntersectionSources { driver, filters } => driver
142 .by_ref()
143 .find(|&entity_id| filters.iter().all(|filter| filter.contains(entity_id))),
144 Self::Intersection { driver, filters } => {
145 while let Some(entity_id) = driver.next_inner() {
146 if filters.iter().all(|filter| filter.contains(entity_id)) {
147 return Some(entity_id);
148 }
149 }
150 None
151 }
152 Self::Difference { left, right } => {
153 while let Some(entity_id) = left.next_inner() {
154 if !right.contains(entity_id) {
155 return Some(entity_id);
156 }
157 }
158 None
159 }
160 Self::Union { left, right } => loop {
161 if let Some(entity_id) = left.next_inner() {
162 return Some(entity_id);
163 }
164
165 match right {
166 UnionRightState::Pending(maybe_set) => {
167 if let Some(set) = maybe_set.take() {
168 *right = UnionRightState::Active(Box::new(Self::from_entity_set(set)));
169 }
170 continue;
171 }
172 UnionRightState::Active(right_iter) => {
173 while let Some(entity_id) = right_iter.next_inner() {
174 if !left.contains(entity_id) {
175 return Some(entity_id);
176 }
177 }
178 return None;
179 }
180 }
181 },
182 }
183 }
184
185 #[inline]
186 fn size_hint_inner(&self) -> (usize, Option<usize>) {
187 match self {
188 Self::Source(source) => source.size_hint(),
189 Self::IntersectionSources { driver, .. } => {
190 let (_, upper) = driver.size_hint();
191 (0, upper)
192 }
193 Self::Intersection { driver, .. } => {
194 let (_, upper) = driver.size_hint_inner();
195 (0, upper)
196 }
197 Self::Difference { left, .. } => {
198 let (_, upper) = left.size_hint_inner();
199 (0, upper)
200 }
201 Self::Union { left, right } => {
202 let (_, left_upper) = left.size_hint_inner();
203 let right_upper = match right {
204 UnionRightState::Pending(_) => None,
205 UnionRightState::Active(right_iter) => right_iter.size_hint_inner().1,
206 };
207 let upper = match (left_upper, right_upper) {
208 (Some(a), Some(b)) => Some(a.saturating_add(b)),
209 _ => None,
210 };
211 (0, upper)
212 }
213 }
214 }
215}
216
217pub struct EntitySetIterator<'c, E: Entity> {
219 inner: EntitySetIteratorInner<'c, E>,
220 #[cfg(feature = "profiling")]
221 pub(in crate::entity) query_profile: Option<QueryExecutionProfile<'c>>,
222}
223
224impl<'c, E: Entity> EntitySetIterator<'c, E> {
225 fn from_inner(inner: EntitySetIteratorInner<'c, E>) -> Self {
226 Self {
227 inner,
228 #[cfg(feature = "profiling")]
229 query_profile: None,
230 }
231 }
232
233 pub(crate) fn empty() -> EntitySetIterator<'c, E> {
234 Self::from_inner(EntitySetIteratorInner::empty_source())
235 }
236
237 pub(crate) fn from_population_iterator(iter: PopulationIterator<E>) -> Self {
238 Self::from_inner(EntitySetIteratorInner::Source(
239 SourceIterator::PopulationRange(PopulationRangeIterator::from_population_iterator(
240 iter,
241 )),
242 ))
243 }
244
245 pub(crate) fn from_sources(mut sources: Vec<SourceSet<'c, E>>) -> Self {
246 if sources.is_empty() {
247 return Self::empty();
248 }
249 if sources.len() == 1 {
250 return Self::from_inner(EntitySetIteratorInner::Source(
251 sources.pop().unwrap().into_iter(),
252 ));
253 }
254
255 sources.sort_unstable_by_key(SourceSet::sort_key);
258 let mut source_iter = sources.into_iter();
259 let driver = source_iter.next().unwrap().into_iter();
260 Self::from_inner(EntitySetIteratorInner::IntersectionSources {
261 driver,
262 filters: source_iter.collect(),
263 })
264 }
265
266 pub(crate) fn from_index_set(set: &'c IndexSet<EntityId<E>>) -> EntitySetIterator<'c, E> {
267 Self::from_inner(EntitySetIteratorInner::Source(
268 SourceSet::IndexSet(set).into_iter(),
269 ))
270 }
271
272 #[cfg(feature = "profiling")]
273 #[inline]
274 pub(in crate::entity) fn with_query_profile(mut self, profile: QueryProfileHandle<'c>) -> Self {
275 self.query_profile = Some(profile.execution());
276 self
277 }
278
279 #[allow(unused_mut)]
280 pub(super) fn new(mut set: EntitySet<'c, E>) -> Self {
281 #[cfg(feature = "profiling")]
282 let query_profile = set.query_profile.take().map(QueryProfileHandle::execution);
283 Self {
284 inner: EntitySetIteratorInner::from_entity_set(set),
285 #[cfg(feature = "profiling")]
286 query_profile,
287 }
288 }
289}
290
291impl<'a, E: Entity> Iterator for EntitySetIterator<'a, E> {
292 type Item = EntityId<E>;
293
294 #[inline]
295 fn next(&mut self) -> Option<Self::Item> {
296 #[cfg(feature = "profiling")]
297 {
298 let Self {
299 inner,
300 query_profile,
301 } = self;
302 if let Some(profile) = query_profile {
303 let item = {
304 let _query_execution_scope = profile.scope();
305 inner.next_inner()
306 };
307 if item.is_none() {
308 profile.finish();
309 }
310 return item;
311 }
312 }
313 self.inner.next_inner()
314 }
315
316 #[inline]
317 fn size_hint(&self) -> (usize, Option<usize>) {
318 self.inner.size_hint_inner()
319 }
320
321 fn count(self) -> usize {
322 let Self {
323 inner,
324 #[cfg(feature = "profiling")]
325 mut query_profile,
326 } = self;
327
328 #[cfg(feature = "profiling")]
329 let _query_execution_scope = query_profile
330 .as_mut()
331 .and_then(QueryExecutionProfile::scope);
332
333 match inner {
334 EntitySetIteratorInner::Source(source) => source.count(),
335 EntitySetIteratorInner::IntersectionSources {
336 mut driver,
337 filters,
338 } => driver
339 .by_ref()
340 .filter(|&entity_id| filters.iter().all(|filter| filter.contains(entity_id)))
341 .count(),
342 mut other => {
343 let mut count = 0usize;
344 while other.next_inner().is_some() {
345 count += 1;
346 }
347 count
348 }
349 }
350 }
351
352 #[inline]
353 fn nth(&mut self, n: usize) -> Option<Self::Item> {
354 let Self {
355 inner,
356 #[cfg(feature = "profiling")]
357 query_profile,
358 } = self;
359
360 let item = {
361 #[cfg(feature = "profiling")]
362 let _query_execution_scope = query_profile
363 .as_mut()
364 .and_then(QueryExecutionProfile::scope);
365
366 match inner {
367 EntitySetIteratorInner::Source(source) => source.nth(n),
368 EntitySetIteratorInner::IntersectionSources { driver, filters } => driver
369 .by_ref()
370 .filter(|&entity_id| filters.iter().all(|filter| filter.contains(entity_id)))
371 .nth(n),
372 other => 'item: {
373 for _ in 0..n {
374 if other.next_inner().is_none() {
375 break 'item None;
376 }
377 }
378 break 'item other.next_inner();
379 }
380 }
381 };
382
383 #[cfg(feature = "profiling")]
384 if item.is_none() {
385 if let Some(profile) = query_profile {
386 profile.finish();
387 }
388 }
389
390 item
391 }
392
393 fn for_each<F>(self, mut f: F)
394 where
395 F: FnMut(Self::Item),
396 {
397 #[allow(unused_mut)]
398 let EntitySetIterator {
399 mut inner,
400 #[cfg(feature = "profiling")]
401 query_profile,
402 } = self;
403 #[cfg(feature = "profiling")]
404 if let Some(mut query_profile) = query_profile {
405 loop {
406 let item = {
407 let _query_execution_scope = query_profile.scope();
408 inner.next_inner()
409 };
410 let Some(item) = item else {
411 query_profile.finish();
412 break;
413 };
414 f(item);
415 }
416 return;
417 }
418
419 match inner {
420 EntitySetIteratorInner::Source(source) => source.for_each(f),
421 mut other => {
422 while let Some(item) = other.next_inner() {
423 f(item);
424 }
425 }
426 }
427 }
428
429 fn fold<B, F>(self, init: B, mut f: F) -> B
430 where
431 F: FnMut(B, Self::Item) -> B,
432 {
433 #[allow(unused_mut)]
434 let EntitySetIterator {
435 mut inner,
436 #[cfg(feature = "profiling")]
437 query_profile,
438 } = self;
439 #[cfg(feature = "profiling")]
440 if let Some(mut query_profile) = query_profile {
441 let mut acc = init;
442 loop {
443 let item = {
444 let _query_execution_scope = query_profile.scope();
445 inner.next_inner()
446 };
447 let Some(item) = item else {
448 query_profile.finish();
449 break;
450 };
451 acc = f(acc, item);
452 }
453 return acc;
454 }
455
456 match inner {
457 EntitySetIteratorInner::Source(source) => source.fold(init, f),
458 mut other => {
459 let mut acc = init;
460 while let Some(item) = other.next_inner() {
461 acc = f(acc, item);
462 }
463 acc
464 }
465 }
466 }
467}
468
469impl<'c, E: Entity> std::iter::FusedIterator for EntitySetIterator<'c, E> {}
470
471#[cfg(test)]
472mod tests {
473 use indexmap::IndexSet;
499
500 use crate::entity::entity_set::{EntitySet, SourceSet};
501 use crate::hashing::IndexSet as FxIndexSet;
502 use crate::prelude::*;
503 use crate::{define_derived_property, define_property, with};
504
505 define_entity!(Person);
506
507 define_property!(struct ExplicitProp(u8), Person);
511
512 define_property!(struct ConstantProp(u8), Person, default_const = ConstantProp(42));
514
515 define_derived_property!(struct DerivedProp(bool), Person, [ExplicitProp], |explicit| {
517 DerivedProp(explicit.0 % 2 == 0)
518 });
519
520 define_property!(struct ConstantProp2(u16), Person, default_const = ConstantProp2(100));
522 define_property!(struct ExplicitProp2(bool), Person);
523
524 define_property!(struct Age(u8), Person, default_const = Age(0));
525 define_property!(struct Alive(bool), Person, default_const = Alive(true));
526
527 define_derived_property!(
528 enum AgeGroupRisk {
529 NewBorn,
530 General,
531 OldAdult,
532 },
533 Person,
534 [Age],
535 [],
536 |age| {
537 if age.0 <= 1 {
538 AgeGroupRisk::NewBorn
539 } else if age.0 <= 65 {
540 AgeGroupRisk::General
541 } else {
542 AgeGroupRisk::OldAdult
543 }
544 }
545 );
546
547 fn setup_test_population(context: &mut Context, size: usize) -> Vec<EntityId<Person>> {
549 let mut people = Vec::new();
550 for i in 0..size {
551 let person = context
552 .add_entity(with!(
553 Person,
554 ExplicitProp((i % 20) as u8),
555 ExplicitProp2(i % 2 == 0)
556 ))
557 .unwrap();
558 people.push(person);
559 }
560 people
561 }
562
563 #[test]
567 fn test_explicit_non_default_not_indexed_initial_source_yes() {
568 let mut context = Context::new();
569 setup_test_population(&mut context, 100);
570
571 let results = context
572 .query_result_iterator(with!(Person, ExplicitProp(5)))
573 .collect::<Vec<_>>();
574
575 assert_eq!(results.len(), 5); for person in results {
577 assert_eq!(
578 context.get_property::<_, ExplicitProp>(person),
579 ExplicitProp(5)
580 );
581 }
582 }
583
584 #[test]
586 fn test_explicit_non_default_indexed_initial_source_yes() {
587 let mut context = Context::new();
588 context.index_property::<Person, ExplicitProp>();
589 setup_test_population(&mut context, 100);
590
591 let results = context
592 .query_result_iterator(with!(Person, ExplicitProp(7)))
593 .collect::<Vec<_>>();
594
595 assert_eq!(results.len(), 5); for person in results {
597 assert_eq!(
598 context.get_property::<_, ExplicitProp>(person),
599 ExplicitProp(7)
600 );
601 }
602 }
603
604 #[test]
606 fn test_constant_default_not_indexed_initial_source_yes() {
607 let mut context = Context::new();
608 for _ in 0..50 {
610 context
611 .add_entity(with!(Person, ExplicitProp(1), ExplicitProp2(false)))
612 .unwrap();
613 }
614
615 let results = context
616 .query_result_iterator(with!(Person, ConstantProp(42), ExplicitProp2(false)))
617 .collect::<Vec<_>>();
618
619 assert_eq!(results.len(), 50);
620 for person in results {
621 assert_eq!(
622 context.get_property::<_, ConstantProp>(person),
623 ConstantProp(42)
624 );
625 }
626 }
627
628 #[test]
630 fn test_constant_default_indexed_initial_source_yes() {
631 let mut context = Context::new();
632 context.index_property::<Person, ConstantProp>();
633
634 for _ in 0..50 {
635 context
636 .add_entity(with!(Person, ExplicitProp(1), ExplicitProp2(false)))
637 .unwrap();
638 }
639
640 let results = context
641 .query_result_iterator(with!(Person, ConstantProp(42)))
642 .collect::<Vec<_>>();
643 assert_eq!(results.len(), 50);
644 }
645
646 #[test]
648 fn test_constant_non_default_not_indexed_initial_source_yes() {
649 let mut context = Context::new();
650
651 for i in 0..50 {
652 if i < 10 {
653 context
654 .add_entity(with!(
655 Person,
656 ExplicitProp(1),
657 ExplicitProp2(false),
658 ConstantProp(99)
659 ))
660 .unwrap();
661 } else {
662 context
663 .add_entity(with!(Person, ExplicitProp(1), ExplicitProp2(false)))
664 .unwrap();
665 }
666 }
667
668 let results = context
669 .query_result_iterator(with!(Person, ConstantProp(99)))
670 .collect::<Vec<_>>();
671
672 assert_eq!(results.len(), 10);
673 for person in results {
674 assert_eq!(
675 context.get_property::<_, ConstantProp>(person),
676 ConstantProp(99)
677 );
678 }
679 }
680
681 #[test]
683 fn test_constant_non_default_indexed_initial_source_yes() {
684 let mut context = Context::new();
685 context.index_property::<Person, ConstantProp>();
686
687 for i in 0..50 {
688 if i < 10 {
689 context
690 .add_entity(with!(
691 Person,
692 ExplicitProp(1),
693 ExplicitProp2(false),
694 ConstantProp(99)
695 ))
696 .unwrap();
697 } else {
698 context
699 .add_entity(with!(Person, ExplicitProp(1), ExplicitProp2(false)))
700 .unwrap();
701 }
702 }
703
704 let results = context
705 .query_result_iterator(with!(Person, ConstantProp(99)))
706 .collect::<Vec<_>>();
707
708 assert_eq!(results.len(), 10);
709 }
710
711 #[test]
713 fn test_derived_not_indexed_initial_source_yes() {
714 let mut context = Context::new();
715
716 for i in 0..100 {
717 context
718 .add_entity(with!(Person, ExplicitProp(i as u8), ExplicitProp2(false)))
719 .unwrap();
720 }
721
722 let results = context
723 .query_result_iterator(with!(Person, DerivedProp(true)))
724 .collect::<Vec<_>>();
725
726 assert_eq!(results.len(), 50);
728 for person in results {
729 assert_eq!(
730 context.get_property::<Person, DerivedProp>(person),
731 DerivedProp(true)
732 );
733 }
734 }
735
736 #[test]
738 fn test_derived_indexed_initial_source_yes() {
739 let mut context = Context::new();
740 context.index_property::<Person, DerivedProp>();
741
742 for i in 0..100 {
743 context
744 .add_entity(with!(Person, ExplicitProp(i as u8), ExplicitProp2(false)))
745 .unwrap();
746 }
747
748 let results = context
749 .query_result_iterator(with!(Person, DerivedProp(false)))
750 .collect::<Vec<_>>();
751
752 assert_eq!(results.len(), 50);
754 for person in results {
755 assert_eq!(
756 context.get_property::<Person, DerivedProp>(person),
757 DerivedProp(false)
758 );
759 }
760 }
761
762 #[test]
766 fn test_explicit_non_default_not_indexed_initial_source_no() {
767 let mut context = Context::new();
768 context.index_property::<Person, ExplicitProp2>(); for i in 0..100 {
771 context
772 .add_entity(with!(
773 Person,
774 ExplicitProp((i % 20) as u8),
775 ExplicitProp2(i % 2 == 0)
776 ))
777 .unwrap();
778 }
779
780 let results = context
782 .query_result_iterator(with!(Person, ExplicitProp(5), ExplicitProp2(false)))
783 .collect::<Vec<_>>();
784
785 let expected = results.len();
789 assert!(expected > 0);
790 for person in results {
791 assert_eq!(
792 context.get_property::<Person, ExplicitProp>(person),
793 ExplicitProp(5)
794 );
795 assert_eq!(
796 context.get_property::<Person, ExplicitProp2>(person),
797 ExplicitProp2(false)
798 );
799 }
800 }
801
802 #[test]
804 fn test_explicit_non_default_indexed_initial_source_no() {
805 let mut context = Context::new();
806 context.index_property::<Person, ExplicitProp>();
807 context.index_property::<Person, ConstantProp2>(); for i in 0..100 {
810 if i < 10 {
811 context
812 .add_entity(with!(
813 Person,
814 ExplicitProp(7),
815 ExplicitProp2(false),
816 ConstantProp2(200), ))
818 .unwrap();
819 } else {
820 context
821 .add_entity(with!(
822 Person,
823 ExplicitProp((i % 20) as u8),
824 ExplicitProp2(false)
825 ))
826 .unwrap();
827 }
828 }
829
830 let results = context
831 .query_result_iterator(with!(Person, ExplicitProp(7), ConstantProp2(200)))
832 .collect::<Vec<_>>();
833
834 assert_eq!(results.len(), 10);
835 }
836
837 #[test]
839 fn test_constant_default_not_indexed_initial_source_no() {
840 let mut context = Context::new();
841 context.index_property::<Person, ExplicitProp>(); for i in 0..100 {
844 if i < 5 {
845 context
846 .add_entity(with!(Person, ExplicitProp(99), ExplicitProp2(false)))
847 .unwrap(); } else {
849 context
850 .add_entity(with!(
851 Person,
852 ExplicitProp((i % 20) as u8),
853 ExplicitProp2(false)
854 ))
855 .unwrap();
856 }
857 }
858
859 let results = context
860 .query_result_iterator(with!(Person, ExplicitProp(99), ConstantProp(42)))
861 .collect::<Vec<_>>();
862
863 assert_eq!(results.len(), 5);
864 for person in results {
865 assert_eq!(
866 context.get_property::<Person, ConstantProp>(person),
867 ConstantProp(42)
868 );
869 }
870 }
871
872 #[test]
874 fn test_constant_non_default_indexed_initial_source_no() {
875 let mut context = Context::new();
876 context.index_property::<Person, ConstantProp>();
877 context.index_property::<Person, ExplicitProp2>();
878
879 for i in 0..100 {
880 if i < 10 {
881 context
882 .add_entity(with!(
883 Person,
884 ConstantProp(99),
885 ExplicitProp(0),
886 ExplicitProp2(true)
887 ))
888 .unwrap();
889 } else {
890 context
891 .add_entity(with!(Person, ExplicitProp(0), ExplicitProp2(false)))
892 .unwrap();
893 }
894 }
895
896 let results = context
897 .query_result_iterator(with!(Person, ConstantProp(99), ExplicitProp2(true)))
898 .collect::<Vec<_>>();
899
900 assert_eq!(results.len(), 10);
901 }
902
903 #[test]
905 fn test_derived_not_indexed_initial_source_no() {
906 let mut context = Context::new();
907 context.index_property::<Person, ExplicitProp2>();
908
909 for i in 0..100 {
910 context
911 .add_entity(with!(Person, ExplicitProp(i as u8), ExplicitProp2(i < 50)))
912 .unwrap();
913 }
914
915 let results = context
916 .query_result_iterator(with!(Person, ExplicitProp2(true), DerivedProp(true)))
917 .collect::<Vec<_>>();
918
919 assert_eq!(results.len(), 25);
922 }
923
924 #[test]
926 fn test_derived_indexed_initial_source_no() {
927 let mut context = Context::new();
928 context.index_property::<Person, DerivedProp>();
929 context.index_property::<Person, ExplicitProp2>();
930
931 for i in 0..100 {
932 context
933 .add_entity(with!(Person, ExplicitProp(i as u8), ExplicitProp2(i < 30)))
934 .unwrap();
935 }
936
937 let results = context
938 .query_result_iterator(with!(Person, ExplicitProp2(true), DerivedProp(false)))
939 .collect::<Vec<_>>();
940
941 assert_eq!(results.len(), 15);
944 }
945
946 #[test]
949 fn test_multiple_query_result_iterators() {
950 let mut context = Context::new();
951 context.index_property::<Person, Age>();
952
953 for age in 0..100 {
954 context
955 .add_entity(with!(
956 Person,
957 Age(age),
958 ExplicitProp(age.wrapping_mul(7) % 100),
959 ExplicitProp2(false),
960 ))
961 .unwrap();
962 }
963 for age in 0..100 {
964 context
965 .add_entity(with!(
966 Person,
967 Age(age),
968 ExplicitProp(age.wrapping_mul(14) % 100),
969 ExplicitProp2(false),
970 ))
971 .unwrap();
972 }
973
974 let results = context.query_result_iterator(with!(Person, Age(25)));
977 let more_results = context.query_result_iterator(with!(Person, Age(25), ExplicitProp(75)));
978
979 let collected_results = results.collect::<IndexSet<_>>();
980 let other_collected_results = more_results.collect::<IndexSet<_>>();
981 let intersection_count = collected_results
982 .intersection(&other_collected_results)
983 .count();
984 assert_eq!(intersection_count, 1);
985 }
986
987 #[test]
988 fn test_expression_intersection_iteration() {
989 let set = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..10)).intersection(
990 EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..6)),
991 );
992
993 let ids = set.into_iter().collect::<Vec<_>>();
994 let expected = (0..6).map(EntityId::new).collect::<Vec<_>>();
995 assert_eq!(ids, expected);
996 }
997
998 #[test]
999 fn test_expression_difference_iteration() {
1000 let set = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..5)).difference(
1001 EntitySet::from_source(SourceSet::<Person>::PopulationRange(2..3)),
1002 );
1003
1004 let ids = set.into_iter().collect::<Vec<_>>();
1005 let expected = vec![
1006 EntityId::new(0),
1007 EntityId::new(1),
1008 EntityId::new(3),
1009 EntityId::new(4),
1010 ];
1011 assert_eq!(ids, expected);
1012 }
1013
1014 #[test]
1015 fn test_expression_union_deduplicates() {
1016 let left = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..3)).difference(
1017 EntitySet::from_source(SourceSet::<Person>::PopulationRange(99..100)),
1018 );
1019 let right = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..5)).difference(
1020 EntitySet::from_source(SourceSet::<Person>::PopulationRange(99..100)),
1021 );
1022 let set = left.union(right);
1023
1024 let ids = set.into_iter().collect::<Vec<_>>();
1025 let expected = (0..5).map(EntityId::new).collect::<Vec<_>>();
1026 assert_eq!(ids, expected);
1027 }
1028
1029 #[test]
1030 fn test_expression_union_overlap_no_duplicates() {
1031 let left = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..5)).difference(
1032 EntitySet::from_source(SourceSet::<Person>::PopulationRange(4..5)),
1033 );
1034 let right = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..7)).difference(
1035 EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..1)),
1036 );
1037
1038 let ids = left.union(right).into_iter().collect::<IndexSet<_>>();
1039 let expected = (0..7).map(EntityId::new).collect::<IndexSet<_>>();
1040 assert_eq!(ids, expected);
1041 }
1042
1043 #[test]
1044 fn test_expression_intersection_of_unions() {
1045 let ab = EntitySet::from_source(SourceSet::<Person>::PopulationRange(1..2))
1046 .union(EntitySet::from_source(
1047 SourceSet::<Person>::PopulationRange(2..3),
1048 ))
1049 .union(EntitySet::from_source(
1050 SourceSet::<Person>::PopulationRange(3..4),
1051 ));
1052 let cd = EntitySet::from_source(SourceSet::<Person>::PopulationRange(2..3))
1053 .union(EntitySet::from_source(
1054 SourceSet::<Person>::PopulationRange(3..4),
1055 ))
1056 .union(EntitySet::from_source(
1057 SourceSet::<Person>::PopulationRange(4..5),
1058 ));
1059
1060 let ids = ab.intersection(cd).into_iter().collect::<Vec<_>>();
1061 assert_eq!(ids, vec![EntityId::new(2), EntityId::new(3)]);
1062 }
1063
1064 #[test]
1065 fn test_expression_difference_not_commutative() {
1066 let left = EntitySet::from_source(SourceSet::<Person>::PopulationRange(1..2))
1067 .union(EntitySet::from_source(
1068 SourceSet::<Person>::PopulationRange(2..3),
1069 ))
1070 .union(EntitySet::from_source(
1071 SourceSet::<Person>::PopulationRange(3..4),
1072 ));
1073 let right = EntitySet::from_source(SourceSet::<Person>::PopulationRange(2..3))
1074 .union(EntitySet::from_source(
1075 SourceSet::<Person>::PopulationRange(3..4),
1076 ))
1077 .union(EntitySet::from_source(
1078 SourceSet::<Person>::PopulationRange(4..5),
1079 ));
1080
1081 let left_minus_right = left.difference(right).into_iter().collect::<Vec<_>>();
1082 let right_minus_left = EntitySet::from_source(SourceSet::<Person>::PopulationRange(2..3))
1083 .union(EntitySet::from_source(
1084 SourceSet::<Person>::PopulationRange(3..4),
1085 ))
1086 .union(EntitySet::from_source(
1087 SourceSet::<Person>::PopulationRange(4..5),
1088 ))
1089 .difference(
1090 EntitySet::from_source(SourceSet::<Person>::PopulationRange(1..2))
1091 .union(EntitySet::from_source(
1092 SourceSet::<Person>::PopulationRange(2..3),
1093 ))
1094 .union(EntitySet::from_source(
1095 SourceSet::<Person>::PopulationRange(3..4),
1096 )),
1097 )
1098 .into_iter()
1099 .collect::<Vec<_>>();
1100
1101 assert_eq!(left_minus_right, vec![EntityId::new(1)]);
1102 assert_eq!(right_minus_left, vec![EntityId::new(4)]);
1103 }
1104
1105 #[test]
1106 fn test_union_size_hint_pending_right_is_unknown() {
1107 let left = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..2)).difference(
1108 EntitySet::from_source(SourceSet::<Person>::PopulationRange(99..100)),
1109 );
1110 let right = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..4)).difference(
1111 EntitySet::from_source(SourceSet::<Person>::PopulationRange(98..99)),
1112 );
1113 let iter = left.union(right).into_iter();
1114
1115 assert_eq!(iter.size_hint(), (4, Some(4)));
1116 }
1117
1118 #[test]
1119 fn test_nth_and_count_on_source() {
1120 let mut iter =
1121 EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..5)).into_iter();
1122 assert_eq!(iter.nth(2), Some(EntityId::new(2)));
1123
1124 let remaining = iter.count();
1125 assert_eq!(remaining, 2);
1126 }
1127
1128 #[test]
1129 fn population_range_source_iteration_and_size_hint() {
1130 let mut iter =
1131 EntitySet::from_source(SourceSet::<Person>::PopulationRange(3..7)).into_iter();
1132 assert_eq!(iter.size_hint(), (4, Some(4)));
1133 assert_eq!(iter.next(), Some(EntityId::new(3)));
1134 assert_eq!(iter.size_hint(), (3, Some(3)));
1135 assert_eq!(
1136 iter.collect::<Vec<_>>(),
1137 vec![EntityId::new(4), EntityId::new(5), EntityId::new(6)]
1138 );
1139 }
1140
1141 #[test]
1142 fn optimized_range_results_iterate_as_single_source() {
1143 let union = EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..3)).union(
1144 EntitySet::from_source(SourceSet::<Person>::PopulationRange(3..5)),
1145 );
1146 assert_eq!(
1147 union.into_iter().collect::<Vec<_>>(),
1148 vec![
1149 EntityId::new(0),
1150 EntityId::new(1),
1151 EntityId::new(2),
1152 EntityId::new(3),
1153 EntityId::new(4),
1154 ]
1155 );
1156
1157 let intersection = EntitySet::from_source(SourceSet::<Person>::PopulationRange(2..8))
1158 .intersection(EntitySet::from_source(
1159 SourceSet::<Person>::PopulationRange(4..6),
1160 ));
1161 assert_eq!(
1162 intersection.into_iter().collect::<Vec<_>>(),
1163 vec![EntityId::new(4), EntityId::new(5)]
1164 );
1165 }
1166
1167 #[test]
1168 fn split_difference_still_uses_generic_iteration_path() {
1169 let split = EntitySet::from_source(SourceSet::<Person>::PopulationRange(2..8)).difference(
1170 EntitySet::from_source(SourceSet::<Person>::PopulationRange(4..6)),
1171 );
1172 assert_eq!(
1173 split.into_iter().collect::<Vec<_>>(),
1174 vec![
1175 EntityId::new(2),
1176 EntityId::new(3),
1177 EntityId::new(6),
1178 EntityId::new(7)
1179 ]
1180 );
1181 }
1182
1183 fn finite_set(ids: &[usize]) -> FxIndexSet<EntityId<Person>> {
1184 ids.iter()
1185 .copied()
1186 .map(EntityId::new)
1187 .collect::<FxIndexSet<_>>()
1188 }
1189
1190 fn as_entity_set(set: &FxIndexSet<EntityId<Person>>) -> EntitySet<Person> {
1191 EntitySet::from_source(SourceSet::IndexSet(set))
1192 }
1193
1194 #[test]
1195 fn prototype_empty_entity_set_yields_nothing() {
1196 let ids = EntitySet::<Person>::empty().into_iter().collect::<Vec<_>>();
1197 assert!(ids.is_empty());
1198 }
1199
1200 #[test]
1201 fn prototype_iter_union_disjoint() {
1202 let a = finite_set(&[1, 2]);
1203 let b = finite_set(&[3, 4]);
1204 let ids = as_entity_set(&a)
1205 .union(as_entity_set(&b))
1206 .into_iter()
1207 .collect::<IndexSet<_>>();
1208 let expected = [1usize, 2, 3, 4]
1209 .into_iter()
1210 .map(EntityId::new)
1211 .collect::<IndexSet<_>>();
1212 assert_eq!(ids, expected);
1213 }
1214
1215 #[test]
1216 fn prototype_iter_union_overlapping() {
1217 let a = finite_set(&[1, 2, 3]);
1218 let b = finite_set(&[2, 3, 4]);
1219 let ids = as_entity_set(&a)
1220 .union(as_entity_set(&b))
1221 .into_iter()
1222 .collect::<Vec<_>>();
1223 let unique = ids.iter().copied().collect::<IndexSet<_>>();
1224 assert_eq!(ids.len(), unique.len());
1225 assert!(unique.contains(&EntityId::new(1)));
1226 assert!(unique.contains(&EntityId::new(4)));
1227 }
1228
1229 #[test]
1230 fn prototype_iter_intersection_disjoint() {
1231 let a = finite_set(&[1, 2]);
1232 let b = finite_set(&[3, 4]);
1233 let ids = as_entity_set(&a)
1234 .intersection(as_entity_set(&b))
1235 .into_iter()
1236 .collect::<Vec<_>>();
1237 assert!(ids.is_empty());
1238 }
1239
1240 #[test]
1241 fn prototype_iter_difference_basic() {
1242 let a = finite_set(&[1, 2, 3, 4]);
1243 let b = finite_set(&[3, 4, 5, 6]);
1244 let ids = as_entity_set(&a)
1245 .difference(as_entity_set(&b))
1246 .into_iter()
1247 .collect::<IndexSet<_>>();
1248 assert_eq!(ids.len(), 2);
1249 assert!(ids.contains(&EntityId::new(1)));
1250 assert!(ids.contains(&EntityId::new(2)));
1251 }
1252
1253 #[test]
1254 fn prototype_iter_matches_contains_compound() {
1255 let a = finite_set(&[1, 2, 3, 4]);
1256 let b = finite_set(&[3, 4, 5]);
1257 let c = finite_set(&[7, 8, 9, 10]);
1258 let d = finite_set(&[9, 10, 11]);
1259 let left = as_entity_set(&a).intersection(as_entity_set(&b));
1260 let right = as_entity_set(&c).difference(as_entity_set(&d));
1261 let iterated = left.union(right).into_iter().collect::<IndexSet<_>>();
1262
1263 let a2 = finite_set(&[1, 2, 3, 4]);
1264 let b2 = finite_set(&[3, 4, 5]);
1265 let c2 = finite_set(&[7, 8, 9, 10]);
1266 let d2 = finite_set(&[9, 10, 11]);
1267 let check = as_entity_set(&a2)
1268 .intersection(as_entity_set(&b2))
1269 .union(as_entity_set(&c2).difference(as_entity_set(&d2)));
1270
1271 for value in 0..15 {
1272 let entity = EntityId::new(value);
1273 assert_eq!(iterated.contains(&entity), check.contains(entity));
1274 }
1275 }
1276
1277 #[test]
1278 fn prototype_size_hint_single_source_and_partial_consume() {
1279 let mut iter =
1280 EntitySet::from_source(SourceSet::<Person>::PopulationRange(0..5)).into_iter();
1281 assert_eq!(iter.size_hint(), (5, Some(5)));
1282 iter.next();
1283 assert_eq!(iter.size_hint(), (4, Some(4)));
1284 }
1285}