summaryrefslogtreecommitdiff
path: root/ecs/src/query/flexible.rs
blob: 7d24dc9be06f41eb4af8beafa625a2d2fc533cda (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
102
103
104
105
106
107
108
109
//! Low-level querying.
use std::iter::{repeat_n, FlatMap, RepeatN, Zip};

use crate::component::storage::archetype::{Archetype, ArchetypeEntity, EntityIter};
use crate::component::storage::{
    ArchetypeRefIter,
    ArchetypeSearchTerms,
    Storage as ComponentStorage,
};
use crate::lock::ReadGuard;
use crate::query::Terms;
use crate::uid::Uid;
use crate::{EntityComponent, World};

/// Low-level entity query structure.
#[derive(Debug)]
pub struct Query<'world, 'terms>
{
    component_storage: ReadGuard<'world, ComponentStorage>,
    terms: Terms<'terms>,
}

impl<'world, 'terms> Query<'world, 'terms>
{
    /// Iterates over the entities matching this query.
    #[must_use]
    pub fn iter(&self) -> Iter<'_>
    {
        Iter {
            iter: self
                .component_storage
                .search_archetypes(ArchetypeSearchTerms {
                    required_components: &self.terms.required_components,
                    excluded_components: &self.terms.excluded_components,
                })
                .flat_map(
                    (|archetype| {
                        repeat_n(archetype, archetype.entity_cnt())
                            .zip(archetype.entities())
                    }) as ComponentIterMapFn,
                ),
        }
    }

    pub(crate) fn new(world: &'world World, terms: Terms<'terms>) -> Self
    {
        Self {
            component_storage: world
                .data
                .component_storage
                .read_nonblock()
                .expect("Failed to acquire read-only component storage lock"),
            terms,
        }
    }
}

pub struct Iter<'query>
{
    iter: QueryEntityIter<'query>,
}

impl<'query> Iterator for Iter<'query>
{
    type Item = EntityHandle<'query>;

    fn next(&mut self) -> Option<Self::Item>
    {
        let (archetype, entity) = self.iter.next()?;

        Some(EntityHandle { archetype, entity })
    }
}

pub struct EntityHandle<'query>
{
    archetype: &'query Archetype,
    entity: &'query ArchetypeEntity,
}

impl<'query> EntityHandle<'query>
{
    /// Returns the [`Uid`] of this entity.
    #[inline]
    #[must_use]
    pub fn uid(&self) -> Uid
    {
        self.entity.uid
    }

    #[inline]
    #[must_use]
    pub fn get_component(&self, component_uid: Uid) -> Option<&'query EntityComponent>
    {
        let index = self.archetype.get_index_for_component(component_uid)?;

        Some(self.entity.components.get(index).unwrap())
    }
}

type ComponentIterMapFnOutput<'a> = Zip<RepeatN<&'a Archetype>, EntityIter<'a>>;

type ComponentIterMapFn = for<'a> fn(&'a Archetype) -> ComponentIterMapFnOutput<'a>;

type QueryEntityIter<'query> = FlatMap<
    ArchetypeRefIter<'query, 'query>,
    ComponentIterMapFnOutput<'query>,
    ComponentIterMapFn,
>;