1use crate::{
2 bundle::Bundle,
3 commands::{DespawnManyCommand, SpawnManyCommand},
4 entity::Entity,
5 query::{TypedLookupAccess, TypedLookupFetch},
6};
7
8pub trait WorldCreateIteratorExt: Iterator
9where
10 Self::Item: Bundle + Send + Sync + 'static,
11{
12 fn to_spawn_command(self) -> SpawnManyCommand<Self::Item>;
13}
14
15impl<I> WorldCreateIteratorExt for I
16where
17 I: Iterator,
18 I::Item: Bundle + Send + Sync + 'static,
19{
20 fn to_spawn_command(self) -> SpawnManyCommand<Self::Item> {
21 SpawnManyCommand::new(self)
22 }
23}
24
25pub trait WorldDestroyIteratorExt: Iterator {
26 fn to_despawn_command(self) -> DespawnManyCommand;
27}
28
29impl<I> WorldDestroyIteratorExt for I
30where
31 I: Iterator<Item = Entity>,
32{
33 fn to_despawn_command(self) -> DespawnManyCommand {
34 DespawnManyCommand::new(self)
35 }
36}
37
38pub struct WorldJoinIterator<'a, const LOCKING: bool, LeftIter, RightFetch, F, EntityIIter>
39where
40 LeftIter: Iterator,
41 RightFetch: TypedLookupFetch<'a, LOCKING>,
42 F: Fn(LeftIter::Item) -> EntityIIter,
43 EntityIIter: Iterator<Item = Entity>,
44{
45 left_iter: LeftIter,
46 right_lookup: TypedLookupAccess<'a, LOCKING, RightFetch>,
47 entity_producer: F,
48 current: Option<(LeftIter::Item, EntityIIter)>,
49}
50
51impl<'a, const LOCKING: bool, LeftIter, RightFetch, F, EntityIter>
52 WorldJoinIterator<'a, LOCKING, LeftIter, RightFetch, F, EntityIter>
53where
54 LeftIter: Iterator,
55 RightFetch: TypedLookupFetch<'a, LOCKING>,
56 F: Fn(LeftIter::Item) -> EntityIter,
57 EntityIter: Iterator<Item = Entity>,
58{
59 pub fn new(
60 left_iter: LeftIter,
61 right_lookup: TypedLookupAccess<'a, LOCKING, RightFetch>,
62 entity_producer: F,
63 ) -> Self {
64 Self {
65 left_iter,
66 right_lookup,
67 entity_producer,
68 current: None,
69 }
70 }
71}
72
73impl<'a, const LOCKING: bool, LeftIter, RightFetch, F, EI> Iterator
74 for WorldJoinIterator<'a, LOCKING, LeftIter, RightFetch, F, EI>
75where
76 LeftIter: Iterator,
77 RightFetch: TypedLookupFetch<'a, LOCKING>,
78 F: Fn(LeftIter::Item) -> EI,
79 EI: Iterator<Item = Entity>,
80 LeftIter::Item: Copy,
81{
82 type Item = (LeftIter::Item, RightFetch::Value);
83
84 fn next(&mut self) -> Option<Self::Item> {
85 loop {
86 if let Some((left, entities)) = self.current.as_mut() {
87 if let Some(entity) = entities.next() {
88 let right = self.right_lookup.access(entity)?;
89 return Some((*left, right));
90 } else {
91 self.current = None;
92 }
93 }
94 let left = self.left_iter.next()?;
95 let entities = (self.entity_producer)(left);
96 self.current = Some((left, entities));
97 }
98 }
99}
100
101pub trait WorldJoinIteratorExt: Iterator {
102 fn join<'a, const LOCKING: bool, RightFetch, F, EntityIter>(
103 self,
104 right_lookup: TypedLookupAccess<'a, LOCKING, RightFetch>,
105 entity_producer: F,
106 ) -> WorldJoinIterator<'a, LOCKING, Self, RightFetch, F, EntityIter>
107 where
108 RightFetch: TypedLookupFetch<'a, LOCKING>,
109 F: Fn(Self::Item) -> EntityIter,
110 EntityIter: Iterator<Item = Entity>,
111 Self: Sized;
112}
113
114impl<I> WorldJoinIteratorExt for I
115where
116 I: Iterator,
117{
118 fn join<'a, const LOCKING: bool, RightFetch, F, EntityIter>(
119 self,
120 right_lookup: TypedLookupAccess<'a, LOCKING, RightFetch>,
121 entity_producer: F,
122 ) -> WorldJoinIterator<'a, LOCKING, Self, RightFetch, F, EntityIter>
123 where
124 RightFetch: TypedLookupFetch<'a, LOCKING>,
125 F: Fn(Self::Item) -> EntityIter,
126 EntityIter: Iterator<Item = Entity>,
127 Self: Sized,
128 {
129 WorldJoinIterator::new(self, right_lookup, entity_producer)
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::{
137 commands::Command,
138 entity::Entity,
139 world::{Relation, World},
140 };
141
142 #[test]
143 fn test_crud() {
144 let mut world = World::default();
145
146 [
148 ("a", 1usize, 1.0f32),
149 ("b", 2usize, 2.0f32),
150 ("c", 3usize, 3.0f32),
151 ]
152 .into_iter()
153 .to_spawn_command()
154 .execute(&mut world);
155
156 let rows = world
158 .query::<true, (&&str, &usize, &f32)>()
159 .collect::<Vec<_>>();
160
161 assert_eq!(
162 rows,
163 vec![
164 (&"a", &1usize, &1.0f32),
165 (&"b", &2usize, &2.0f32),
166 (&"c", &3usize, &3.0f32),
167 ]
168 );
169
170 for value in world.query::<true, &mut usize>() {
172 if *value < 2 {
173 *value = 0;
174 }
175 }
176
177 world
179 .query::<true, (Entity, &usize)>()
180 .filter(|(_, &a)| a > 0)
181 .map(|(entity, _)| entity)
182 .to_despawn_command()
183 .execute(&mut world);
184
185 let rows = world
186 .query::<true, (&&str, &usize, &f32)>()
187 .collect::<Vec<_>>();
188 assert_eq!(rows, vec![(&"a", &0usize, &1.0f32),]);
189 }
190
191 #[test]
192 fn test_join() {
193 let mut world = World::default();
194
195 let a = world.spawn(("a", 1usize)).unwrap();
196 let b = world.spawn(("b", 2usize)).unwrap();
197 world
198 .spawn(("c", 3usize, Relation::<()>::new((), a).with((), b)))
199 .unwrap();
200 world
201 .spawn(("d", 4usize, Relation::<()>::default()))
202 .unwrap();
203
204 let rows = world
206 .query::<true, (&&str, &Relation<()>)>()
207 .join(world.lookup_access::<true, &usize>(), |(_, relation)| {
208 relation.entities()
209 })
210 .map(|((name, _), value)| (name, value))
211 .collect::<Vec<_>>();
212
213 assert_eq!(rows, vec![(&"c", &1usize), (&"c", &2usize)]);
214 }
215}