1use crate::{
2 archetype::{
3 Archetype, ArchetypeColumnAccess, ArchetypeDynamicColumnAccess, ArchetypeDynamicColumnItem,
4 ArchetypeDynamicColumnIter, ArchetypeError,
5 },
6 component::{Component, ComponentRef, ComponentRefMut},
7 entity::{Entity, EntityDenseMap},
8 view::WorldView,
9 world::World,
10};
11use intuicio_data::type_hash::TypeHash;
12use std::{
13 collections::{HashMap, HashSet},
14 error::Error,
15 marker::PhantomData,
16 sync::Arc,
17};
18
19#[derive(Debug)]
20pub enum QueryError {
21 Archetype(ArchetypeError),
22 TryingToReadUnavailableType { type_hash: TypeHash },
23 TryingToWriteUnavailableType { type_hash: TypeHash },
24}
25
26impl Error for QueryError {}
27
28impl From<ArchetypeError> for QueryError {
29 fn from(value: ArchetypeError) -> Self {
30 Self::Archetype(value)
31 }
32}
33
34impl std::fmt::Display for QueryError {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::Archetype(archetype) => write!(f, "World archetype: {archetype}"),
38 Self::TryingToReadUnavailableType { type_hash } => {
39 write!(f, "Trying to read unavailable type: {type_hash:?}")
40 }
41 Self::TryingToWriteUnavailableType { type_hash } => {
42 write!(f, "Trying to write unavailable type: {type_hash:?}")
43 }
44 }
45 }
46}
47
48pub struct Query<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>>(
49 PhantomData<fn() -> &'a Fetch>,
50);
51
52impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> Default
53 for Query<'a, LOCKING, Fetch>
54{
55 fn default() -> Self {
56 Self(Default::default())
57 }
58}
59
60impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> Clone
61 for Query<'a, LOCKING, Fetch>
62{
63 fn clone(&self) -> Self {
64 *self
65 }
66}
67
68impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> Copy
69 for Query<'a, LOCKING, Fetch>
70{
71}
72
73impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> Query<'a, LOCKING, Fetch> {
74 pub fn query(&self, world: &'a World) -> TypedQueryIter<'a, LOCKING, Fetch> {
75 world.query::<'a, LOCKING, Fetch>()
76 }
77
78 pub fn query_view(&self, view: &'a WorldView) -> TypedQueryIter<'a, LOCKING, Fetch> {
79 view.query::<'a, LOCKING, Fetch>()
80 }
81}
82
83impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> TypedQueryFetch<'a, LOCKING>
84 for Query<'a, LOCKING, Fetch>
85{
86 type Value = ();
87 type Access = ();
88
89 fn does_accept_archetype(archetype: &Archetype) -> bool {
90 Fetch::does_accept_archetype(archetype)
91 }
92
93 fn access(_: &Archetype) -> Result<Self::Access, QueryError> {
94 Ok(())
95 }
96
97 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
98 Some(())
99 }
100}
101
102impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> TypedLookupFetch<'a, LOCKING>
103 for Query<'a, LOCKING, Fetch>
104{
105 type Value = ();
106 type ValueOne = Self::Value;
107 type Access = ();
108
109 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
110 if Fetch::does_accept_archetype(archetype) {
111 Some(())
112 } else {
113 None
114 }
115 }
116
117 fn fetch(_: &mut Self::Access, _: Entity) -> Option<Self::Value> {
118 Some(())
119 }
120
121 fn fetch_one(_: &World, _: Entity) -> Option<Self::ValueOne> {
122 Some(())
123 }
124}
125
126pub struct Lookup<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>(
127 PhantomData<fn() -> &'a Fetch>,
128);
129
130impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> Default
131 for Lookup<'a, LOCKING, Fetch>
132{
133 fn default() -> Self {
134 Self(Default::default())
135 }
136}
137
138impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> Clone
139 for Lookup<'a, LOCKING, Fetch>
140{
141 fn clone(&self) -> Self {
142 *self
143 }
144}
145
146impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> Copy
147 for Lookup<'a, LOCKING, Fetch>
148{
149}
150
151impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> Lookup<'a, LOCKING, Fetch> {
152 pub fn lookup(
153 &self,
154 world: &'a World,
155 entities: impl IntoIterator<Item = Entity> + 'a,
156 ) -> TypedLookupIter<'a, LOCKING, Fetch> {
157 world.lookup::<'a, LOCKING, Fetch>(entities)
158 }
159
160 pub fn lookup_view(
161 &self,
162 view: &'a WorldView,
163 entities: impl IntoIterator<Item = Entity> + 'a,
164 ) -> TypedLookupIter<'a, LOCKING, Fetch> {
165 view.lookup::<'a, LOCKING, Fetch>(entities)
166 }
167
168 pub fn lookup_access(&self, world: &'a World) -> TypedLookupAccess<'a, LOCKING, Fetch> {
169 world.lookup_access::<'a, LOCKING, Fetch>()
170 }
171
172 pub fn lookup_access_view(&self, view: &'a WorldView) -> TypedLookupAccess<'a, LOCKING, Fetch> {
173 view.lookup_access::<'a, LOCKING, Fetch>()
174 }
175}
176
177impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedLookupFetch<'a, LOCKING>
178 for Lookup<'a, LOCKING, Fetch>
179{
180 type Value = ();
181 type ValueOne = Self::Value;
182 type Access = ();
183
184 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
185 if Fetch::try_access(archetype).is_some() {
186 Some(())
187 } else {
188 None
189 }
190 }
191
192 fn fetch(_: &mut Self::Access, _: Entity) -> Option<Self::Value> {
193 Some(())
194 }
195
196 fn fetch_one(_: &World, _: Entity) -> Option<Self::ValueOne> {
197 Some(())
198 }
199}
200
201impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedQueryFetch<'a, LOCKING>
202 for Lookup<'a, LOCKING, Fetch>
203{
204 type Value = ();
205 type Access = ();
206
207 fn does_accept_archetype(archetype: &Archetype) -> bool {
208 let archetype = unsafe { std::mem::transmute::<&Archetype, &Archetype>(archetype) };
209 Fetch::try_access(archetype).is_some()
210 }
211
212 fn access(_: &'a Archetype) -> Result<Self::Access, QueryError> {
213 Ok(())
214 }
215
216 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
217 Some(())
218 }
219}
220
221pub trait TypedQueryFetch<'a, const LOCKING: bool> {
222 type Value;
223 type Access;
224
225 fn does_accept_archetype(archetype: &Archetype) -> bool;
226 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError>;
227 fn fetch(access: &mut Self::Access) -> Option<Self::Value>;
228
229 #[allow(unused_variables)]
230 fn unique_access(output: &mut HashSet<TypeHash>) {}
231}
232
233pub trait TypedLookupFetch<'a, const LOCKING: bool> {
234 type Value;
235 type ValueOne;
236 type Access;
237
238 fn try_access(archetype: &'a Archetype) -> Option<Self::Access>;
239 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value>;
240 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne>;
241
242 #[allow(unused_variables)]
243 fn unique_access(output: &mut HashSet<TypeHash>) {}
244}
245
246pub trait TypedRelationLookupFetch<'a> {
247 type Value;
248 type Access;
249
250 fn access(world: &'a World, entity: Entity) -> Self::Access;
251 fn fetch(access: &mut Self::Access) -> Option<Self::Value>;
252}
253
254pub trait TypedRelationLookupTransform<'a> {
255 type Input;
256 type Output;
257
258 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output>;
259}
260
261impl<const LOCKING: bool> TypedQueryFetch<'_, LOCKING> for () {
262 type Value = ();
263 type Access = ();
264
265 fn does_accept_archetype(_: &Archetype) -> bool {
266 true
267 }
268
269 fn access(_: &Archetype) -> Result<Self::Access, QueryError> {
270 Ok(())
271 }
272
273 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
274 Some(())
275 }
276}
277
278impl<const LOCKING: bool> TypedLookupFetch<'_, LOCKING> for () {
279 type Value = ();
280 type ValueOne = Self::Value;
281 type Access = ();
282
283 fn try_access(_: &Archetype) -> Option<Self::Access> {
284 Some(())
285 }
286
287 fn fetch(_: &mut Self::Access, _: Entity) -> Option<Self::Value> {
288 Some(())
289 }
290
291 fn fetch_one(_: &World, _: Entity) -> Option<Self::ValueOne> {
292 Some(())
293 }
294}
295
296impl<'a, const LOCKING: bool> TypedQueryFetch<'a, LOCKING> for Entity {
297 type Value = Entity;
298 type Access = Box<dyn Iterator<Item = Entity> + 'a>;
299
300 fn does_accept_archetype(_: &Archetype) -> bool {
301 true
302 }
303
304 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
305 Ok(Box::new(archetype.entities().iter()))
306 }
307
308 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
309 access.next()
310 }
311}
312
313impl<'a, const LOCKING: bool> TypedLookupFetch<'a, LOCKING> for Entity {
314 type Value = Entity;
315 type ValueOne = Self::Value;
316 type Access = &'a EntityDenseMap;
317
318 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
319 Some(archetype.entities())
320 }
321
322 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
323 if access.contains(entity) {
324 Some(entity)
325 } else {
326 None
327 }
328 }
329
330 fn fetch_one(_: &World, entity: Entity) -> Option<Self::ValueOne> {
331 Some(entity)
332 }
333}
334
335impl<'a, const LOCKING: bool, T: Component> TypedQueryFetch<'a, LOCKING> for &'a T {
336 type Value = &'a T;
337 type Access = Box<dyn Iterator<Item = &'a T> + 'a>;
338
339 fn does_accept_archetype(archetype: &Archetype) -> bool {
340 archetype.has_type(TypeHash::of::<T>())
341 }
342
343 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
344 Ok(Box::new(archetype.column_read_iter::<LOCKING, T>()?))
345 }
346
347 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
348 access.next()
349 }
350}
351
352impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for &'a T {
353 type Value = &'a T;
354 type ValueOne = ComponentRef<'a, LOCKING, T>;
355 type Access = (&'a EntityDenseMap, ArchetypeColumnAccess<'a, LOCKING, T>);
356
357 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
358 if archetype.has_type(TypeHash::of::<T>()) {
359 Some((
360 archetype.entities(),
361 archetype.column::<LOCKING, T>(false).ok()?,
362 ))
363 } else {
364 None
365 }
366 }
367
368 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
369 if let Some(index) = access.0.index_of(entity) {
370 access
371 .1
372 .read(index)
373 .map(|value| unsafe { std::mem::transmute(value) })
374 } else {
375 None
376 }
377 }
378
379 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
380 world.component::<LOCKING, T>(entity).ok()
381 }
382}
383
384impl<'a, const LOCKING: bool, T: Component> TypedQueryFetch<'a, LOCKING> for &'a mut T {
385 type Value = &'a mut T;
386 type Access = Box<dyn Iterator<Item = &'a mut T> + 'a>;
387
388 fn does_accept_archetype(archetype: &Archetype) -> bool {
389 archetype.has_type(TypeHash::of::<T>())
390 }
391
392 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
393 Ok(Box::new(archetype.column_write_iter::<LOCKING, T>()?))
394 }
395
396 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
397 access.next()
398 }
399
400 fn unique_access(output: &mut HashSet<TypeHash>) {
401 output.insert(TypeHash::of::<T>());
402 }
403}
404
405impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for &'a mut T {
406 type Value = &'a mut T;
407 type ValueOne = ComponentRefMut<'a, LOCKING, T>;
408 type Access = (&'a EntityDenseMap, ArchetypeColumnAccess<'a, LOCKING, T>);
409
410 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
411 if archetype.has_type(TypeHash::of::<T>()) {
412 Some((
413 archetype.entities(),
414 archetype.column::<LOCKING, T>(true).ok()?,
415 ))
416 } else {
417 None
418 }
419 }
420
421 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
422 if let Some(index) = access.0.index_of(entity) {
423 access
424 .1
425 .write(index)
426 .map(|value| unsafe { std::mem::transmute(value) })
427 } else {
428 None
429 }
430 }
431
432 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
433 world.component_mut::<LOCKING, T>(entity).ok()
434 }
435
436 fn unique_access(output: &mut HashSet<TypeHash>) {
437 output.insert(TypeHash::of::<T>());
438 }
439}
440
441impl<'a, const LOCKING: bool, T: Component> TypedQueryFetch<'a, LOCKING> for Option<&'a T> {
442 type Value = Option<&'a T>;
443 type Access = Option<Box<dyn Iterator<Item = &'a T> + 'a>>;
444
445 fn does_accept_archetype(_: &Archetype) -> bool {
446 true
447 }
448
449 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
450 match archetype.column_read_iter::<LOCKING, T>().ok() {
451 Some(value) => Ok(Some(Box::new(value))),
452 None => Ok(None),
453 }
454 }
455
456 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
457 match access {
458 Some(access) => Some(access.next()),
460 None => Some(None),
461 }
462 }
463}
464
465impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Option<&'a T> {
466 type Value = Option<&'a T>;
467 type ValueOne = Option<ComponentRef<'a, LOCKING, T>>;
468 type Access = Option<(&'a EntityDenseMap, ArchetypeColumnAccess<'a, LOCKING, T>)>;
469
470 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
471 match archetype.column::<LOCKING, T>(false).ok() {
472 Some(value) => Some(Some((archetype.entities(), value))),
473 None => Some(None),
474 }
475 }
476
477 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
478 match access {
479 Some(access) => Some(if let Some(index) = access.0.index_of(entity) {
481 access
482 .1
483 .read(index)
484 .map(|value| unsafe { std::mem::transmute(value) })
485 } else {
486 None
487 }),
488 None => Some(None),
489 }
490 }
491
492 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
493 Some(world.component::<LOCKING, T>(entity).ok())
494 }
495}
496
497impl<'a, const LOCKING: bool, T: Component> TypedQueryFetch<'a, LOCKING> for Option<&'a mut T> {
498 type Value = Option<&'a mut T>;
499 type Access = Option<Box<dyn Iterator<Item = &'a mut T> + 'a>>;
500
501 fn does_accept_archetype(_: &Archetype) -> bool {
502 true
503 }
504
505 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
506 match archetype.column_write_iter::<LOCKING, T>().ok() {
507 Some(value) => Ok(Some(Box::new(value))),
508 None => Ok(None),
509 }
510 }
511
512 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
513 match access {
514 Some(access) => Some(access.next()),
516 None => Some(None),
517 }
518 }
519
520 fn unique_access(output: &mut HashSet<TypeHash>) {
521 output.insert(TypeHash::of::<T>());
522 }
523}
524
525impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Option<&'a mut T> {
526 type Value = Option<&'a mut T>;
527 type ValueOne = Option<ComponentRefMut<'a, LOCKING, T>>;
528 type Access = Option<(&'a EntityDenseMap, ArchetypeColumnAccess<'a, LOCKING, T>)>;
529
530 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
531 match archetype.column::<LOCKING, T>(true).ok() {
532 Some(value) => Some(Some((archetype.entities(), value))),
533 None => Some(None),
534 }
535 }
536
537 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
538 match access {
539 Some(access) => Some(if let Some(index) = access.0.index_of(entity) {
541 access
542 .1
543 .write(index)
544 .map(|value| unsafe { std::mem::transmute(value) })
545 } else {
546 None
547 }),
548 None => Some(None),
549 }
550 }
551
552 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
553 Some(world.component_mut::<LOCKING, T>(entity).ok())
554 }
555
556 fn unique_access(output: &mut HashSet<TypeHash>) {
557 output.insert(TypeHash::of::<T>());
558 }
559}
560
561pub struct Satisfy<T>(PhantomData<fn() -> T>);
562
563impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> TypedQueryFetch<'a, LOCKING>
564 for Satisfy<Fetch>
565{
566 type Value = ();
567 type Access = ();
568
569 fn does_accept_archetype(archetype: &Archetype) -> bool {
570 Fetch::does_accept_archetype(archetype)
571 }
572
573 fn access(_: &'_ Archetype) -> Result<Self::Access, QueryError> {
574 Ok(())
575 }
576
577 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
578 Some(())
579 }
580}
581
582impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedLookupFetch<'a, LOCKING>
583 for Satisfy<Fetch>
584{
585 type Value = ();
586 type ValueOne = ();
587 type Access = &'a EntityDenseMap;
588
589 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
590 if Fetch::try_access(archetype).is_some() {
591 Some(archetype.entities())
592 } else {
593 None
594 }
595 }
596
597 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
598 if access.contains(entity) {
599 Some(())
600 } else {
601 None
602 }
603 }
604
605 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
606 if Fetch::fetch_one(world, entity).is_some() {
607 Some(())
608 } else {
609 None
610 }
611 }
612}
613
614pub struct DoesNotSatisfy<T>(PhantomData<fn() -> T>);
615
616impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> TypedQueryFetch<'a, LOCKING>
617 for DoesNotSatisfy<Fetch>
618{
619 type Value = ();
620 type Access = ();
621
622 fn does_accept_archetype(archetype: &Archetype) -> bool {
623 !Fetch::does_accept_archetype(archetype)
624 }
625
626 fn access(_: &'_ Archetype) -> Result<Self::Access, QueryError> {
627 Ok(())
628 }
629
630 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
631 Some(())
632 }
633}
634
635impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedLookupFetch<'a, LOCKING>
636 for DoesNotSatisfy<Fetch>
637{
638 type Value = ();
639 type ValueOne = ();
640 type Access = &'a EntityDenseMap;
641
642 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
643 if Fetch::try_access(archetype).is_none() {
644 Some(archetype.entities())
645 } else {
646 None
647 }
648 }
649
650 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
651 if access.contains(entity) {
652 Some(())
653 } else {
654 None
655 }
656 }
657
658 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
659 if Fetch::fetch_one(world, entity).is_none() {
660 Some(())
661 } else {
662 None
663 }
664 }
665}
666
667pub struct Include<T: Component>(PhantomData<fn() -> T>);
668
669impl<const LOCKING: bool, T: Component> TypedQueryFetch<'_, LOCKING> for Include<T> {
670 type Value = ();
671 type Access = ();
672
673 fn does_accept_archetype(archetype: &Archetype) -> bool {
674 archetype.has_type(TypeHash::of::<T>())
675 }
676
677 fn access(_: &Archetype) -> Result<Self::Access, QueryError> {
678 Ok(())
679 }
680
681 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
682 Some(())
683 }
684}
685
686impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Include<T> {
687 type Value = ();
688 type ValueOne = ();
689 type Access = &'a EntityDenseMap;
690
691 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
692 if archetype.has_type(TypeHash::of::<T>()) {
693 Some(archetype.entities())
694 } else {
695 None
696 }
697 }
698
699 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
700 if access.contains(entity) {
701 Some(())
702 } else {
703 None
704 }
705 }
706
707 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
708 if world.has_entity_component::<T>(entity) {
709 Some(())
710 } else {
711 None
712 }
713 }
714}
715
716pub struct Exclude<T: Component>(PhantomData<fn() -> T>);
717
718impl<const LOCKING: bool, T: Component> TypedQueryFetch<'_, LOCKING> for Exclude<T> {
719 type Value = ();
720 type Access = ();
721
722 fn does_accept_archetype(archetype: &Archetype) -> bool {
723 !archetype.has_type(TypeHash::of::<T>())
724 }
725
726 fn access(_: &Archetype) -> Result<Self::Access, QueryError> {
727 Ok(())
728 }
729
730 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
731 Some(())
732 }
733}
734
735impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Exclude<T> {
736 type Value = ();
737 type ValueOne = ();
738 type Access = &'a EntityDenseMap;
739
740 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
741 if !archetype.has_type(TypeHash::of::<T>()) {
742 Some(archetype.entities())
743 } else {
744 None
745 }
746 }
747
748 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
749 if access.contains(entity) {
750 Some(())
751 } else {
752 None
753 }
754 }
755
756 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
757 if !world.has_entity_component::<T>(entity) {
758 Some(())
759 } else {
760 None
761 }
762 }
763}
764
765pub struct Update<T: Component>(PhantomData<fn() -> T>);
766
767pub struct UpdatedAccess<'a, T>(Entity, &'a mut T);
768
769impl<'a, T> UpdatedAccess<'a, T> {
770 pub fn entity(&self) -> Entity {
771 self.0
772 }
773
774 pub fn read(&'a self) -> &'a T {
775 self.1
776 }
777
778 pub fn write(&'a mut self) -> &'a mut T {
779 self.1
780 }
781
782 pub fn notify(&self, world: &World) {
783 world.update::<T>(self.0);
784 }
785
786 pub fn write_notified(&'a mut self, world: &World) -> &'a mut T {
787 self.notify(world);
788 self.write()
789 }
790}
791
792pub struct UpdatedAccessComponent<'a, const LOCKING: bool, T: Component>(
793 Entity,
794 ComponentRefMut<'a, LOCKING, T>,
795);
796
797impl<'a, const LOCKING: bool, T: Component> UpdatedAccessComponent<'a, LOCKING, T> {
798 pub fn entity(&self) -> Entity {
799 self.0
800 }
801
802 pub fn read(&'a self) -> &'a T {
803 &self.1
804 }
805
806 pub fn write(&'a mut self) -> &'a mut T {
807 &mut self.1
808 }
809
810 pub fn notify(&self, world: &World) {
811 world.update::<T>(self.0);
812 }
813
814 pub fn write_notified(&'a mut self, world: &World) -> &'a mut T {
815 self.notify(world);
816 self.write()
817 }
818}
819
820impl<'a, const LOCKING: bool, T: Component> TypedQueryFetch<'a, LOCKING> for Update<T> {
821 type Value = UpdatedAccess<'a, T>;
822 type Access = Box<dyn Iterator<Item = (Entity, &'a mut T)> + 'a>;
823
824 fn does_accept_archetype(archetype: &Archetype) -> bool {
825 archetype.has_type(TypeHash::of::<T>())
826 }
827
828 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
829 Ok(Box::new(
830 archetype
831 .entities()
832 .iter()
833 .zip(archetype.column_write_iter::<LOCKING, T>()?),
834 ))
835 }
836
837 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
838 access
839 .next()
840 .map(|(entity, data)| UpdatedAccess(entity, data))
841 }
842
843 fn unique_access(output: &mut HashSet<TypeHash>) {
844 output.insert(TypeHash::of::<T>());
845 }
846}
847
848impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Update<T> {
849 type Value = UpdatedAccess<'a, T>;
850 type ValueOne = UpdatedAccessComponent<'a, LOCKING, T>;
851 type Access = (&'a EntityDenseMap, ArchetypeColumnAccess<'a, LOCKING, T>);
852
853 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
854 if archetype.has_type(TypeHash::of::<T>()) {
855 Some((
856 archetype.entities(),
857 archetype.column::<LOCKING, T>(true).ok()?,
858 ))
859 } else {
860 None
861 }
862 }
863
864 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
865 if let Some(index) = access.0.index_of(entity) {
866 access
867 .1
868 .write(index)
869 .map(|value| unsafe { std::mem::transmute(value) })
870 .map(|data| UpdatedAccess(entity, data))
871 } else {
872 None
873 }
874 }
875
876 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
877 world
878 .component_mut::<LOCKING, T>(entity)
879 .ok()
880 .map(|data| UpdatedAccessComponent(entity, data))
881 }
882
883 fn unique_access(output: &mut HashSet<TypeHash>) {
884 output.insert(TypeHash::of::<T>());
885 }
886}
887
888impl<'a> TypedRelationLookupFetch<'a> for () {
889 type Value = ();
890 type Access = ();
891
892 fn access(_: &'a World, _: Entity) -> Self::Access {}
893
894 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
895 Some(())
896 }
897}
898
899impl<'a> TypedRelationLookupFetch<'a> for Entity {
900 type Value = Entity;
901 type Access = Option<Entity>;
902
903 fn access(_: &'a World, entity: Entity) -> Self::Access {
904 Some(entity)
905 }
906
907 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
908 access.take()
909 }
910}
911
912impl<'a, const LOCKING: bool, Fetch> TypedRelationLookupFetch<'a> for Lookup<'a, LOCKING, Fetch>
913where
914 Fetch: TypedLookupFetch<'a, LOCKING>,
915{
916 type Value = Fetch::ValueOne;
917 type Access = Option<Fetch::ValueOne>;
918
919 fn access(world: &'a World, entity: Entity) -> Self::Access {
920 world.lookup_one::<LOCKING, Fetch>(entity)
921 }
922
923 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
924 access.take()
925 }
926}
927
928pub struct Related<'a, const LOCKING: bool, T, Transform>(PhantomData<fn() -> &'a (T, Transform)>)
929where
930 T: Component,
931 Transform: TypedRelationLookupTransform<'a, Input = Entity>;
932
933impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
934 for Related<'a, LOCKING, T, Transform>
935where
936 T: Component,
937 Transform: TypedRelationLookupTransform<'a, Input = Entity>,
938{
939 type Value = Transform::Output;
940 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
941
942 fn access(world: &'a World, entity: Entity) -> Self::Access {
943 Box::new(
944 world
945 .relations_outgoing::<LOCKING, T>(entity)
946 .flat_map(|(_, _, entity)| Transform::transform(world, entity)),
947 )
948 }
949
950 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
951 access.next()
952 }
953}
954
955pub struct RelatedPair<'a, const LOCKING: bool, T, Transform>(
956 PhantomData<fn() -> &'a (T, Transform)>,
957)
958where
959 T: Component,
960 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>;
961
962impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
963 for RelatedPair<'a, LOCKING, T, Transform>
964where
965 T: Component,
966 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>,
967{
968 type Value = Transform::Output;
969 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
970
971 fn access(world: &'a World, entity: Entity) -> Self::Access {
972 Box::new(
973 world
974 .relations_outgoing::<LOCKING, T>(entity)
975 .flat_map(|(from, _, to)| Transform::transform(world, (from, to))),
976 )
977 }
978
979 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
980 access.next()
981 }
982}
983
984pub struct Traverse<'a, const LOCKING: bool, T, Transform>(PhantomData<fn() -> &'a (T, Transform)>)
985where
986 T: Component,
987 Transform: TypedRelationLookupTransform<'a, Input = Entity>;
988
989impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
990 for Traverse<'a, LOCKING, T, Transform>
991where
992 T: Component,
993 Transform: TypedRelationLookupTransform<'a, Input = Entity>,
994{
995 type Value = Transform::Output;
996 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
997
998 fn access(world: &'a World, entity: Entity) -> Self::Access {
999 Box::new(
1000 world
1001 .traverse_outgoing::<LOCKING, T>([entity])
1002 .flat_map(|(_, to)| Transform::transform(world, to)),
1003 )
1004 }
1005
1006 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1007 access.next()
1008 }
1009}
1010
1011pub struct TraversePair<'a, const LOCKING: bool, T, Transform>(
1012 PhantomData<fn() -> &'a (T, Transform)>,
1013)
1014where
1015 T: Component,
1016 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>;
1017
1018impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
1019 for TraversePair<'a, LOCKING, T, Transform>
1020where
1021 T: Component,
1022 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>,
1023{
1024 type Value = Transform::Output;
1025 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
1026
1027 fn access(world: &'a World, entity: Entity) -> Self::Access {
1028 Box::new(
1029 world
1030 .traverse_outgoing::<LOCKING, T>([entity])
1031 .flat_map(|(from, to)| Transform::transform(world, (from, to))),
1032 )
1033 }
1034
1035 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1036 access.next()
1037 }
1038}
1039
1040pub struct Join<'a, A, B>(PhantomData<fn() -> &'a (A, B)>)
1041where
1042 A: TypedRelationLookupFetch<'a>,
1043 B: TypedRelationLookupFetch<'a>;
1044
1045impl<'a, A, B> TypedRelationLookupFetch<'a> for Join<'a, A, B>
1046where
1047 A: TypedRelationLookupFetch<'a>,
1048 B: TypedRelationLookupFetch<'a>,
1049{
1050 type Value = (Arc<A::Value>, B::Value);
1051 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
1052
1053 fn access(world: &'a World, entity: Entity) -> Self::Access {
1054 Box::new(
1055 TypedRelationLookupIter::<A>::access(A::access(world, entity)).flat_map(move |a| {
1056 let a = Arc::new(a);
1057 TypedRelationLookupIter::<B>::access(B::access(world, entity))
1058 .map(move |b| (a.clone(), b))
1059 }),
1060 )
1061 }
1062
1063 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1064 access.next()
1065 }
1066}
1067
1068impl<'a> TypedRelationLookupTransform<'a> for Entity {
1069 type Input = Entity;
1070 type Output = Entity;
1071
1072 fn transform(_: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1073 std::iter::once(input)
1074 }
1075}
1076
1077pub struct Is<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>(
1078 PhantomData<fn() -> &'a Fetch>,
1079);
1080
1081impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedRelationLookupTransform<'a>
1082 for Is<'a, LOCKING, Fetch>
1083{
1084 type Input = Entity;
1085 type Output = Entity;
1086
1087 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1088 world
1089 .lookup_one::<LOCKING, Fetch>(input)
1090 .is_some()
1091 .then_some(input)
1092 .into_iter()
1093 }
1094}
1095
1096pub struct IsNot<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>(
1097 PhantomData<fn() -> &'a Fetch>,
1098);
1099
1100impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedRelationLookupTransform<'a>
1101 for IsNot<'a, LOCKING, Fetch>
1102{
1103 type Input = Entity;
1104 type Output = Entity;
1105
1106 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1107 world
1108 .lookup_one::<LOCKING, Fetch>(input)
1109 .is_none()
1110 .then_some(input)
1111 .into_iter()
1112 }
1113}
1114
1115impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedRelationLookupTransform<'a>
1116 for Lookup<'a, LOCKING, Fetch>
1117{
1118 type Input = Entity;
1119 type Output = Fetch::ValueOne;
1120
1121 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1122 world.lookup_one::<LOCKING, Fetch>(input).into_iter()
1123 }
1124}
1125
1126pub struct Limit<'a, const COUNT: usize, Transform: TypedRelationLookupTransform<'a>>(
1127 PhantomData<fn() -> &'a Transform>,
1128);
1129
1130impl<'a, const COUNT: usize, Transform: TypedRelationLookupTransform<'a>>
1131 TypedRelationLookupTransform<'a> for Limit<'a, COUNT, Transform>
1132{
1133 type Input = Transform::Input;
1134 type Output = Transform::Output;
1135
1136 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1137 Transform::transform(world, input).take(COUNT)
1138 }
1139}
1140
1141pub type Single<'a, Transform> = Limit<'a, 1, Transform>;
1142
1143pub struct SelectEntity<const INDEX: usize>;
1144
1145impl<'a, const INDEX: usize> TypedRelationLookupTransform<'a> for SelectEntity<INDEX> {
1146 type Input = (Entity, Entity);
1147 type Output = Entity;
1148
1149 fn transform(_: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1150 if INDEX == 0 {
1151 std::iter::once(input.0)
1152 } else {
1153 std::iter::once(input.1)
1154 }
1155 }
1156}
1157
1158pub struct Follow<'a, const LOCKING: bool, Transform, Fetch>(
1159 PhantomData<fn() -> &'a (Transform, Fetch)>,
1160)
1161where
1162 Transform: TypedRelationLookupTransform<'a, Input = Entity, Output = Entity>,
1163 Fetch: TypedRelationLookupFetch<'a>;
1164
1165impl<'a, const LOCKING: bool, Transform, Fetch> TypedRelationLookupTransform<'a>
1166 for Follow<'a, LOCKING, Transform, Fetch>
1167where
1168 Transform: TypedRelationLookupTransform<'a, Input = Entity, Output = Entity>,
1169 Fetch: TypedRelationLookupFetch<'a>,
1170{
1171 type Input = Entity;
1172 type Output = Fetch::Value;
1173
1174 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1175 Transform::transform(world, input)
1176 .flat_map(|entity| world.relation_lookup::<LOCKING, Fetch>(entity))
1177 }
1178}
1179
1180macro_rules! impl_typed_query_fetch_tuple {
1181 ($($type:ident),+) => {
1182 impl<'a, const LOCKING: bool, $($type: TypedQueryFetch<'a, LOCKING>),+> TypedQueryFetch<'a, LOCKING> for ($($type,)+) {
1183 type Value = ($($type::Value,)+);
1184 type Access = ($($type::Access,)+);
1185
1186 fn does_accept_archetype(archetype: &Archetype) -> bool {
1187 $($type::does_accept_archetype(archetype))&&+
1188 }
1189
1190 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
1191 Ok(($($type::access(archetype)?,)+))
1192 }
1193
1194 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1195 #[allow(non_snake_case)]
1196 let ($($type,)+) = access;
1197 Some(($($type::fetch($type)?,)+))
1198 }
1199
1200 fn unique_access(output: &mut HashSet<TypeHash>) {
1201 $(
1202 $type::unique_access(output);
1203 )+
1204 }
1205 }
1206 };
1207}
1208
1209impl_typed_query_fetch_tuple!(A);
1210impl_typed_query_fetch_tuple!(A, B);
1211impl_typed_query_fetch_tuple!(A, B, C);
1212impl_typed_query_fetch_tuple!(A, B, C, D);
1213impl_typed_query_fetch_tuple!(A, B, C, D, E);
1214impl_typed_query_fetch_tuple!(A, B, C, D, E, F);
1215impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G);
1216impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H);
1217impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I);
1218impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J);
1219impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1220impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1221impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1222impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
1223impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
1224impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
1225
1226macro_rules! impl_typed_lookup_fetch_tuple {
1227 ($($type:ident),+) => {
1228 impl<'a, const LOCKING: bool, $($type: TypedLookupFetch<'a, LOCKING>),+> TypedLookupFetch<'a, LOCKING> for ($($type,)+) {
1229 type Value = ($($type::Value,)+);
1230 type ValueOne = ($($type::ValueOne,)+);
1231 type Access = ($($type::Access,)+);
1232
1233 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
1234 Some(($($type::try_access(archetype)?,)+))
1235 }
1236
1237 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
1238 #[allow(non_snake_case)]
1239 let ($($type,)+) = access;
1240 Some(($($type::fetch($type, entity)?,)+))
1241 }
1242
1243 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
1244 Some(($($type::fetch_one(world, entity)?,)+))
1245 }
1246
1247 fn unique_access(output: &mut HashSet<TypeHash>) {
1248 $(
1249 $type::unique_access(output);
1250 )+
1251 }
1252 }
1253 };
1254}
1255
1256impl_typed_lookup_fetch_tuple!(A);
1257impl_typed_lookup_fetch_tuple!(A, B);
1258impl_typed_lookup_fetch_tuple!(A, B, C);
1259impl_typed_lookup_fetch_tuple!(A, B, C, D);
1260impl_typed_lookup_fetch_tuple!(A, B, C, D, E);
1261impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F);
1262impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G);
1263impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H);
1264impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I);
1265impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J);
1266impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1267impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1268impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1269impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
1270impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
1271impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
1272
1273macro_rules! impl_typed_relation_fetch_tuple {
1274 ($($type:ident),+) => {
1275 impl<'a, $($type: TypedRelationLookupFetch<'a>),+> TypedRelationLookupFetch<'a> for ($($type,)+) {
1276 type Value = ($($type::Value,)+);
1277 type Access = ($($type::Access,)+);
1278
1279 fn access(world: &'a World, entity: Entity) -> Self::Access {
1280 ($($type::access(world, entity),)+)
1281 }
1282
1283 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1284 #[allow(non_snake_case)]
1285 let ($($type,)+) = access;
1286 Some(($($type::fetch($type)?,)+))
1287 }
1288 }
1289 };
1290}
1291
1292impl_typed_relation_fetch_tuple!(A);
1293impl_typed_relation_fetch_tuple!(A, B);
1294impl_typed_relation_fetch_tuple!(A, B, C);
1295impl_typed_relation_fetch_tuple!(A, B, C, D);
1296impl_typed_relation_fetch_tuple!(A, B, C, D, E);
1297impl_typed_relation_fetch_tuple!(A, B, C, D, E, F);
1298impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G);
1299impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H);
1300impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I);
1301impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J);
1302impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1303impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1304impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1305impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O);
1306impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P);
1307
1308pub struct TypedQueryIter<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> {
1309 archetypes: Vec<&'a Archetype>,
1310 index: usize,
1311 access: Option<Fetch::Access>,
1312 _phantom: PhantomData<fn() -> Fetch>,
1313}
1314
1315impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>>
1316 TypedQueryIter<'a, LOCKING, Fetch>
1317{
1318 pub fn new(world: &'a World) -> Self {
1319 Self {
1320 archetypes: world
1321 .archetypes()
1322 .filter(|archetype| Fetch::does_accept_archetype(archetype))
1323 .collect(),
1324 index: 0,
1325 access: None,
1326 _phantom: PhantomData,
1327 }
1328 }
1329
1330 pub fn new_view(view: &'a WorldView) -> Self {
1331 Self {
1332 archetypes: view
1333 .archetypes()
1334 .filter(|archetype| Fetch::does_accept_archetype(archetype))
1335 .collect(),
1336 index: 0,
1337 access: None,
1338 _phantom: PhantomData,
1339 }
1340 }
1341}
1342
1343impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> Iterator
1344 for TypedQueryIter<'a, LOCKING, Fetch>
1345{
1346 type Item = Fetch::Value;
1347
1348 fn next(&mut self) -> Option<Self::Item> {
1349 while self.index < self.archetypes.len() {
1350 match self.access.as_mut() {
1351 Some(access) => {
1352 let item = Fetch::fetch(access);
1353 if item.is_none() {
1354 self.access = None;
1355 self.index += 1;
1356 continue;
1357 }
1358 return item;
1359 }
1360 None => {
1361 if let Some(archetype) = self.archetypes.get(self.index) {
1362 self.access = Some(Fetch::access(archetype).unwrap());
1363 } else {
1364 self.index += 1;
1365 }
1366 continue;
1367 }
1368 }
1369 }
1370 None
1371 }
1372}
1373
1374pub struct TypedLookupIter<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> {
1375 access: Vec<Fetch::Access>,
1376 entities: Box<dyn Iterator<Item = Entity> + 'a>,
1377 _phantom: PhantomData<fn() -> Fetch>,
1378}
1379
1380impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>
1381 TypedLookupIter<'a, LOCKING, Fetch>
1382{
1383 pub fn new(world: &'a World, entities: impl IntoIterator<Item = Entity> + 'a) -> Self {
1384 Self {
1385 access: world
1386 .archetypes()
1387 .filter_map(|archetype| Fetch::try_access(archetype))
1388 .collect(),
1389 entities: Box::new(entities.into_iter()),
1390 _phantom: PhantomData,
1391 }
1392 }
1393
1394 pub fn new_view(view: &'a WorldView, entities: impl IntoIterator<Item = Entity> + 'a) -> Self {
1395 Self {
1396 access: view
1397 .archetypes()
1398 .filter_map(|archetype| Fetch::try_access(archetype))
1399 .collect(),
1400 entities: Box::new(entities.into_iter()),
1401 _phantom: PhantomData,
1402 }
1403 }
1404}
1405
1406impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> Iterator
1407 for TypedLookupIter<'a, LOCKING, Fetch>
1408{
1409 type Item = Fetch::Value;
1410
1411 fn next(&mut self) -> Option<Self::Item> {
1412 let entity = self.entities.next()?;
1413 for access in &mut self.access {
1414 if let Some(result) = Fetch::fetch(access, entity) {
1415 return Some(result);
1416 }
1417 }
1418 None
1419 }
1420}
1421
1422pub struct TypedLookupAccess<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> {
1423 access: Vec<Fetch::Access>,
1424 _phantom: PhantomData<fn() -> Fetch>,
1425}
1426
1427impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>
1428 TypedLookupAccess<'a, LOCKING, Fetch>
1429{
1430 pub fn new(world: &'a World) -> Self {
1431 Self {
1432 access: world
1433 .archetypes()
1434 .filter_map(|archetype| Fetch::try_access(archetype))
1435 .collect(),
1436 _phantom: PhantomData,
1437 }
1438 }
1439
1440 pub fn new_view(view: &'a WorldView) -> Self {
1441 Self {
1442 access: view
1443 .archetypes()
1444 .filter_map(|archetype| Fetch::try_access(archetype))
1445 .collect(),
1446 _phantom: PhantomData,
1447 }
1448 }
1449
1450 pub fn access(&mut self, entity: Entity) -> Option<Fetch::Value> {
1451 for access in &mut self.access {
1452 if let Some(result) = Fetch::fetch(access, entity) {
1453 return Some(result);
1454 }
1455 }
1456 None
1457 }
1458}
1459
1460pub struct TypedRelationLookupIter<'a, Fetch: TypedRelationLookupFetch<'a>> {
1461 access: Fetch::Access,
1462}
1463
1464impl<'a, Fetch: TypedRelationLookupFetch<'a>> TypedRelationLookupIter<'a, Fetch> {
1465 pub fn new(world: &'a World, entity: Entity) -> Self {
1466 Self {
1467 access: Fetch::access(world, entity),
1468 }
1469 }
1470
1471 pub fn access(access: Fetch::Access) -> Self {
1472 Self { access }
1473 }
1474}
1475
1476impl<'a, Fetch: TypedRelationLookupFetch<'a>> Iterator for TypedRelationLookupIter<'a, Fetch> {
1477 type Item = Fetch::Value;
1478
1479 fn next(&mut self) -> Option<Self::Item> {
1480 Fetch::fetch(&mut self.access)
1481 }
1482}
1483
1484#[derive(Debug)]
1485enum DynamicQueryFilterMode {
1486 Read,
1487 Write,
1488 Include,
1489 Exclude,
1490}
1491
1492#[derive(Debug, Default)]
1493pub struct DynamicQueryFilter {
1494 filter: HashMap<TypeHash, DynamicQueryFilterMode>,
1495}
1496
1497impl DynamicQueryFilter {
1498 pub fn from_raw(
1499 read: &[TypeHash],
1500 write: &[TypeHash],
1501 include: &[TypeHash],
1502 exclude: &[TypeHash],
1503 ) -> Self {
1504 Self {
1505 filter: read
1506 .iter()
1507 .copied()
1508 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Read))
1509 .chain(
1510 write
1511 .iter()
1512 .copied()
1513 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Write)),
1514 )
1515 .chain(
1516 include
1517 .iter()
1518 .copied()
1519 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Include)),
1520 )
1521 .chain(
1522 exclude
1523 .iter()
1524 .copied()
1525 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Exclude)),
1526 )
1527 .collect(),
1528 }
1529 }
1530
1531 pub fn read<T>(self) -> Self {
1532 self.read_raw(TypeHash::of::<T>())
1533 }
1534
1535 pub fn read_raw(mut self, type_hash: TypeHash) -> Self {
1536 self.filter.insert(type_hash, DynamicQueryFilterMode::Read);
1537 self
1538 }
1539
1540 pub fn write<T>(self) -> Self {
1541 self.write_raw(TypeHash::of::<T>())
1542 }
1543
1544 pub fn write_raw(mut self, type_hash: TypeHash) -> Self {
1545 self.filter.insert(type_hash, DynamicQueryFilterMode::Write);
1546 self
1547 }
1548
1549 pub fn include<T>(self) -> Self {
1550 self.include_raw(TypeHash::of::<T>())
1551 }
1552
1553 pub fn include_raw(mut self, type_hash: TypeHash) -> Self {
1554 self.filter
1555 .insert(type_hash, DynamicQueryFilterMode::Include);
1556 self
1557 }
1558
1559 pub fn exclude<T>(self) -> Self {
1560 self.exclude_raw(TypeHash::of::<T>())
1561 }
1562
1563 pub fn exclude_raw(mut self, type_hash: TypeHash) -> Self {
1564 self.filter
1565 .insert(type_hash, DynamicQueryFilterMode::Exclude);
1566 self
1567 }
1568
1569 pub fn does_accept_archetype(&self, archetype: &Archetype) -> bool {
1570 self.filter.iter().all(|(type_hash, mode)| match mode {
1571 DynamicQueryFilterMode::Read
1572 | DynamicQueryFilterMode::Write
1573 | DynamicQueryFilterMode::Include => archetype.has_type(*type_hash),
1574 DynamicQueryFilterMode::Exclude => !archetype.has_type(*type_hash),
1575 })
1576 }
1577
1578 fn columns(&self) -> Vec<(TypeHash, bool)> {
1579 self.columns_iter().collect()
1580 }
1581
1582 fn columns_iter(&self) -> impl Iterator<Item = (TypeHash, bool)> + '_ {
1583 self.filter
1584 .iter()
1585 .filter_map(|(type_hash, mode)| match mode {
1586 DynamicQueryFilterMode::Read => Some((*type_hash, false)),
1587 DynamicQueryFilterMode::Write => Some((*type_hash, true)),
1588 _ => None,
1589 })
1590 }
1591
1592 pub fn unique_access(&self, output: &mut HashSet<TypeHash>) {
1593 for (type_hash, filter) in &self.filter {
1594 if matches!(filter, DynamicQueryFilterMode::Write) {
1595 output.insert(*type_hash);
1596 }
1597 }
1598 }
1599
1600 pub fn query<'a, const LOCKING: bool>(
1601 &self,
1602 world: &'a World,
1603 ) -> DynamicQueryIter<'a, LOCKING> {
1604 world.dynamic_query::<LOCKING>(self)
1605 }
1606
1607 pub fn lookup<'a, const LOCKING: bool>(
1608 &self,
1609 world: &'a World,
1610 entities: impl IntoIterator<Item = Entity> + 'a,
1611 ) -> DynamicLookupIter<'a, LOCKING> {
1612 world.dynamic_lookup::<LOCKING>(self, entities)
1613 }
1614
1615 pub fn lookup_access<'a, const LOCKING: bool>(
1616 &self,
1617 world: &'a World,
1618 ) -> DynamicLookupAccess<'a, LOCKING> {
1619 world.dynamic_lookup_access::<LOCKING>(self)
1620 }
1621}
1622
1623pub struct DynamicQueryItem<'a> {
1624 entity: Entity,
1625 columns: Vec<ArchetypeDynamicColumnItem<'a>>,
1626}
1627
1628impl<'a> DynamicQueryItem<'a> {
1629 pub fn entity(&self) -> Entity {
1630 self.entity
1631 }
1632
1633 pub fn read<T>(&self) -> Result<&ArchetypeDynamicColumnItem<'a>, QueryError> {
1634 self.read_raw(TypeHash::of::<T>())
1635 }
1636
1637 pub fn read_raw(
1638 &self,
1639 type_hash: TypeHash,
1640 ) -> Result<&ArchetypeDynamicColumnItem<'a>, QueryError> {
1641 self.columns
1642 .iter()
1643 .find(|column| column.type_hash() == type_hash)
1644 .ok_or(QueryError::TryingToReadUnavailableType { type_hash })
1645 }
1646
1647 pub fn write<T>(&mut self) -> Result<&mut ArchetypeDynamicColumnItem<'a>, QueryError> {
1648 self.write_raw(TypeHash::of::<T>())
1649 }
1650
1651 pub fn write_raw(
1652 &mut self,
1653 type_hash: TypeHash,
1654 ) -> Result<&mut ArchetypeDynamicColumnItem<'a>, QueryError> {
1655 self.columns
1656 .iter_mut()
1657 .find(|column| column.type_hash() == type_hash)
1658 .ok_or(QueryError::TryingToWriteUnavailableType { type_hash })
1659 }
1660}
1661
1662pub struct DynamicQueryIter<'a, const LOCKING: bool> {
1663 columns: Vec<(TypeHash, bool)>,
1665 archetypes: Vec<&'a Archetype>,
1666 index: usize,
1667 access: Option<(
1668 Box<dyn Iterator<Item = Entity> + 'a>,
1669 Vec<ArchetypeDynamicColumnIter<'a, LOCKING>>,
1670 )>,
1671}
1672
1673impl<'a, const LOCKING: bool> DynamicQueryIter<'a, LOCKING> {
1674 pub fn new(filter: &DynamicQueryFilter, world: &'a World) -> Self {
1675 Self {
1676 columns: filter.columns(),
1677 archetypes: world
1678 .archetypes()
1679 .filter(|archetype| filter.does_accept_archetype(archetype))
1680 .collect(),
1681 index: 0,
1682 access: None,
1683 }
1684 }
1685
1686 pub fn new_view(filter: &DynamicQueryFilter, view: &'a WorldView) -> Self {
1687 Self {
1688 columns: filter.columns(),
1689 archetypes: view
1690 .archetypes()
1691 .filter(|archetype| filter.does_accept_archetype(archetype))
1692 .collect(),
1693 index: 0,
1694 access: None,
1695 }
1696 }
1697}
1698
1699impl<'a, const LOCKING: bool> Iterator for DynamicQueryIter<'a, LOCKING> {
1700 type Item = DynamicQueryItem<'a>;
1701
1702 fn next(&mut self) -> Option<Self::Item> {
1703 while self.index < self.archetypes.len() {
1704 match self.access.as_mut() {
1705 Some((entities, columns)) => {
1706 let entity = entities.next();
1707 match columns
1708 .iter_mut()
1709 .map(|access| access.next())
1710 .collect::<Option<_>>()
1711 .and_then(|columns| Some((entity?, columns)))
1712 {
1713 Some((entity, columns)) => {
1714 return Some(DynamicQueryItem { entity, columns });
1715 }
1716 None => {
1717 self.access = None;
1718 self.index += 1;
1719 continue;
1720 }
1721 }
1722 }
1723 None => {
1724 if let Some(archetype) = self.archetypes.get(self.index) {
1725 self.access = Some((
1726 Box::new(archetype.entities().iter()),
1727 self.columns
1728 .iter()
1729 .copied()
1730 .map(|(type_hash, unique)| {
1731 archetype.dynamic_column_iter(type_hash, unique).unwrap()
1732 })
1733 .collect(),
1734 ));
1735 } else {
1736 self.index += 1;
1737 }
1738 continue;
1739 }
1740 }
1741 }
1742 None
1743 }
1744}
1745
1746pub struct DynamicLookupIter<'a, const LOCKING: bool> {
1747 columns: Vec<(TypeHash, bool)>,
1749 access: Vec<(
1750 &'a EntityDenseMap,
1751 ArchetypeDynamicColumnAccess<'a, LOCKING>,
1752 )>,
1753 entities: Box<dyn Iterator<Item = Entity> + 'a>,
1754}
1755
1756impl<'a, const LOCKING: bool> DynamicLookupIter<'a, LOCKING> {
1757 pub fn new(
1758 filter: &DynamicQueryFilter,
1759 world: &'a World,
1760 entities: impl IntoIterator<Item = Entity> + 'a,
1761 ) -> Self {
1762 Self {
1763 columns: filter.columns(),
1764 access: world
1765 .archetypes()
1766 .filter(|archetype| filter.does_accept_archetype(archetype))
1767 .flat_map(|archetype| {
1768 filter.columns_iter().filter_map(|(type_hash, unique)| {
1769 Some((
1770 archetype.entities(),
1771 archetype.dynamic_column(type_hash, unique).ok()?,
1772 ))
1773 })
1774 })
1775 .collect(),
1776 entities: Box::new(entities.into_iter()),
1777 }
1778 }
1779
1780 pub fn new_view(
1781 filter: &DynamicQueryFilter,
1782 view: &'a WorldView,
1783 entities: impl IntoIterator<Item = Entity> + 'a,
1784 ) -> Self {
1785 Self {
1786 columns: filter.columns(),
1787 access: view
1788 .archetypes()
1789 .filter(|archetype| filter.does_accept_archetype(archetype))
1790 .flat_map(|archetype| {
1791 filter.columns_iter().filter_map(|(type_hash, unique)| {
1792 Some((
1793 archetype.entities(),
1794 archetype.dynamic_column(type_hash, unique).ok()?,
1795 ))
1796 })
1797 })
1798 .collect(),
1799 entities: Box::new(entities.into_iter()),
1800 }
1801 }
1802}
1803
1804impl<'a, const LOCKING: bool> Iterator for DynamicLookupIter<'a, LOCKING> {
1805 type Item = DynamicQueryItem<'a>;
1806
1807 fn next(&mut self) -> Option<Self::Item> {
1808 let entity = self.entities.next()?;
1809 let columns = self
1810 .columns
1811 .iter()
1812 .map(|(type_hash, unique)| {
1813 self.access
1814 .iter()
1815 .find(|(map, access)| {
1816 map.contains(entity)
1817 && access.info().type_hash() == *type_hash
1818 && access.is_unique() == *unique
1819 })
1820 .and_then(|(map, access)| unsafe {
1821 std::mem::transmute(access.dynamic_item(map.index_of(entity).unwrap()).ok())
1822 })
1823 })
1824 .collect::<Option<Vec<_>>>()?;
1825 Some(DynamicQueryItem { entity, columns })
1826 }
1827}
1828
1829pub struct DynamicLookupAccess<'a, const LOCKING: bool> {
1830 columns: Vec<(TypeHash, bool)>,
1832 access: Vec<(
1833 &'a EntityDenseMap,
1834 ArchetypeDynamicColumnAccess<'a, LOCKING>,
1835 )>,
1836}
1837
1838impl<'a, const LOCKING: bool> DynamicLookupAccess<'a, LOCKING> {
1839 pub fn new(filter: &DynamicQueryFilter, world: &'a World) -> Self {
1840 Self {
1841 columns: filter.columns(),
1842 access: world
1843 .archetypes()
1844 .filter(|archetype| filter.does_accept_archetype(archetype))
1845 .flat_map(|archetype| {
1846 filter.columns_iter().filter_map(|(type_hash, unique)| {
1847 Some((
1848 archetype.entities(),
1849 archetype.dynamic_column(type_hash, unique).ok()?,
1850 ))
1851 })
1852 })
1853 .collect(),
1854 }
1855 }
1856
1857 pub fn new_view(filter: &DynamicQueryFilter, view: &'a WorldView) -> Self {
1858 Self {
1859 columns: filter.columns(),
1860 access: view
1861 .archetypes()
1862 .filter(|archetype| filter.does_accept_archetype(archetype))
1863 .flat_map(|archetype| {
1864 filter.columns_iter().filter_map(|(type_hash, unique)| {
1865 Some((
1866 archetype.entities(),
1867 archetype.dynamic_column(type_hash, unique).ok()?,
1868 ))
1869 })
1870 })
1871 .collect(),
1872 }
1873 }
1874
1875 pub fn access(&'_ self, entity: Entity) -> Option<DynamicQueryItem<'_>> {
1876 let columns = self
1877 .columns
1878 .iter()
1879 .map(|(type_hash, unique)| {
1880 self.access
1881 .iter()
1882 .find(|(map, access)| {
1883 map.contains(entity)
1884 && access.info().type_hash() == *type_hash
1885 && access.is_unique() == *unique
1886 })
1887 .and_then(|(map, access)| unsafe {
1888 std::mem::transmute(access.dynamic_item(map.index_of(entity).unwrap()).ok())
1889 })
1890 })
1891 .collect::<Option<Vec<_>>>()?;
1892 Some(DynamicQueryItem { entity, columns })
1893 }
1894}