Skip to main content

ixa/entity/query/
query_impls.rs

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