async_ecs/join/
iter.rs

1use std::iter::Iterator;
2
3use hibitset::{BitIter, BitSetLike};
4use log::warn;
5
6use crate::entity::{Entities, Entity};
7
8use super::Join;
9
10/// `JoinIter` is an `Iterator` over a group of `Storages`.
11pub struct JoinIter<J: Join> {
12    keys: BitIter<J::Mask>,
13    values: J::Value,
14}
15
16impl<J: Join> JoinIter<J> {
17    pub fn new(j: J) -> Self {
18        if <J as Join>::is_unconstrained() {
19            warn!(
20                "`Join` possibly iterating through all indices, you might've made a join with all `MaybeJoin`s, which is unbounded in length."
21            );
22        }
23
24        let (keys, values) = unsafe { j.open() };
25
26        JoinIter {
27            keys: keys.iter(),
28            values,
29        }
30    }
31
32    /// Allows getting joined values for specific entity.
33    ///
34    /// ## Example
35    ///
36    /// ```
37    /// # use async_ecs::*;
38    /// # #[derive(Debug, PartialEq)]
39    /// # struct Pos; impl Component for Pos { type Storage = VecStorage<Self>; }
40    /// # #[derive(Debug, PartialEq)]
41    /// # struct Vel; impl Component for Vel { type Storage = VecStorage<Self>; }
42    /// let mut world = World::default();
43    ///
44    /// world.register_component::<Pos>();
45    /// world.register_component::<Vel>();
46    ///
47    /// // This entity could be stashed anywhere (into `Component`, `Resource`, `System`s data, etc.) as it's just a number.
48    /// let entity = world
49    ///     .create_entity()
50    ///     .with(Pos)
51    ///     .with(Vel)
52    ///     .build();
53    ///
54    /// // Later
55    /// {
56    ///     let mut pos = world.component_mut::<Pos>();
57    ///     let vel = world.component::<Vel>();
58    ///
59    ///     assert_eq!(
60    ///         Some((&mut Pos, &Vel)),
61    ///         (&mut pos, &vel).join().get(entity, &world.entities()),
62    ///         "The entity that was stashed still has the needed components and is alive."
63    ///     );
64    /// }
65    ///
66    /// // The entity has found nice spot and doesn't need to move anymore.
67    /// world.component_mut::<Vel>().remove(entity);
68    ///
69    /// // Even later
70    /// {
71    ///     let mut pos = world.component_mut::<Pos>();
72    ///     let vel = world.component::<Vel>();
73    ///
74    ///     assert_eq!(
75    ///         None,
76    ///         (&mut pos, &vel).join().get(entity, &world.entities()),
77    ///         "The entity doesn't have velocity anymore."
78    ///     );
79    /// }
80    /// ```
81    pub fn get(&mut self, entity: Entity, entities: &Entities) -> Option<J::Type> {
82        if self.keys.contains(entity.index()) && entities.is_alive(entity) {
83            Some(unsafe { J::get(&mut self.values, entity.index()) })
84        } else {
85            None
86        }
87    }
88}
89
90impl<J: Join> Iterator for JoinIter<J> {
91    type Item = J::Type;
92
93    fn next(&mut self) -> Option<J::Type> {
94        self.keys
95            .next()
96            .map(|idx| unsafe { J::get(&mut self.values, idx) })
97    }
98}
99
100impl<J: Join> Clone for JoinIter<J>
101where
102    J::Mask: Clone,
103    J::Value: Clone,
104{
105    fn clone(&self) -> Self {
106        Self {
107            keys: self.keys.clone(),
108            values: self.values.clone(),
109        }
110    }
111}