ixa/entity/query/
query_impls.rs

1use std::any::TypeId;
2
3use seq_macro::seq;
4
5use crate::entity::entity_set::{EntitySet, EntitySetIterator, SourceSet};
6use crate::entity::index::IndexSetResult;
7use crate::entity::property::Property;
8use crate::entity::query::QueryInternal;
9use crate::entity::{ContextEntitiesExt, Entity, EntityId};
10use crate::Context;
11
12impl<E: Entity> QueryInternal<E> for () {
13    type QueryParts<'a>
14        = [&'a dyn std::any::Any; 0]
15    where
16        Self: 'a;
17
18    fn get_type_ids(&self) -> Vec<TypeId> {
19        Vec::new()
20    }
21
22    fn multi_property_id(&self) -> Option<usize> {
23        None
24    }
25
26    fn is_empty_query(&self) -> bool {
27        true
28    }
29
30    fn query_parts(&self) -> Self::QueryParts<'_> {
31        []
32    }
33
34    fn new_query_result<'c>(&self, context: &'c Context) -> EntitySet<'c, E> {
35        EntitySet::from_source(SourceSet::PopulationRange(
36            0..context.get_entity_count::<E>(),
37        ))
38    }
39
40    fn new_query_result_iterator<'c>(&self, context: &'c Context) -> EntitySetIterator<'c, E> {
41        EntitySetIterator::from_population_iterator(context.get_entity_iterator::<E>())
42    }
43
44    fn match_entity(&self, _entity_id: EntityId<E>, _context: &Context) -> bool {
45        // Every entity matches the empty query.
46        true
47    }
48
49    fn filter_entities(&self, _entities: &mut Vec<EntityId<E>>, _context: &Context) {
50        // Nothing to do.
51    }
52}
53
54// An Entity ZST itself is an empty query matching all entities of that type.
55// This allows `context.sample_entity(Rng, Person)` instead of `context.sample_entity(Rng, ())`.
56impl<E: Entity> QueryInternal<E> for E {
57    type QueryParts<'a>
58        = [&'a dyn std::any::Any; 0]
59    where
60        Self: 'a;
61
62    fn get_type_ids(&self) -> Vec<TypeId> {
63        Vec::new()
64    }
65
66    fn multi_property_id(&self) -> Option<usize> {
67        None
68    }
69
70    fn is_empty_query(&self) -> bool {
71        true
72    }
73
74    fn query_parts(&self) -> Self::QueryParts<'_> {
75        []
76    }
77
78    fn new_query_result<'c>(&self, context: &'c Context) -> EntitySet<'c, E> {
79        EntitySet::from_source(SourceSet::PopulationRange(
80            0..context.get_entity_count::<E>(),
81        ))
82    }
83
84    fn new_query_result_iterator<'c>(&self, context: &'c Context) -> EntitySetIterator<'c, E> {
85        let population_iterator = context.get_entity_iterator::<E>();
86        EntitySetIterator::from_population_iterator(population_iterator)
87    }
88
89    fn match_entity(&self, _entity_id: EntityId<E>, _context: &Context) -> bool {
90        true
91    }
92
93    fn filter_entities(&self, _entities: &mut Vec<EntityId<E>>, _context: &Context) {
94        // Nothing to do.
95    }
96}
97
98// Implement the query version with one parameter.
99impl<E: Entity, P1: Property<E>> QueryInternal<E> for (P1,) {
100    type QueryParts<'a>
101        = P1::QueryParts<'a>
102    where
103        Self: 'a;
104
105    fn get_type_ids(&self) -> Vec<TypeId> {
106        vec![P1::type_id()]
107    }
108
109    fn multi_property_id(&self) -> Option<usize> {
110        // While not a "true" multi-property, it is convenient to have this method return the
111        // `TypeId` of the singleton property.
112        Some(P1::index_id())
113    }
114
115    fn query_parts(&self) -> Self::QueryParts<'_> {
116        P1::query_parts_for_value(&self.0)
117    }
118
119    fn new_query_result<'c>(&self, context: &'c Context) -> EntitySet<'c, E> {
120        let property_store = context.entity_store.get_property_store::<E>();
121
122        // The case of an indexed multi-property.
123        // This mirrors the indexed case in `SourceSet<'a, E>::new()`. The difference is, if the
124        // multi-property is unindexed, we fall through to create `SourceSet`s for the components
125        // rather than wrapping a `DerivedPropertySource`.
126        if let Some(multi_property_id) = self.multi_property_id() {
127            let query_parts = P1::query_parts_for_value(&self.0);
128            let lookup_result = property_store
129                .get_index_set_for_query_parts(multi_property_id, query_parts.as_ref());
130            match lookup_result {
131                IndexSetResult::Set(people_set) => {
132                    return EntitySet::from_source(SourceSet::IndexSet(people_set));
133                }
134                IndexSetResult::Empty => {
135                    return EntitySet::empty();
136                }
137                IndexSetResult::Unsupported => {}
138            }
139            // If the property is not indexed, we fall through.
140        }
141
142        // We create a source set for each property.
143        let mut sources: Vec<SourceSet<E>> = Vec::new();
144
145        if let Some(source_set) = SourceSet::new::<P1>(self.0, context) {
146            sources.push(source_set);
147        } else {
148            // If a single source set is empty, the intersection of all sources is empty.
149            return EntitySet::empty();
150        }
151
152        EntitySet::from_intersection_sources(sources)
153    }
154
155    fn new_query_result_iterator<'c>(&self, context: &'c Context) -> EntitySetIterator<'c, E> {
156        // Constructing the `EntitySetIterator` directly instead of constructing an `EntitySet`
157        // first is a micro-optimization improving tight-loop benchmark performance.
158        let property_store = context.entity_store.get_property_store::<E>();
159
160        if let Some(multi_property_id) = self.multi_property_id() {
161            let query_parts = P1::query_parts_for_value(&self.0);
162            let lookup_result = property_store
163                .get_index_set_for_query_parts(multi_property_id, query_parts.as_ref());
164            match lookup_result {
165                IndexSetResult::Set(people_set) => {
166                    return EntitySetIterator::from_index_set(people_set);
167                }
168                IndexSetResult::Empty => {
169                    return EntitySetIterator::empty();
170                }
171                IndexSetResult::Unsupported => {}
172            }
173        }
174
175        let mut sources: Vec<SourceSet<E>> = Vec::new();
176
177        if let Some(source_set) = SourceSet::new::<P1>(self.0, context) {
178            sources.push(source_set);
179        } else {
180            return EntitySetIterator::empty();
181        }
182
183        EntitySetIterator::from_sources(sources)
184    }
185
186    fn match_entity(&self, entity_id: EntityId<E>, context: &Context) -> bool {
187        let found_value: P1 = context.get_property(entity_id);
188        found_value == self.0
189    }
190
191    fn filter_entities(&self, entities: &mut Vec<EntityId<E>>, context: &Context) {
192        let property_value_store = context.get_property_value_store::<E, P1>();
193        entities.retain(|entity| self.0 == property_value_store.get(*entity));
194    }
195}
196
197macro_rules! impl_query {
198    ($ct:expr) => {
199        seq!(N in 0..$ct {
200            impl<
201                E: Entity,
202                #(
203                    T~N : Property<E>,
204                )*
205            > QueryInternal<E> for (
206                #(
207                    T~N,
208                )*
209            )
210            {
211                type QueryParts<'a> = [&'a dyn std::any::Any; $ct] where Self: 'a;
212
213                fn get_type_ids(&self) -> Vec<TypeId> {
214                    vec![
215                        #(
216                            <T~N as $crate::entity::property::Property<E>>::type_id(),
217                        )*
218                    ]
219                }
220
221                fn query_parts(&self) -> Self::QueryParts<'_> {
222                    let keys = [
223                        #(
224                            <T~N as $crate::entity::property::Property<E>>::name(),
225                        )*
226                    ];
227                    let mut query_parts = [
228                        #(
229                            &self.N as &dyn std::any::Any,
230                        )*
231                    ];
232                    $crate::entity::multi_property::static_reorder_by_keys(&keys, &mut query_parts);
233                    query_parts
234                }
235
236                fn new_query_result<'c>(&self, context: &'c Context) -> EntitySet<'c, E> {
237                    // The case of an indexed multi-property.
238                    // This mirrors the indexed case in `SourceSet<'a, E>::new()`. The difference is, if the
239                    // multi-property is unindexed, we fall through to create `SourceSet`s for the components
240                    // rather than wrapping a `DerivedPropertySource`.
241                    if let Some(multi_property_id) = <Self as $crate::entity::QueryInternal<E>>::multi_property_id(self) {
242                        let property_store = context.entity_store.get_property_store::<E>();
243                        let query_parts = <Self as $crate::entity::QueryInternal<E>>::query_parts(self);
244                        let lookup_result = property_store.get_index_set_for_query_parts(
245                            multi_property_id,
246                            query_parts.as_ref(),
247                        );
248                        match lookup_result {
249                            $crate::entity::index::IndexSetResult::Set(entity_set) => {
250                                return EntitySet::from_source(SourceSet::IndexSet(entity_set));
251                            }
252                            $crate::entity::index::IndexSetResult::Empty => {
253                                return EntitySet::empty();
254                            }
255                            $crate::entity::index::IndexSetResult::Unsupported => {}
256                        }
257                        // If the property is not indexed, we fall through.
258                    }
259
260                    // We create a source set for each property.
261                    let mut sources: Vec<SourceSet<E>> = Vec::new();
262
263                    #(
264                        if let Some(source_set) = SourceSet::new::<T~N>(self.N, context) {
265                            sources.push(source_set);
266                        } else {
267                            // If a single source set is empty, the intersection of all sources is empty.
268                            return EntitySet::empty();
269                        }
270                    )*
271
272                    EntitySet::from_intersection_sources(sources)
273                }
274
275                fn new_query_result_iterator<'c>(&self, context: &'c Context) -> EntitySetIterator<'c, E> {
276                    // Constructing the `EntitySetIterator` directly instead of constructing an `EntitySet`
277                    // first is a micro-optimization improving tight-loop benchmark performance.
278                    if let Some(multi_property_id) = <Self as $crate::entity::QueryInternal<E>>::multi_property_id(self) {
279                        let property_store = context.entity_store.get_property_store::<E>();
280                        let query_parts = <Self as $crate::entity::QueryInternal<E>>::query_parts(self);
281                        let lookup_result = property_store.get_index_set_for_query_parts(
282                            multi_property_id,
283                            query_parts.as_ref(),
284                        );
285                        match lookup_result {
286                            $crate::entity::index::IndexSetResult::Set(entity_set) => {
287                                return EntitySetIterator::from_index_set(entity_set);
288                            }
289                            $crate::entity::index::IndexSetResult::Empty => {
290                                return EntitySetIterator::empty();
291                            }
292                            $crate::entity::index::IndexSetResult::Unsupported => {}
293                        }
294                    }
295
296                    let mut sources: Vec<SourceSet<E>> = Vec::new();
297
298                    #(
299                        if let Some(source_set) = SourceSet::new::<T~N>(self.N, context) {
300                            sources.push(source_set);
301                        } else {
302                            return EntitySetIterator::empty();
303                        }
304                    )*
305
306                    EntitySetIterator::from_sources(sources)
307                }
308
309                fn match_entity(&self, entity_id: EntityId<E>, context: &Context) -> bool {
310                    #(
311                        {
312                            let found_value: T~N = context.get_property(entity_id);
313                            if found_value != self.N {
314                                return false
315                            }
316                        }
317                    )*
318                    true
319                }
320
321                fn filter_entities(&self, entities: &mut Vec<EntityId<E>>, context: &Context) {
322                    // The fast path: If this query is indexed, we only have to do one pass over the entities.
323                    if let Some(multi_property_id) = <Self as $crate::entity::QueryInternal<E>>::multi_property_id(self) {
324                        let property_store = context.entity_store.get_property_store::<E>();
325                        let query_parts = <Self as $crate::entity::QueryInternal<E>>::query_parts(self);
326                        let lookup_result = property_store.get_index_set_for_query_parts(
327                            multi_property_id,
328                            query_parts.as_ref(),
329                        );
330                        match lookup_result {
331                            $crate::entity::index::IndexSetResult::Set(entity_set) => {
332                                entities.retain(|entity_id| entity_set.contains(entity_id));
333                                return;
334                            }
335                            $crate::entity::index::IndexSetResult::Empty => {
336                                entities.clear();
337                                return;
338                            }
339                            $crate::entity::index::IndexSetResult::Unsupported => {}
340                        }
341                        // If the property is not indexed, we fall through.
342                    }
343
344                    // The slow path: Check each property of the query separately.
345                    #(
346                        {
347                            let property_value_store = context.get_property_value_store::<E, T~N>();
348                            entities.retain(
349                                |entity|{
350                                    self.N == property_value_store.get(*entity)
351                                }
352                            );
353                        }
354                    )*
355                }
356            }
357        });
358    }
359}
360
361// Implement the versions with 2..20 parameters. (The 0 and 1 case are implemented above.)
362seq!(Z in 2..20 {
363    impl_query!(Z);
364});