1use crate::{
2 archetype::ChangeKind,
3 component::ComponentValue,
4 filter::{ChangeFilter, Filtered, NoEntities, Union},
5 Component, EntityIds, FetchExt, Mutable,
6};
7
8pub trait TransformFetch<Method> {
13 type Output;
17 fn transform_fetch(self, method: Method) -> Self::Output;
19}
20
21impl<T: ComponentValue> TransformFetch<Modified> for Component<T> {
22 type Output = ChangeFilter<T>;
23 fn transform_fetch(self, _: Modified) -> Self::Output {
24 self.into_change_filter(ChangeKind::Modified)
25 }
26}
27
28impl<T: ComponentValue> TransformFetch<Added> for Component<T> {
29 type Output = ChangeFilter<T>;
30 fn transform_fetch(self, _: Added) -> Self::Output {
31 self.into_change_filter(ChangeKind::Added)
32 }
33}
34
35impl<T: ComponentValue> TransformFetch<Modified> for Mutable<T> {
36 type Output = Filtered<Self, NoEntities>;
37 fn transform_fetch(self, _: Modified) -> Self::Output {
38 self.filtered(NoEntities)
39 }
40}
41
42impl<T: ComponentValue> TransformFetch<Added> for Mutable<T> {
43 type Output = Filtered<Self, NoEntities>;
44 fn transform_fetch(self, _: Added) -> Self::Output {
45 self.filtered(NoEntities)
46 }
47}
48
49impl TransformFetch<Modified> for EntityIds {
50 type Output = Filtered<Self, NoEntities>;
51 fn transform_fetch(self, _: Modified) -> Self::Output {
52 self.filtered(NoEntities)
53 }
54}
55
56impl TransformFetch<Added> for EntityIds {
57 type Output = Filtered<Self, NoEntities>;
58 fn transform_fetch(self, _: Added) -> Self::Output {
59 self.filtered(NoEntities)
60 }
61}
62
63#[derive(Debug, Clone, Copy)]
65pub struct Modified;
66
67#[derive(Debug, Clone, Copy)]
69pub struct Added;
70
71macro_rules! tuple_impl {
72 ($($idx: tt => $ty: ident),*) => {
73 impl<$($ty: TransformFetch<Modified>,)*> TransformFetch<Modified> for ($($ty,)*) {
74 type Output = Union<($($ty::Output,)*)>;
75 fn transform_fetch(self, method: Modified) -> Self::Output {
76 Union(($(self.$idx.transform_fetch(method),)*))
77 }
78 }
79
80 impl<$($ty: TransformFetch<Added>,)*> TransformFetch<Added> for ($($ty,)*) {
81 type Output = Union<($($ty::Output,)*)>;
82 fn transform_fetch(self, method: Added) -> Self::Output {
83 Union(($(self.$idx.transform_fetch(method),)*))
84 }
85 }
86 };
87}
88
89tuple_impl! { 0 => A }
90tuple_impl! { 0 => A, 1 => B }
91tuple_impl! { 0 => A, 1 => B, 2 => C }
92tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D }
93tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E }
94tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F }
95tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H }
96
97#[cfg(test)]
98mod tests {
99
100 use alloc::string::{String, ToString};
101 use itertools::Itertools;
102
103 use crate::{component, entity_ids, CommandBuffer, Entity, FetchExt, Query, World};
104
105 #[test]
106 fn query_modified() {
107 component! {
108 a: i32,
109 b: String,
110 other: (),
111 }
112
113 let mut world = World::new();
114
115 let id1 = Entity::builder()
116 .set(a(), 0)
117 .set(b(), "Hello".into())
118 .spawn(&mut world);
119
120 let id2 = Entity::builder()
121 .set(a(), 1)
122 .set(b(), "World".into())
123 .spawn(&mut world);
124
125 let id3 = Entity::builder()
126 .set(b(), "There".into())
128 .spawn(&mut world);
129
130 let id4 = Entity::builder()
132 .set(a(), 2)
133 .set(b(), "!".into())
134 .tag(other())
135 .spawn(&mut world);
136
137 let mut query = Query::new((entity_ids(), (a(), b(), other().as_mut().opt()).modified()));
138
139 assert_eq!(
140 query.borrow(&world).iter().collect_vec(),
141 [
142 (id1, (&0, &"Hello".to_string(), None)),
143 (id2, (&1, &"World".to_string(), None)),
144 (id4, (&2, &"!".to_string(), Some(&mut ())))
145 ]
146 );
147
148 assert_eq!(query.borrow(&world).iter().collect_vec(), []);
149
150 assert_eq!(*world.get_mut(id2, a()).unwrap(), 1);
152
153 assert_eq!(query.borrow(&world).iter().collect_vec(), []);
154
155 *world.get_mut(id2, a()).unwrap() = 5;
156
157 assert_eq!(
158 query.borrow(&world).iter().collect_vec(),
159 [(id2, (&5, &"World".to_string(), None))]
160 );
161
162 let mut cmd = CommandBuffer::new();
164 cmd.set(id3, a(), -1).apply(&mut world).unwrap();
165
166 assert_eq!(
167 query.borrow(&world).iter().collect_vec(),
168 [(id3, (&-1, &"There".to_string(), None))]
169 );
170
171 cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap();
172
173 assert_eq!(
174 query.borrow(&world).iter().collect_vec(),
175 [(id3, (&-1, &":P".to_string(), None))]
176 );
177 }
178
179 #[test]
180 #[cfg(feature = "derive")]
181 fn query_modified_struct() {
182 use crate::{fetch::Cloned, Component, Fetch, Mutable, Opt};
183
184 component! {
185 a: i32,
186 b: String,
187 other: (),
188 c: f32,
189 }
190
191 #[derive(Fetch)]
192 #[fetch(item_derives = [Debug], transforms = [Modified])]
193 struct MyFetch {
194 a: Component<i32>,
195 b: Cloned<Component<String>>,
196 c: Mutable<f32>,
197 other: Opt<Mutable<()>>,
198 }
199
200 let mut world = World::new();
201
202 let id1 = Entity::builder()
203 .set(a(), 0)
204 .set(b(), "Hello".into())
205 .set_default(c())
206 .spawn(&mut world);
207
208 let id2 = Entity::builder()
209 .set(a(), 1)
210 .set(b(), "World".into())
211 .set_default(c())
212 .spawn(&mut world);
213
214 let id3 = Entity::builder()
215 .set(b(), "There".into())
217 .set_default(c())
218 .spawn(&mut world);
219
220 let id4 = Entity::builder()
222 .set(a(), 2)
223 .set(b(), "!".into())
224 .set_default(c())
225 .tag(other())
226 .spawn(&mut world);
227
228 let query = MyFetch {
229 a: a(),
230 b: b().cloned(),
231 c: c().as_mut(),
232 other: other().as_mut().opt(),
233 }
234 .modified()
235 .map(|v| (*v.a, v.b));
236
237 let mut query = Query::new((entity_ids(), query));
238
239 assert_eq!(
240 query.collect_vec(&world),
241 [
242 (id1, (0, "Hello".to_string())),
243 (id2, (1, "World".to_string())),
244 (id4, (2, "!".to_string()))
245 ]
246 );
247
248 assert_eq!(query.collect_vec(&world), []);
249
250 assert_eq!(*world.get_mut(id2, a()).unwrap(), 1);
252
253 assert_eq!(query.collect_vec(&world), []);
254
255 *world.get_mut(id2, a()).unwrap() = 5;
256
257 assert_eq!(query.collect_vec(&world), [(id2, (5, "World".to_string()))]);
258
259 let mut cmd = CommandBuffer::new();
261 cmd.set(id3, a(), -1).apply(&mut world).unwrap();
262
263 assert_eq!(
264 query.collect_vec(&world),
265 [(id3, (-1, "There".to_string()))]
266 );
267
268 cmd.set(id3, b(), ":P".into()).apply(&mut world).unwrap();
269
270 assert_eq!(query.collect_vec(&world), [(id3, (-1, ":P".to_string()))]);
271 }
272
273 #[test]
274 #[cfg(feature = "derive")]
275 fn query_inserted_struct() {
276 use crate::{fetch::Cloned, Component, EntityIds, Fetch, Mutable};
277
278 #[derive(Debug)]
279 struct Custom;
280
281 component! {
282 a: i32,
283 b: String,
284 c: Custom,
285 other: (),
286 }
287
288 #[derive(Fetch)]
289 #[fetch(item_derives = [Debug], transforms = [Modified, Added])]
290 struct MyFetch {
291 #[fetch(ignore)]
292 id: EntityIds,
293
294 a: Component<i32>,
295 b: Cloned<Component<String>>,
296 #[fetch(ignore)]
297 c: Mutable<Custom>,
298 }
299
300 let mut world = World::new();
301
302 let id1 = Entity::builder()
303 .set(a(), 0)
304 .set(b(), "Hello".into())
305 .set(c(), Custom)
306 .spawn(&mut world);
307
308 let id2 = Entity::builder()
309 .set(a(), 1)
310 .set(b(), "World".into())
311 .set(c(), Custom)
312 .spawn(&mut world);
313
314 let id3 = Entity::builder()
315 .set(b(), "There".into())
317 .set(c(), Custom)
318 .spawn(&mut world);
319
320 let id4 = Entity::builder()
322 .set(a(), 2)
323 .set(b(), "!".into())
324 .set(c(), Custom)
325 .tag(other())
326 .spawn(&mut world);
327
328 let query = MyFetch {
329 id: entity_ids(),
330 a: a(),
331 b: b().cloned(),
332 c: c().as_mut(),
333 }
334 .added()
335 .map(|v| (v.id, *v.a, v.b));
336
337 let mut query = Query::new(query);
338
339 assert_eq!(
340 query.collect_vec(&world),
341 [
342 (id1, 0, "Hello".to_string()),
343 (id2, 1, "World".to_string()),
344 (id4, 2, "!".to_string())
345 ]
346 );
347
348 assert_eq!(query.collect_vec(&world), []);
349
350 assert_eq!(query.collect_vec(&world), []);
351
352 world.remove(id2, a()).unwrap();
353
354 assert_eq!(query.collect_vec(&world), []);
355
356 world.set(id2, a(), 5).unwrap();
357
358 assert_eq!(query.collect_vec(&world), [(id2, 5, "World".to_string())]);
359
360 let mut cmd = CommandBuffer::new();
362 cmd.set(id3, a(), -1).apply(&mut world).unwrap();
363
364 assert_eq!(query.collect_vec(&world), [(id3, -1, "There".to_string())]);
365 }
366
367 #[test]
368 #[cfg(feature = "derive")]
369 fn test_derive_parse() {
370 use crate::{fetch::Cloned, Component, Fetch};
371
372 #[derive(Fetch)]
373 struct MyFetch {
374 a: Component<i32>,
375 b: Cloned<Component<String>>,
376 }
377 }
378}