Skip to main content

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        Some(P1::id())
111    }
112
113    fn query_parts(&self) -> Self::QueryParts<'_> {
114        P1::query_parts_for_value(&self.0)
115    }
116
117    fn new_query_result<'c>(&self, context: &'c Context) -> EntitySet<'c, E> {
118        let property_store = context.entity_store.get_property_store::<E>();
119
120        // The case of an indexed multi-property.
121        // This mirrors the indexed case in `SourceSet<'a, E>::new()`. The difference is, if the
122        // multi-property is unindexed, we fall through to create `SourceSet`s for the components
123        // rather than wrapping a `DerivedPropertySource`.
124        if let Some(multi_property_id) = self.multi_property_id() {
125            let query_parts = P1::query_parts_for_value(&self.0);
126            let lookup_result = property_store
127                .get_index_set_for_query_parts(multi_property_id, query_parts.as_ref());
128            match lookup_result {
129                IndexSetResult::Set(people_set) => {
130                    return EntitySet::from_source(SourceSet::IndexSet(people_set));
131                }
132                IndexSetResult::Empty => {
133                    return EntitySet::empty();
134                }
135                IndexSetResult::Unsupported => {}
136            }
137            // If the property is not indexed, we fall through.
138        }
139
140        // We create a source set for each property.
141        let mut sources: Vec<SourceSet<E>> = Vec::new();
142
143        if let Some(source_set) = SourceSet::new::<P1>(self.0, context) {
144            sources.push(source_set);
145        } else {
146            // If a single source set is empty, the intersection of all sources is empty.
147            return EntitySet::empty();
148        }
149
150        EntitySet::from_intersection_sources(sources)
151    }
152
153    fn new_query_result_iterator<'c>(&self, context: &'c Context) -> EntitySetIterator<'c, E> {
154        // Constructing the `EntitySetIterator` directly instead of constructing an `EntitySet`
155        // first is a micro-optimization improving tight-loop benchmark performance.
156        let property_store = context.entity_store.get_property_store::<E>();
157
158        if let Some(multi_property_id) = self.multi_property_id() {
159            let query_parts = P1::query_parts_for_value(&self.0);
160            let lookup_result = property_store
161                .get_index_set_for_query_parts(multi_property_id, query_parts.as_ref());
162            match lookup_result {
163                IndexSetResult::Set(people_set) => {
164                    return EntitySetIterator::from_index_set(people_set);
165                }
166                IndexSetResult::Empty => {
167                    return EntitySetIterator::empty();
168                }
169                IndexSetResult::Unsupported => {}
170            }
171        }
172
173        let mut sources: Vec<SourceSet<E>> = Vec::new();
174
175        if let Some(source_set) = SourceSet::new::<P1>(self.0, context) {
176            sources.push(source_set);
177        } else {
178            return EntitySetIterator::empty();
179        }
180
181        EntitySetIterator::from_sources(sources)
182    }
183
184    fn match_entity(&self, entity_id: EntityId<E>, context: &Context) -> bool {
185        let found_value: P1 = context.get_property(entity_id);
186        found_value == self.0
187    }
188
189    fn filter_entities(&self, entities: &mut Vec<EntityId<E>>, context: &Context) {
190        let property_value_store = context.get_property_value_store::<E, P1>();
191        entities.retain(|entity| self.0 == property_value_store.get(*entity));
192    }
193}
194
195macro_rules! impl_query {
196    ($ct:expr) => {
197        seq!(N in 0..$ct {
198            impl<
199                E: Entity,
200                #(
201                    T~N : Property<E>,
202                )*
203            > QueryInternal<E> for (
204                #(
205                    T~N,
206                )*
207            )
208            {
209                type QueryParts<'a> = [&'a dyn std::any::Any; $ct] where Self: 'a;
210
211                fn get_type_ids(&self) -> Vec<TypeId> {
212                    vec![
213                        #(
214                            <T~N as $crate::entity::property::Property<E>>::type_id(),
215                        )*
216                    ]
217                }
218
219                fn query_parts(&self) -> Self::QueryParts<'_> {
220                    let keys = [
221                        #(
222                            <T~N as $crate::entity::property::Property<E>>::type_id(),
223                        )*
224                    ];
225                    let mut query_parts = [
226                        #(
227                            &self.N as &dyn std::any::Any,
228                        )*
229                    ];
230                    $crate::entity::multi_property::static_reorder_by_keys(&keys, &mut query_parts);
231                    query_parts
232                }
233
234                fn new_query_result<'c>(&self, context: &'c Context) -> EntitySet<'c, E> {
235                    // The case of an indexed multi-property.
236                    // This mirrors the indexed case in `SourceSet<'a, E>::new()`. The difference is, if the
237                    // multi-property is unindexed, we fall through to create `SourceSet`s for the components
238                    // rather than wrapping a `DerivedPropertySource`.
239                    if let Some(multi_property_id) = <Self as $crate::entity::QueryInternal<E>>::multi_property_id(self) {
240                        let property_store = context.entity_store.get_property_store::<E>();
241                        let query_parts = <Self as $crate::entity::QueryInternal<E>>::query_parts(self);
242                        let lookup_result = property_store.get_index_set_for_query_parts(
243                            multi_property_id,
244                            query_parts.as_ref(),
245                        );
246                        match lookup_result {
247                            $crate::entity::index::IndexSetResult::Set(entity_set) => {
248                                return EntitySet::from_source(SourceSet::IndexSet(entity_set));
249                            }
250                            $crate::entity::index::IndexSetResult::Empty => {
251                                return EntitySet::empty();
252                            }
253                            $crate::entity::index::IndexSetResult::Unsupported => {}
254                        }
255                        // If the property is not indexed, we fall through.
256                    }
257
258                    // We create a source set for each property.
259                    let mut sources: Vec<SourceSet<E>> = Vec::new();
260
261                    #(
262                        if let Some(source_set) = SourceSet::new::<T~N>(self.N, context) {
263                            sources.push(source_set);
264                        } else {
265                            // If a single source set is empty, the intersection of all sources is empty.
266                            return EntitySet::empty();
267                        }
268                    )*
269
270                    EntitySet::from_intersection_sources(sources)
271                }
272
273                fn new_query_result_iterator<'c>(&self, context: &'c Context) -> EntitySetIterator<'c, E> {
274                    // Constructing the `EntitySetIterator` directly instead of constructing an `EntitySet`
275                    // first is a micro-optimization improving tight-loop benchmark performance.
276                    if let Some(multi_property_id) = <Self as $crate::entity::QueryInternal<E>>::multi_property_id(self) {
277                        let property_store = context.entity_store.get_property_store::<E>();
278                        let query_parts = <Self as $crate::entity::QueryInternal<E>>::query_parts(self);
279                        let lookup_result = property_store.get_index_set_for_query_parts(
280                            multi_property_id,
281                            query_parts.as_ref(),
282                        );
283                        match lookup_result {
284                            $crate::entity::index::IndexSetResult::Set(entity_set) => {
285                                return EntitySetIterator::from_index_set(entity_set);
286                            }
287                            $crate::entity::index::IndexSetResult::Empty => {
288                                return EntitySetIterator::empty();
289                            }
290                            $crate::entity::index::IndexSetResult::Unsupported => {}
291                        }
292                    }
293
294                    let mut sources: Vec<SourceSet<E>> = Vec::new();
295
296                    #(
297                        if let Some(source_set) = SourceSet::new::<T~N>(self.N, context) {
298                            sources.push(source_set);
299                        } else {
300                            return EntitySetIterator::empty();
301                        }
302                    )*
303
304                    EntitySetIterator::from_sources(sources)
305                }
306
307                fn match_entity(&self, entity_id: EntityId<E>, context: &Context) -> bool {
308                    #(
309                        {
310                            let found_value: T~N = context.get_property(entity_id);
311                            if found_value != self.N {
312                                return false
313                            }
314                        }
315                    )*
316                    true
317                }
318
319                fn filter_entities(&self, entities: &mut Vec<EntityId<E>>, context: &Context) {
320                    // The fast path: If this query is indexed, we only have to do one pass over the entities.
321                    if let Some(multi_property_id) = <Self as $crate::entity::QueryInternal<E>>::multi_property_id(self) {
322                        let property_store = context.entity_store.get_property_store::<E>();
323                        let query_parts = <Self as $crate::entity::QueryInternal<E>>::query_parts(self);
324                        let lookup_result = property_store.get_index_set_for_query_parts(
325                            multi_property_id,
326                            query_parts.as_ref(),
327                        );
328                        match lookup_result {
329                            $crate::entity::index::IndexSetResult::Set(entity_set) => {
330                                entities.retain(|entity_id| entity_set.contains(entity_id));
331                                return;
332                            }
333                            $crate::entity::index::IndexSetResult::Empty => {
334                                entities.clear();
335                                return;
336                            }
337                            $crate::entity::index::IndexSetResult::Unsupported => {}
338                        }
339                        // If the property is not indexed, we fall through.
340                    }
341
342                    // The slow path: Check each property of the query separately.
343                    #(
344                        {
345                            let property_value_store = context.get_property_value_store::<E, T~N>();
346                            entities.retain(
347                                |entity|{
348                                    self.N == property_value_store.get(*entity)
349                                }
350                            );
351                        }
352                    )*
353                }
354            }
355        });
356    }
357}
358
359// Implement the versions with 2..20 parameters. (The 0 and 1 case are implemented above.)
360seq!(Z in 2..20 {
361    impl_query!(Z);
362});