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}