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 Include<T: Component>(PhantomData<fn() -> T>);
562
563impl<const LOCKING: bool, T: Component> TypedQueryFetch<'_, LOCKING> for Include<T> {
564 type Value = ();
565 type Access = ();
566
567 fn does_accept_archetype(archetype: &Archetype) -> bool {
568 archetype.has_type(TypeHash::of::<T>())
569 }
570
571 fn access(_: &Archetype) -> Result<Self::Access, QueryError> {
572 Ok(())
573 }
574
575 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
576 Some(())
577 }
578}
579
580impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Include<T> {
581 type Value = ();
582 type ValueOne = ();
583 type Access = &'a EntityDenseMap;
584
585 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
586 if archetype.has_type(TypeHash::of::<T>()) {
587 Some(archetype.entities())
588 } else {
589 None
590 }
591 }
592
593 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
594 if access.contains(entity) {
595 Some(())
596 } else {
597 None
598 }
599 }
600
601 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
602 if world.has_entity_component::<T>(entity) {
603 Some(())
604 } else {
605 None
606 }
607 }
608}
609
610pub struct Exclude<T: Component>(PhantomData<fn() -> T>);
611
612impl<const LOCKING: bool, T: Component> TypedQueryFetch<'_, LOCKING> for Exclude<T> {
613 type Value = ();
614 type Access = ();
615
616 fn does_accept_archetype(archetype: &Archetype) -> bool {
617 !archetype.has_type(TypeHash::of::<T>())
618 }
619
620 fn access(_: &Archetype) -> Result<Self::Access, QueryError> {
621 Ok(())
622 }
623
624 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
625 Some(())
626 }
627}
628
629impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Exclude<T> {
630 type Value = ();
631 type ValueOne = ();
632 type Access = &'a EntityDenseMap;
633
634 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
635 if !archetype.has_type(TypeHash::of::<T>()) {
636 Some(archetype.entities())
637 } else {
638 None
639 }
640 }
641
642 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
643 if access.contains(entity) {
644 Some(())
645 } else {
646 None
647 }
648 }
649
650 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
651 if !world.has_entity_component::<T>(entity) {
652 Some(())
653 } else {
654 None
655 }
656 }
657}
658
659pub struct Update<T: Component>(PhantomData<fn() -> T>);
660
661pub struct UpdatedAccess<'a, T>(Entity, &'a mut T);
662
663impl<'a, T> UpdatedAccess<'a, T> {
664 pub fn entity(&self) -> Entity {
665 self.0
666 }
667
668 pub fn read(&'a self) -> &'a T {
669 self.1
670 }
671
672 pub fn write(&'a mut self) -> &'a mut T {
673 self.1
674 }
675
676 pub fn notify(&self, world: &World) {
677 world.update::<T>(self.0);
678 }
679
680 pub fn write_notified(&'a mut self, world: &World) -> &'a mut T {
681 self.notify(world);
682 self.write()
683 }
684}
685
686pub struct UpdatedAccessComponent<'a, const LOCKING: bool, T: Component>(
687 Entity,
688 ComponentRefMut<'a, LOCKING, T>,
689);
690
691impl<'a, const LOCKING: bool, T: Component> UpdatedAccessComponent<'a, LOCKING, T> {
692 pub fn entity(&self) -> Entity {
693 self.0
694 }
695
696 pub fn read(&'a self) -> &'a T {
697 &self.1
698 }
699
700 pub fn write(&'a mut self) -> &'a mut T {
701 &mut self.1
702 }
703
704 pub fn notify(&self, world: &World) {
705 world.update::<T>(self.0);
706 }
707
708 pub fn write_notified(&'a mut self, world: &World) -> &'a mut T {
709 self.notify(world);
710 self.write()
711 }
712}
713
714impl<'a, const LOCKING: bool, T: Component> TypedQueryFetch<'a, LOCKING> for Update<T> {
715 type Value = UpdatedAccess<'a, T>;
716 type Access = Box<dyn Iterator<Item = (Entity, &'a mut T)> + 'a>;
717
718 fn does_accept_archetype(archetype: &Archetype) -> bool {
719 archetype.has_type(TypeHash::of::<T>())
720 }
721
722 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
723 Ok(Box::new(
724 archetype
725 .entities()
726 .iter()
727 .zip(archetype.column_write_iter::<LOCKING, T>()?),
728 ))
729 }
730
731 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
732 access
733 .next()
734 .map(|(entity, data)| UpdatedAccess(entity, data))
735 }
736
737 fn unique_access(output: &mut HashSet<TypeHash>) {
738 output.insert(TypeHash::of::<T>());
739 }
740}
741
742impl<'a, const LOCKING: bool, T: Component> TypedLookupFetch<'a, LOCKING> for Update<T> {
743 type Value = UpdatedAccess<'a, T>;
744 type ValueOne = UpdatedAccessComponent<'a, LOCKING, T>;
745 type Access = (&'a EntityDenseMap, ArchetypeColumnAccess<'a, LOCKING, T>);
746
747 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
748 if archetype.has_type(TypeHash::of::<T>()) {
749 Some((
750 archetype.entities(),
751 archetype.column::<LOCKING, T>(true).ok()?,
752 ))
753 } else {
754 None
755 }
756 }
757
758 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
759 if let Some(index) = access.0.index_of(entity) {
760 access
761 .1
762 .write(index)
763 .map(|value| unsafe { std::mem::transmute(value) })
764 .map(|data| UpdatedAccess(entity, data))
765 } else {
766 None
767 }
768 }
769
770 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
771 world
772 .component_mut::<LOCKING, T>(entity)
773 .ok()
774 .map(|data| UpdatedAccessComponent(entity, data))
775 }
776
777 fn unique_access(output: &mut HashSet<TypeHash>) {
778 output.insert(TypeHash::of::<T>());
779 }
780}
781
782impl<'a> TypedRelationLookupFetch<'a> for () {
783 type Value = ();
784 type Access = ();
785
786 fn access(_: &'a World, _: Entity) -> Self::Access {}
787
788 fn fetch(_: &mut Self::Access) -> Option<Self::Value> {
789 Some(())
790 }
791}
792
793impl<'a> TypedRelationLookupFetch<'a> for Entity {
794 type Value = Entity;
795 type Access = Option<Entity>;
796
797 fn access(_: &'a World, entity: Entity) -> Self::Access {
798 Some(entity)
799 }
800
801 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
802 access.take()
803 }
804}
805
806impl<'a, const LOCKING: bool, Fetch> TypedRelationLookupFetch<'a> for Lookup<'a, LOCKING, Fetch>
807where
808 Fetch: TypedLookupFetch<'a, LOCKING>,
809{
810 type Value = Fetch::ValueOne;
811 type Access = Option<Fetch::ValueOne>;
812
813 fn access(world: &'a World, entity: Entity) -> Self::Access {
814 world.lookup_one::<LOCKING, Fetch>(entity)
815 }
816
817 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
818 access.take()
819 }
820}
821
822pub struct Related<'a, const LOCKING: bool, T, Transform>(PhantomData<fn() -> &'a (T, Transform)>)
823where
824 T: Component,
825 Transform: TypedRelationLookupTransform<'a, Input = Entity>;
826
827impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
828 for Related<'a, LOCKING, T, Transform>
829where
830 T: Component,
831 Transform: TypedRelationLookupTransform<'a, Input = Entity>,
832{
833 type Value = Transform::Output;
834 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
835
836 fn access(world: &'a World, entity: Entity) -> Self::Access {
837 Box::new(
838 world
839 .relations_outgoing::<LOCKING, T>(entity)
840 .flat_map(|(_, _, entity)| Transform::transform(world, entity)),
841 )
842 }
843
844 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
845 access.next()
846 }
847}
848
849pub struct RelatedPair<'a, const LOCKING: bool, T, Transform>(
850 PhantomData<fn() -> &'a (T, Transform)>,
851)
852where
853 T: Component,
854 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>;
855
856impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
857 for RelatedPair<'a, LOCKING, T, Transform>
858where
859 T: Component,
860 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>,
861{
862 type Value = Transform::Output;
863 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
864
865 fn access(world: &'a World, entity: Entity) -> Self::Access {
866 Box::new(
867 world
868 .relations_outgoing::<LOCKING, T>(entity)
869 .flat_map(|(from, _, to)| Transform::transform(world, (from, to))),
870 )
871 }
872
873 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
874 access.next()
875 }
876}
877
878pub struct Traverse<'a, const LOCKING: bool, T, Transform>(PhantomData<fn() -> &'a (T, Transform)>)
879where
880 T: Component,
881 Transform: TypedRelationLookupTransform<'a, Input = Entity>;
882
883impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
884 for Traverse<'a, LOCKING, T, Transform>
885where
886 T: Component,
887 Transform: TypedRelationLookupTransform<'a, Input = Entity>,
888{
889 type Value = Transform::Output;
890 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
891
892 fn access(world: &'a World, entity: Entity) -> Self::Access {
893 Box::new(
894 world
895 .traverse_outgoing::<LOCKING, T>([entity])
896 .flat_map(|(_, to)| Transform::transform(world, to)),
897 )
898 }
899
900 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
901 access.next()
902 }
903}
904
905pub struct TraversePair<'a, const LOCKING: bool, T, Transform>(
906 PhantomData<fn() -> &'a (T, Transform)>,
907)
908where
909 T: Component,
910 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>;
911
912impl<'a, const LOCKING: bool, T, Transform> TypedRelationLookupFetch<'a>
913 for TraversePair<'a, LOCKING, T, Transform>
914where
915 T: Component,
916 Transform: TypedRelationLookupTransform<'a, Input = (Entity, Entity)>,
917{
918 type Value = Transform::Output;
919 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
920
921 fn access(world: &'a World, entity: Entity) -> Self::Access {
922 Box::new(
923 world
924 .traverse_outgoing::<LOCKING, T>([entity])
925 .flat_map(|(from, to)| Transform::transform(world, (from, to))),
926 )
927 }
928
929 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
930 access.next()
931 }
932}
933
934pub struct Join<'a, A, B>(PhantomData<fn() -> &'a (A, B)>)
935where
936 A: TypedRelationLookupFetch<'a>,
937 B: TypedRelationLookupFetch<'a>;
938
939impl<'a, A, B> TypedRelationLookupFetch<'a> for Join<'a, A, B>
940where
941 A: TypedRelationLookupFetch<'a>,
942 B: TypedRelationLookupFetch<'a>,
943{
944 type Value = (Arc<A::Value>, B::Value);
945 type Access = Box<dyn Iterator<Item = Self::Value> + 'a>;
946
947 fn access(world: &'a World, entity: Entity) -> Self::Access {
948 Box::new(
949 TypedRelationLookupIter::<A>::access(A::access(world, entity)).flat_map(move |a| {
950 let a = Arc::new(a);
951 TypedRelationLookupIter::<B>::access(B::access(world, entity))
952 .map(move |b| (a.clone(), b))
953 }),
954 )
955 }
956
957 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
958 access.next()
959 }
960}
961
962impl<'a> TypedRelationLookupTransform<'a> for Entity {
963 type Input = Entity;
964 type Output = Entity;
965
966 fn transform(_: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
967 std::iter::once(input)
968 }
969}
970
971pub struct Is<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>(
972 PhantomData<fn() -> &'a Fetch>,
973);
974
975impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedRelationLookupTransform<'a>
976 for Is<'a, LOCKING, Fetch>
977{
978 type Input = Entity;
979 type Output = Entity;
980
981 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
982 world
983 .lookup_one::<LOCKING, Fetch>(input)
984 .is_some()
985 .then_some(input)
986 .into_iter()
987 }
988}
989
990pub struct IsNot<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>(
991 PhantomData<fn() -> &'a Fetch>,
992);
993
994impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedRelationLookupTransform<'a>
995 for IsNot<'a, LOCKING, Fetch>
996{
997 type Input = Entity;
998 type Output = Entity;
999
1000 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1001 world
1002 .lookup_one::<LOCKING, Fetch>(input)
1003 .is_none()
1004 .then_some(input)
1005 .into_iter()
1006 }
1007}
1008
1009impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> TypedRelationLookupTransform<'a>
1010 for Lookup<'a, LOCKING, Fetch>
1011{
1012 type Input = Entity;
1013 type Output = Fetch::ValueOne;
1014
1015 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1016 world.lookup_one::<LOCKING, Fetch>(input).into_iter()
1017 }
1018}
1019
1020pub struct Limit<'a, const COUNT: usize, Transform: TypedRelationLookupTransform<'a>>(
1021 PhantomData<fn() -> &'a Transform>,
1022);
1023
1024impl<'a, const COUNT: usize, Transform: TypedRelationLookupTransform<'a>>
1025 TypedRelationLookupTransform<'a> for Limit<'a, COUNT, Transform>
1026{
1027 type Input = Transform::Input;
1028 type Output = Transform::Output;
1029
1030 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1031 Transform::transform(world, input).take(COUNT)
1032 }
1033}
1034
1035pub type Single<'a, Transform> = Limit<'a, 1, Transform>;
1036
1037pub struct SelectEntity<const INDEX: usize>;
1038
1039impl<'a, const INDEX: usize> TypedRelationLookupTransform<'a> for SelectEntity<INDEX> {
1040 type Input = (Entity, Entity);
1041 type Output = Entity;
1042
1043 fn transform(_: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1044 if INDEX == 0 {
1045 std::iter::once(input.0)
1046 } else {
1047 std::iter::once(input.1)
1048 }
1049 }
1050}
1051
1052pub struct Follow<'a, const LOCKING: bool, Transform, Fetch>(
1053 PhantomData<fn() -> &'a (Transform, Fetch)>,
1054)
1055where
1056 Transform: TypedRelationLookupTransform<'a, Input = Entity, Output = Entity>,
1057 Fetch: TypedRelationLookupFetch<'a>;
1058
1059impl<'a, const LOCKING: bool, Transform, Fetch> TypedRelationLookupTransform<'a>
1060 for Follow<'a, LOCKING, Transform, Fetch>
1061where
1062 Transform: TypedRelationLookupTransform<'a, Input = Entity, Output = Entity>,
1063 Fetch: TypedRelationLookupFetch<'a>,
1064{
1065 type Input = Entity;
1066 type Output = Fetch::Value;
1067
1068 fn transform(world: &'a World, input: Self::Input) -> impl Iterator<Item = Self::Output> {
1069 Transform::transform(world, input)
1070 .flat_map(|entity| world.relation_lookup::<LOCKING, Fetch>(entity))
1071 }
1072}
1073
1074macro_rules! impl_typed_query_fetch_tuple {
1075 ($($type:ident),+) => {
1076 impl<'a, const LOCKING: bool, $($type: TypedQueryFetch<'a, LOCKING>),+> TypedQueryFetch<'a, LOCKING> for ($($type,)+) {
1077 type Value = ($($type::Value,)+);
1078 type Access = ($($type::Access,)+);
1079
1080 fn does_accept_archetype(archetype: &Archetype) -> bool {
1081 $($type::does_accept_archetype(archetype))&&+
1082 }
1083
1084 fn access(archetype: &'a Archetype) -> Result<Self::Access, QueryError> {
1085 Ok(($($type::access(archetype)?,)+))
1086 }
1087
1088 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1089 #[allow(non_snake_case)]
1090 let ($($type,)+) = access;
1091 Some(($($type::fetch($type)?,)+))
1092 }
1093
1094 fn unique_access(output: &mut HashSet<TypeHash>) {
1095 $(
1096 $type::unique_access(output);
1097 )+
1098 }
1099 }
1100 };
1101}
1102
1103impl_typed_query_fetch_tuple!(A);
1104impl_typed_query_fetch_tuple!(A, B);
1105impl_typed_query_fetch_tuple!(A, B, C);
1106impl_typed_query_fetch_tuple!(A, B, C, D);
1107impl_typed_query_fetch_tuple!(A, B, C, D, E);
1108impl_typed_query_fetch_tuple!(A, B, C, D, E, F);
1109impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G);
1110impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H);
1111impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I);
1112impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J);
1113impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1114impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1115impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1116impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
1117impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
1118impl_typed_query_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
1119
1120macro_rules! impl_typed_lookup_fetch_tuple {
1121 ($($type:ident),+) => {
1122 impl<'a, const LOCKING: bool, $($type: TypedLookupFetch<'a, LOCKING>),+> TypedLookupFetch<'a, LOCKING> for ($($type,)+) {
1123 type Value = ($($type::Value,)+);
1124 type ValueOne = ($($type::ValueOne,)+);
1125 type Access = ($($type::Access,)+);
1126
1127 fn try_access(archetype: &'a Archetype) -> Option<Self::Access> {
1128 Some(($($type::try_access(archetype)?,)+))
1129 }
1130
1131 fn fetch(access: &mut Self::Access, entity: Entity) -> Option<Self::Value> {
1132 #[allow(non_snake_case)]
1133 let ($($type,)+) = access;
1134 Some(($($type::fetch($type, entity)?,)+))
1135 }
1136
1137 fn fetch_one(world: &'a World, entity: Entity) -> Option<Self::ValueOne> {
1138 Some(($($type::fetch_one(world, entity)?,)+))
1139 }
1140
1141 fn unique_access(output: &mut HashSet<TypeHash>) {
1142 $(
1143 $type::unique_access(output);
1144 )+
1145 }
1146 }
1147 };
1148}
1149
1150impl_typed_lookup_fetch_tuple!(A);
1151impl_typed_lookup_fetch_tuple!(A, B);
1152impl_typed_lookup_fetch_tuple!(A, B, C);
1153impl_typed_lookup_fetch_tuple!(A, B, C, D);
1154impl_typed_lookup_fetch_tuple!(A, B, C, D, E);
1155impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F);
1156impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G);
1157impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H);
1158impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I);
1159impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J);
1160impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1161impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1162impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1163impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
1164impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
1165impl_typed_lookup_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
1166
1167macro_rules! impl_typed_relation_fetch_tuple {
1168 ($($type:ident),+) => {
1169 impl<'a, $($type: TypedRelationLookupFetch<'a>),+> TypedRelationLookupFetch<'a> for ($($type,)+) {
1170 type Value = ($($type::Value,)+);
1171 type Access = ($($type::Access,)+);
1172
1173 fn access(world: &'a World, entity: Entity) -> Self::Access {
1174 ($($type::access(world, entity),)+)
1175 }
1176
1177 fn fetch(access: &mut Self::Access) -> Option<Self::Value> {
1178 #[allow(non_snake_case)]
1179 let ($($type,)+) = access;
1180 Some(($($type::fetch($type)?,)+))
1181 }
1182 }
1183 };
1184}
1185
1186impl_typed_relation_fetch_tuple!(A);
1187impl_typed_relation_fetch_tuple!(A, B);
1188impl_typed_relation_fetch_tuple!(A, B, C);
1189impl_typed_relation_fetch_tuple!(A, B, C, D);
1190impl_typed_relation_fetch_tuple!(A, B, C, D, E);
1191impl_typed_relation_fetch_tuple!(A, B, C, D, E, F);
1192impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G);
1193impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H);
1194impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I);
1195impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J);
1196impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K);
1197impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
1198impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M);
1199impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O);
1200impl_typed_relation_fetch_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P);
1201
1202pub struct TypedQueryIter<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> {
1203 archetypes: Vec<&'a Archetype>,
1204 index: usize,
1205 access: Option<Fetch::Access>,
1206 _phantom: PhantomData<fn() -> Fetch>,
1207}
1208
1209impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>>
1210 TypedQueryIter<'a, LOCKING, Fetch>
1211{
1212 pub fn new(world: &'a World) -> Self {
1213 Self {
1214 archetypes: world
1215 .archetypes()
1216 .filter(|archetype| Fetch::does_accept_archetype(archetype))
1217 .collect(),
1218 index: 0,
1219 access: None,
1220 _phantom: PhantomData,
1221 }
1222 }
1223
1224 pub fn new_view(view: &'a WorldView) -> Self {
1225 Self {
1226 archetypes: view
1227 .archetypes()
1228 .filter(|archetype| Fetch::does_accept_archetype(archetype))
1229 .collect(),
1230 index: 0,
1231 access: None,
1232 _phantom: PhantomData,
1233 }
1234 }
1235}
1236
1237impl<'a, const LOCKING: bool, Fetch: TypedQueryFetch<'a, LOCKING>> Iterator
1238 for TypedQueryIter<'a, LOCKING, Fetch>
1239{
1240 type Item = Fetch::Value;
1241
1242 fn next(&mut self) -> Option<Self::Item> {
1243 while self.index < self.archetypes.len() {
1244 match self.access.as_mut() {
1245 Some(access) => {
1246 let item = Fetch::fetch(access);
1247 if item.is_none() {
1248 self.access = None;
1249 self.index += 1;
1250 continue;
1251 }
1252 return item;
1253 }
1254 None => {
1255 if let Some(archetype) = self.archetypes.get(self.index) {
1256 self.access = Some(Fetch::access(archetype).unwrap());
1257 } else {
1258 self.index += 1;
1259 }
1260 continue;
1261 }
1262 }
1263 }
1264 None
1265 }
1266}
1267
1268pub struct TypedLookupIter<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> {
1269 access: Vec<Fetch::Access>,
1270 entities: Box<dyn Iterator<Item = Entity> + 'a>,
1271 _phantom: PhantomData<fn() -> Fetch>,
1272}
1273
1274impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>
1275 TypedLookupIter<'a, LOCKING, Fetch>
1276{
1277 pub fn new(world: &'a World, entities: impl IntoIterator<Item = Entity> + 'a) -> Self {
1278 Self {
1279 access: world
1280 .archetypes()
1281 .filter_map(|archetype| Fetch::try_access(archetype))
1282 .collect(),
1283 entities: Box::new(entities.into_iter()),
1284 _phantom: PhantomData,
1285 }
1286 }
1287
1288 pub fn new_view(view: &'a WorldView, entities: impl IntoIterator<Item = Entity> + 'a) -> Self {
1289 Self {
1290 access: view
1291 .archetypes()
1292 .filter_map(|archetype| Fetch::try_access(archetype))
1293 .collect(),
1294 entities: Box::new(entities.into_iter()),
1295 _phantom: PhantomData,
1296 }
1297 }
1298}
1299
1300impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> Iterator
1301 for TypedLookupIter<'a, LOCKING, Fetch>
1302{
1303 type Item = Fetch::Value;
1304
1305 fn next(&mut self) -> Option<Self::Item> {
1306 let entity = self.entities.next()?;
1307 for access in &mut self.access {
1308 if let Some(result) = Fetch::fetch(access, entity) {
1309 return Some(result);
1310 }
1311 }
1312 None
1313 }
1314}
1315
1316pub struct TypedLookupAccess<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>> {
1317 access: Vec<Fetch::Access>,
1318 _phantom: PhantomData<fn() -> Fetch>,
1319}
1320
1321impl<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING>>
1322 TypedLookupAccess<'a, LOCKING, Fetch>
1323{
1324 pub fn new(world: &'a World) -> Self {
1325 Self {
1326 access: world
1327 .archetypes()
1328 .filter_map(|archetype| Fetch::try_access(archetype))
1329 .collect(),
1330 _phantom: PhantomData,
1331 }
1332 }
1333
1334 pub fn new_view(view: &'a WorldView) -> Self {
1335 Self {
1336 access: view
1337 .archetypes()
1338 .filter_map(|archetype| Fetch::try_access(archetype))
1339 .collect(),
1340 _phantom: PhantomData,
1341 }
1342 }
1343
1344 pub fn access(&mut self, entity: Entity) -> Option<Fetch::Value> {
1345 for access in &mut self.access {
1346 if let Some(result) = Fetch::fetch(access, entity) {
1347 return Some(result);
1348 }
1349 }
1350 None
1351 }
1352}
1353
1354pub struct TypedRelationLookupIter<'a, Fetch: TypedRelationLookupFetch<'a>> {
1355 access: Fetch::Access,
1356}
1357
1358impl<'a, Fetch: TypedRelationLookupFetch<'a>> TypedRelationLookupIter<'a, Fetch> {
1359 pub fn new(world: &'a World, entity: Entity) -> Self {
1360 Self {
1361 access: Fetch::access(world, entity),
1362 }
1363 }
1364
1365 pub fn access(access: Fetch::Access) -> Self {
1366 Self { access }
1367 }
1368}
1369
1370impl<'a, Fetch: TypedRelationLookupFetch<'a>> Iterator for TypedRelationLookupIter<'a, Fetch> {
1371 type Item = Fetch::Value;
1372
1373 fn next(&mut self) -> Option<Self::Item> {
1374 Fetch::fetch(&mut self.access)
1375 }
1376}
1377
1378#[derive(Debug)]
1379enum DynamicQueryFilterMode {
1380 Read,
1381 Write,
1382 Include,
1383 Exclude,
1384}
1385
1386#[derive(Debug, Default)]
1387pub struct DynamicQueryFilter {
1388 filter: HashMap<TypeHash, DynamicQueryFilterMode>,
1389}
1390
1391impl DynamicQueryFilter {
1392 pub fn from_raw(
1393 read: &[TypeHash],
1394 write: &[TypeHash],
1395 include: &[TypeHash],
1396 exclude: &[TypeHash],
1397 ) -> Self {
1398 Self {
1399 filter: read
1400 .iter()
1401 .copied()
1402 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Read))
1403 .chain(
1404 write
1405 .iter()
1406 .copied()
1407 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Write)),
1408 )
1409 .chain(
1410 include
1411 .iter()
1412 .copied()
1413 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Include)),
1414 )
1415 .chain(
1416 exclude
1417 .iter()
1418 .copied()
1419 .map(|type_hash| (type_hash, DynamicQueryFilterMode::Exclude)),
1420 )
1421 .collect(),
1422 }
1423 }
1424
1425 pub fn read<T>(self) -> Self {
1426 self.read_raw(TypeHash::of::<T>())
1427 }
1428
1429 pub fn read_raw(mut self, type_hash: TypeHash) -> Self {
1430 self.filter.insert(type_hash, DynamicQueryFilterMode::Read);
1431 self
1432 }
1433
1434 pub fn write<T>(self) -> Self {
1435 self.write_raw(TypeHash::of::<T>())
1436 }
1437
1438 pub fn write_raw(mut self, type_hash: TypeHash) -> Self {
1439 self.filter.insert(type_hash, DynamicQueryFilterMode::Write);
1440 self
1441 }
1442
1443 pub fn include<T>(self) -> Self {
1444 self.include_raw(TypeHash::of::<T>())
1445 }
1446
1447 pub fn include_raw(mut self, type_hash: TypeHash) -> Self {
1448 self.filter
1449 .insert(type_hash, DynamicQueryFilterMode::Include);
1450 self
1451 }
1452
1453 pub fn exclude<T>(self) -> Self {
1454 self.exclude_raw(TypeHash::of::<T>())
1455 }
1456
1457 pub fn exclude_raw(mut self, type_hash: TypeHash) -> Self {
1458 self.filter
1459 .insert(type_hash, DynamicQueryFilterMode::Exclude);
1460 self
1461 }
1462
1463 pub fn does_accept_archetype(&self, archetype: &Archetype) -> bool {
1464 self.filter.iter().all(|(type_hash, mode)| match mode {
1465 DynamicQueryFilterMode::Read
1466 | DynamicQueryFilterMode::Write
1467 | DynamicQueryFilterMode::Include => archetype.has_type(*type_hash),
1468 DynamicQueryFilterMode::Exclude => !archetype.has_type(*type_hash),
1469 })
1470 }
1471
1472 fn columns(&self) -> Vec<(TypeHash, bool)> {
1473 self.columns_iter().collect()
1474 }
1475
1476 fn columns_iter(&self) -> impl Iterator<Item = (TypeHash, bool)> + '_ {
1477 self.filter
1478 .iter()
1479 .filter_map(|(type_hash, mode)| match mode {
1480 DynamicQueryFilterMode::Read => Some((*type_hash, false)),
1481 DynamicQueryFilterMode::Write => Some((*type_hash, true)),
1482 _ => None,
1483 })
1484 }
1485
1486 pub fn unique_access(&self, output: &mut HashSet<TypeHash>) {
1487 for (type_hash, filter) in &self.filter {
1488 if matches!(filter, DynamicQueryFilterMode::Write) {
1489 output.insert(*type_hash);
1490 }
1491 }
1492 }
1493
1494 pub fn query<'a, const LOCKING: bool>(
1495 &self,
1496 world: &'a World,
1497 ) -> DynamicQueryIter<'a, LOCKING> {
1498 world.dynamic_query::<LOCKING>(self)
1499 }
1500
1501 pub fn lookup<'a, const LOCKING: bool>(
1502 &self,
1503 world: &'a World,
1504 entities: impl IntoIterator<Item = Entity> + 'a,
1505 ) -> DynamicLookupIter<'a, LOCKING> {
1506 world.dynamic_lookup::<LOCKING>(self, entities)
1507 }
1508
1509 pub fn lookup_access<'a, const LOCKING: bool>(
1510 &self,
1511 world: &'a World,
1512 ) -> DynamicLookupAccess<'a, LOCKING> {
1513 world.dynamic_lookup_access::<LOCKING>(self)
1514 }
1515}
1516
1517pub struct DynamicQueryItem<'a> {
1518 entity: Entity,
1519 columns: Vec<ArchetypeDynamicColumnItem<'a>>,
1520}
1521
1522impl<'a> DynamicQueryItem<'a> {
1523 pub fn entity(&self) -> Entity {
1524 self.entity
1525 }
1526
1527 pub fn read<T>(&self) -> Result<&ArchetypeDynamicColumnItem<'a>, QueryError> {
1528 self.read_raw(TypeHash::of::<T>())
1529 }
1530
1531 pub fn read_raw(
1532 &self,
1533 type_hash: TypeHash,
1534 ) -> Result<&ArchetypeDynamicColumnItem<'a>, QueryError> {
1535 self.columns
1536 .iter()
1537 .find(|column| column.type_hash() == type_hash)
1538 .ok_or(QueryError::TryingToReadUnavailableType { type_hash })
1539 }
1540
1541 pub fn write<T>(&mut self) -> Result<&mut ArchetypeDynamicColumnItem<'a>, QueryError> {
1542 self.write_raw(TypeHash::of::<T>())
1543 }
1544
1545 pub fn write_raw(
1546 &mut self,
1547 type_hash: TypeHash,
1548 ) -> Result<&mut ArchetypeDynamicColumnItem<'a>, QueryError> {
1549 self.columns
1550 .iter_mut()
1551 .find(|column| column.type_hash() == type_hash)
1552 .ok_or(QueryError::TryingToWriteUnavailableType { type_hash })
1553 }
1554}
1555
1556pub struct DynamicQueryIter<'a, const LOCKING: bool> {
1557 columns: Vec<(TypeHash, bool)>,
1559 archetypes: Vec<&'a Archetype>,
1560 index: usize,
1561 access: Option<(
1562 Box<dyn Iterator<Item = Entity> + 'a>,
1563 Vec<ArchetypeDynamicColumnIter<'a, LOCKING>>,
1564 )>,
1565}
1566
1567impl<'a, const LOCKING: bool> DynamicQueryIter<'a, LOCKING> {
1568 pub fn new(filter: &DynamicQueryFilter, world: &'a World) -> Self {
1569 Self {
1570 columns: filter.columns(),
1571 archetypes: world
1572 .archetypes()
1573 .filter(|archetype| filter.does_accept_archetype(archetype))
1574 .collect(),
1575 index: 0,
1576 access: None,
1577 }
1578 }
1579
1580 pub fn new_view(filter: &DynamicQueryFilter, view: &'a WorldView) -> Self {
1581 Self {
1582 columns: filter.columns(),
1583 archetypes: view
1584 .archetypes()
1585 .filter(|archetype| filter.does_accept_archetype(archetype))
1586 .collect(),
1587 index: 0,
1588 access: None,
1589 }
1590 }
1591}
1592
1593impl<'a, const LOCKING: bool> Iterator for DynamicQueryIter<'a, LOCKING> {
1594 type Item = DynamicQueryItem<'a>;
1595
1596 fn next(&mut self) -> Option<Self::Item> {
1597 while self.index < self.archetypes.len() {
1598 match self.access.as_mut() {
1599 Some((entities, columns)) => {
1600 let entity = entities.next();
1601 match columns
1602 .iter_mut()
1603 .map(|access| access.next())
1604 .collect::<Option<_>>()
1605 .and_then(|columns| Some((entity?, columns)))
1606 {
1607 Some((entity, columns)) => {
1608 return Some(DynamicQueryItem { entity, columns });
1609 }
1610 None => {
1611 self.access = None;
1612 self.index += 1;
1613 continue;
1614 }
1615 }
1616 }
1617 None => {
1618 if let Some(archetype) = self.archetypes.get(self.index) {
1619 self.access = Some((
1620 Box::new(archetype.entities().iter()),
1621 self.columns
1622 .iter()
1623 .copied()
1624 .map(|(type_hash, unique)| {
1625 archetype.dynamic_column_iter(type_hash, unique).unwrap()
1626 })
1627 .collect(),
1628 ));
1629 } else {
1630 self.index += 1;
1631 }
1632 continue;
1633 }
1634 }
1635 }
1636 None
1637 }
1638}
1639
1640pub struct DynamicLookupIter<'a, const LOCKING: bool> {
1641 columns: Vec<(TypeHash, bool)>,
1643 access: Vec<(
1644 &'a EntityDenseMap,
1645 ArchetypeDynamicColumnAccess<'a, LOCKING>,
1646 )>,
1647 entities: Box<dyn Iterator<Item = Entity> + 'a>,
1648}
1649
1650impl<'a, const LOCKING: bool> DynamicLookupIter<'a, LOCKING> {
1651 pub fn new(
1652 filter: &DynamicQueryFilter,
1653 world: &'a World,
1654 entities: impl IntoIterator<Item = Entity> + 'a,
1655 ) -> Self {
1656 Self {
1657 columns: filter.columns(),
1658 access: world
1659 .archetypes()
1660 .filter(|archetype| filter.does_accept_archetype(archetype))
1661 .flat_map(|archetype| {
1662 filter.columns_iter().filter_map(|(type_hash, unique)| {
1663 Some((
1664 archetype.entities(),
1665 archetype.dynamic_column(type_hash, unique).ok()?,
1666 ))
1667 })
1668 })
1669 .collect(),
1670 entities: Box::new(entities.into_iter()),
1671 }
1672 }
1673
1674 pub fn new_view(
1675 filter: &DynamicQueryFilter,
1676 view: &'a WorldView,
1677 entities: impl IntoIterator<Item = Entity> + 'a,
1678 ) -> Self {
1679 Self {
1680 columns: filter.columns(),
1681 access: view
1682 .archetypes()
1683 .filter(|archetype| filter.does_accept_archetype(archetype))
1684 .flat_map(|archetype| {
1685 filter.columns_iter().filter_map(|(type_hash, unique)| {
1686 Some((
1687 archetype.entities(),
1688 archetype.dynamic_column(type_hash, unique).ok()?,
1689 ))
1690 })
1691 })
1692 .collect(),
1693 entities: Box::new(entities.into_iter()),
1694 }
1695 }
1696}
1697
1698impl<'a, const LOCKING: bool> Iterator for DynamicLookupIter<'a, LOCKING> {
1699 type Item = DynamicQueryItem<'a>;
1700
1701 fn next(&mut self) -> Option<Self::Item> {
1702 let entity = self.entities.next()?;
1703 let columns = self
1704 .columns
1705 .iter()
1706 .map(|(type_hash, unique)| {
1707 self.access
1708 .iter()
1709 .find(|(map, access)| {
1710 map.contains(entity)
1711 && access.info().type_hash() == *type_hash
1712 && access.is_unique() == *unique
1713 })
1714 .and_then(|(map, access)| unsafe {
1715 std::mem::transmute(access.dynamic_item(map.index_of(entity).unwrap()).ok())
1716 })
1717 })
1718 .collect::<Option<Vec<_>>>()?;
1719 Some(DynamicQueryItem { entity, columns })
1720 }
1721}
1722
1723pub struct DynamicLookupAccess<'a, const LOCKING: bool> {
1724 columns: Vec<(TypeHash, bool)>,
1726 access: Vec<(
1727 &'a EntityDenseMap,
1728 ArchetypeDynamicColumnAccess<'a, LOCKING>,
1729 )>,
1730}
1731
1732impl<'a, const LOCKING: bool> DynamicLookupAccess<'a, LOCKING> {
1733 pub fn new(filter: &DynamicQueryFilter, world: &'a World) -> Self {
1734 Self {
1735 columns: filter.columns(),
1736 access: world
1737 .archetypes()
1738 .filter(|archetype| filter.does_accept_archetype(archetype))
1739 .flat_map(|archetype| {
1740 filter.columns_iter().filter_map(|(type_hash, unique)| {
1741 Some((
1742 archetype.entities(),
1743 archetype.dynamic_column(type_hash, unique).ok()?,
1744 ))
1745 })
1746 })
1747 .collect(),
1748 }
1749 }
1750
1751 pub fn new_view(filter: &DynamicQueryFilter, view: &'a WorldView) -> Self {
1752 Self {
1753 columns: filter.columns(),
1754 access: view
1755 .archetypes()
1756 .filter(|archetype| filter.does_accept_archetype(archetype))
1757 .flat_map(|archetype| {
1758 filter.columns_iter().filter_map(|(type_hash, unique)| {
1759 Some((
1760 archetype.entities(),
1761 archetype.dynamic_column(type_hash, unique).ok()?,
1762 ))
1763 })
1764 })
1765 .collect(),
1766 }
1767 }
1768
1769 pub fn access(&self, entity: Entity) -> Option<DynamicQueryItem> {
1770 let columns = self
1771 .columns
1772 .iter()
1773 .map(|(type_hash, unique)| {
1774 self.access
1775 .iter()
1776 .find(|(map, access)| {
1777 map.contains(entity)
1778 && access.info().type_hash() == *type_hash
1779 && access.is_unique() == *unique
1780 })
1781 .and_then(|(map, access)| unsafe {
1782 std::mem::transmute(access.dynamic_item(map.index_of(entity).unwrap()).ok())
1783 })
1784 })
1785 .collect::<Option<Vec<_>>>()?;
1786 Some(DynamicQueryItem { entity, columns })
1787 }
1788}