Skip to main content

pebble/ecs/
query.rs

1use crate::ecs::{Entity, resources::Resources, system_param::SystemParam};
2
3/// Fetches components matching `Q` from every entity that has them. Include
4/// [`Entity`] in `Q` to get entity IDs back out of iteration.
5pub struct Query<'a, Q: hecs::Query> {
6    world: &'a hecs::World,
7    borrow: hecs::QueryBorrow<'a, Q>,
8    scratch: Option<hecs::QueryOne<'a, Q>>,
9}
10
11impl<'a, Q: hecs::Query> IntoIterator for &'a mut Query<'a, Q> {
12    type Item = Q::Item<'a>;
13    type IntoIter = hecs::QueryIter<'a, Q>;
14
15    fn into_iter(self) -> Self::IntoIter {
16        (&mut self.borrow).into_iter()
17    }
18}
19
20impl<'a, Q: hecs::Query> Query<'a, Q> {
21    /// Iterates every matching entity's components.
22    pub fn iter(&mut self) -> impl Iterator<Item = Q::Item<'_>> {
23        self.borrow.iter()
24    }
25
26    /// Fetches one known entity directly, without scanning the rest of the
27    /// query. `None` if it doesn't exist or doesn't match `Q`.
28    pub fn get(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
29        self.scratch = Some(self.world.query_one::<Q>(entity));
30        self.scratch.as_mut().unwrap().get().ok()
31    }
32
33    /// Narrows to entities that also have component(s) `R`, without `R`
34    /// joining the yielded items. Chainable with `.without::<S>()`.
35    pub fn with<R: hecs::Query>(self) -> Query<'a, hecs::With<Q, R>> {
36        Query {
37            world: self.world,
38            borrow: self.borrow.with::<R>(),
39            scratch: None,
40        }
41    }
42
43    /// Narrows to entities that don't have component(s) `R`.
44    pub fn without<R: hecs::Query>(self) -> Query<'a, hecs::Without<Q, R>> {
45        Query {
46            world: self.world,
47            borrow: self.borrow.without::<R>(),
48            scratch: None,
49        }
50    }
51
52    /// Expects exactly one matching entity (the player, the active
53    /// camera). Panics otherwise — use [`get_single`](Self::get_single) if
54    /// that's not guaranteed.
55    pub fn single(&mut self) -> Q::Item<'_> {
56        self.get_single()
57            .expect("Query::single: expected exactly one matching entity")
58    }
59
60    /// Same as [`single`](Self::single), but `None` instead of panicking
61    /// when there isn't exactly one match.
62    pub fn get_single(&mut self) -> Option<Q::Item<'_>> {
63        let mut iter = self.borrow.iter();
64        let first = iter.next()?;
65        if iter.next().is_some() {
66            return None;
67        }
68        Some(first)
69    }
70}
71
72impl<Q> SystemParam for Query<'static, Q>
73where
74    Q: hecs::Query + 'static,
75{
76    type Item<'a> = Query<'a, Q>;
77    type State = ();
78
79    fn fetch<'a>(
80        world: &'a hecs::World,
81        _resources: &'a Resources,
82        _state: &'a mut Self::State,
83    ) -> Self::Item<'a> {
84        Query {
85            world,
86            borrow: world.query::<Q>(),
87            scratch: None,
88        }
89    }
90}