summaryrefslogtreecommitdiff
path: root/engine-ecs/src/query/flexible.rs
blob: 0198fb43ca098d575a11b5f05f58d3f53025f208 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! Low-level querying.
use crate::component::storage::archetype::{Archetype, EntityIter};
use crate::component::storage::{ArchetypeRefIter, TraversalResult};
use crate::entity::Handle as EntityHandle;
use crate::query::Terms;
use crate::util::array_vec::ArrayVec;
use crate::World;

/// Low-level entity query structure.
#[derive(Debug)]
pub struct Query<'world, const TERM_CAP: usize>
{
    world: &'world World,
    terms: Terms<TERM_CAP>,
}

impl<'world, const TERM_CAP: usize> Query<'world, TERM_CAP>
{
    /// Iterates over the entities matching this query.
    #[must_use]
    pub fn iter<'this>(&'this self) -> Iter<'this, TERM_CAP>
    where
        'world: 'this,
    {
        Iter {
            archetype_iter: self
                .world
                .data
                .component_storage
                .search_archetypes(&self.terms),
            current: None,
            world: self.world,
        }
    }

    #[must_use]
    pub fn world(&self) -> &'world World
    {
        self.world
    }

    pub(crate) fn new(world: &'world World, terms: Terms<TERM_CAP>) -> Self
    {
        Self { world, terms }
    }
}

impl<'query, 'world, const TERM_CAP: usize> IntoIterator
    for &'query Query<'world, TERM_CAP>
where
    'world: 'query,
{
    type IntoIter = Iter<'query, TERM_CAP>;
    type Item = EntityHandle<'query>;

    fn into_iter(self) -> Self::IntoIter
    {
        self.iter()
    }
}

pub struct Iter<'query, const TERM_CAP: usize>
{
    archetype_iter: ArchetypeRefIter<'query, 'query, TERM_CAP>,
    current: Option<(
        &'query Archetype,
        ArrayVec<TraversalResult, TERM_CAP>,
        EntityIter<'query>,
    )>,
    world: &'query World,
}

impl<'query, const TERM_CAP: usize> Iter<'query, TERM_CAP>
{
    pub fn traversal_results(&self) -> Option<&[TraversalResult]>
    {
        self.current
            .as_ref()
            .map(|(_, traversal_results, _)| traversal_results.as_ref())
    }
}

impl<'query, const TERM_CAP: usize> Iterator for Iter<'query, TERM_CAP>
{
    type Item = EntityHandle<'query>;

    fn next(&mut self) -> Option<Self::Item>
    {
        if let Some((archetype, _, entity_iter)) = self.current.as_mut() {
            if let Some(entity) = entity_iter.next() {
                return Some(EntityHandle::new(archetype, entity, self.world));
            }
        }

        let (archetype, traversal_results) = self.archetype_iter.next()?;

        self.current = Some((archetype, traversal_results, archetype.entities()));

        self.next()
    }
}