1use std::any::TypeId;
4use std::collections::HashSet;
5
6use crate::archetype::{ArchetypeLayout, ArchetypeStore, EntityLocation};
7use crate::commands::CommandBuffer;
8use crate::component::Component;
9use crate::deadline::{Clock, DeadlineId, Deadlines, Timestamp};
10use crate::entity::{Entity, EntityMetaStore};
11use crate::event::Events;
12use crate::query::{
13 AddedIter, ChangedIter, Mut, Query2Iter, Query2MutIter, Query3Iter, Query3MutIter, QueryFilter,
14 QueryIter, QueryIterMut, QuerySpec, QuerySpecMut,
15};
16use crate::resource::Resources;
17
18pub trait Bundle: 'static {
27 fn type_ids() -> Vec<TypeId>;
32
33 fn register_columns(store: &mut ArchetypeStore);
35
36 fn push_into_columns(self, archetype: &mut crate::archetype::Archetype);
40}
41
42impl<A: Component> Bundle for (A,) {
44 fn type_ids() -> Vec<TypeId> {
45 vec![TypeId::of::<A>()]
46 }
47
48 fn register_columns(store: &mut ArchetypeStore) {
49 store.register_column::<A>();
50 }
51
52 fn push_into_columns(self, archetype: &mut crate::archetype::Archetype) {
53 archetype.column_mut::<A>().unwrap().push(self.0);
54 }
55}
56
57macro_rules! impl_bundle {
59 ($($t:ident),+) => {
60 #[allow(non_snake_case)]
61 impl<$($t: Component),+> Bundle for ($($t,)+) {
62 fn type_ids() -> Vec<TypeId> {
63 let mut ids = vec![$(TypeId::of::<$t>()),+];
64 let original_len = ids.len();
65 ids.sort();
66 ids.dedup();
67 assert_eq!(
68 ids.len(),
69 original_len,
70 "duplicate component types are not allowed in a Bundle"
71 );
72 ids
73 }
74
75 fn register_columns(store: &mut ArchetypeStore) {
76 $(store.register_column::<$t>();)+
77 }
78
79 fn push_into_columns(self, archetype: &mut crate::archetype::Archetype) {
80 let ($($t,)+) = self;
81 $(archetype.column_mut::<$t>().unwrap().push($t);)+
82 }
83 }
84 };
85}
86
87impl_bundle!(A, B);
88impl_bundle!(A, B, C);
89impl_bundle!(A, B, C, D);
90impl_bundle!(A, B, C, D, E);
91impl_bundle!(A, B, C, D, E, F);
92impl_bundle!(A, B, C, D, E, F, G);
93impl_bundle!(A, B, C, D, E, F, G, H);
94
95#[derive(Copy, Clone)]
116pub struct UnsafeWorldCell(*mut World);
117
118impl UnsafeWorldCell {
119 #[inline]
126 pub unsafe fn new(world: *mut World) -> Self {
127 debug_assert!(!world.is_null());
128 Self(world)
129 }
130
131 #[inline]
143 pub unsafe fn get_resource<'w, T: Send + 'static>(self) -> &'w T {
144 unsafe {
148 let resources_ptr: *const Resources = std::ptr::addr_of!((*self.0).resources);
149 (*resources_ptr).get_unchecked::<T>()
150 }
151 }
152
153 #[inline]
167 pub unsafe fn get_resource_mut<'w, T: Send + 'static>(self) -> &'w mut T {
168 unsafe {
172 let resources_ptr: *const Resources = std::ptr::addr_of!((*self.0).resources);
173 (*resources_ptr).get_mut_unchecked::<T>()
174 }
175 }
176
177 #[inline]
184 pub unsafe fn archetypes<'w>(self) -> &'w ArchetypeStore {
185 unsafe {
187 let ptr: *const ArchetypeStore = std::ptr::addr_of!((*self.0).archetypes);
188 &*ptr
189 }
190 }
191
192 #[inline]
206 pub unsafe fn archetypes_mut_ptr(self) -> *mut ArchetypeStore {
207 unsafe { std::ptr::addr_of_mut!((*self.0).archetypes) }
210 }
211
212 #[inline]
221 pub unsafe fn commands_mut<'w>(self) -> &'w mut CommandBuffer {
222 unsafe {
225 let ptr: *mut CommandBuffer = std::ptr::addr_of_mut!((*self.0).commands);
226 &mut *ptr
227 }
228 }
229
230 #[inline]
236 pub unsafe fn change_tick(self) -> u64 {
237 unsafe {
238 let ptr: *const u64 = std::ptr::addr_of!((*self.0).change_tick);
239 *ptr
240 }
241 }
242}
243
244type EventUpdater = Box<dyn Fn(&mut World) + Send>;
250
251type DeadlineDrainer = Box<dyn Fn(&mut World, Timestamp) + Send>;
253
254pub struct World {
256 meta: EntityMetaStore,
257 archetypes: ArchetypeStore,
258 resources: Resources,
259 commands: CommandBuffer,
260 change_tick: u64,
263 event_updaters: Vec<EventUpdater>,
269 registered_events: HashSet<TypeId>,
273 deadline_drainers: Vec<DeadlineDrainer>,
277 registered_deadlines: HashSet<TypeId>,
279 component_removals: Vec<(Entity, TypeId, u64)>,
287 event_swap_epoch: u64,
290}
291
292impl World {
293 pub fn new() -> Self {
295 let mut archetypes = ArchetypeStore::new();
296 archetypes.get_or_create(ArchetypeLayout::empty());
298 Self {
299 meta: EntityMetaStore::new(),
300 archetypes,
301 resources: Resources::new(),
302 commands: CommandBuffer::new(),
303 change_tick: 1,
304 event_updaters: Vec::new(),
305 registered_events: HashSet::new(),
306 deadline_drainers: Vec::new(),
307 registered_deadlines: HashSet::new(),
308 component_removals: Vec::new(),
309 event_swap_epoch: 0,
310 }
311 }
312
313 pub fn change_tick(&self) -> u64 {
319 self.change_tick
320 }
321
322 pub fn advance_tick(&mut self) -> u64 {
324 self.change_tick += 1;
325 let ct = self.change_tick;
326 const REMOVAL_LOG_TICK_WINDOW: u64 = 10_000;
330 self.component_removals
331 .retain(|(_, _, tick)| *tick + REMOVAL_LOG_TICK_WINDOW > ct);
332 ct
333 }
334
335 pub fn spawn<B: Bundle>(&mut self, bundle: B) -> Entity {
341 let type_ids = B::type_ids();
342 let entity = self.meta.alloc();
343 B::register_columns(&mut self.archetypes);
344 let layout = ArchetypeLayout::from_type_ids(&type_ids);
345 let arch_id = self.archetypes.get_or_create(layout);
346 let tick = self.change_tick;
347 let arch = self.archetypes.get_mut(arch_id);
348 bundle.push_into_columns(arch);
349 let row = arch.push_entity(entity);
350 arch.stamp_all_ticks(row, tick, tick);
352 self.meta.set_location(
353 entity,
354 EntityLocation {
355 archetype_id: arch_id,
356 row,
357 },
358 );
359 entity
360 }
361
362 pub fn despawn(&mut self, entity: Entity) -> bool {
364 let Some(loc) = self.meta.get_location(entity) else {
365 return false;
366 };
367
368 let arch = self.archetypes.get_mut(loc.archetype_id);
369 let (_removed, moved) = arch.swap_remove_entity(loc.row as usize);
370
371 if let Some(moved_entity) = moved {
373 self.meta.set_location(
374 moved_entity,
375 EntityLocation {
376 archetype_id: loc.archetype_id,
377 row: loc.row,
378 },
379 );
380 }
381
382 self.meta.dealloc(entity);
383 true
384 }
385
386 pub fn is_alive(&self, entity: Entity) -> bool {
388 self.meta.is_alive(entity)
389 }
390
391 pub fn insert_resource<T: Send + 'static>(&mut self, value: T) {
397 self.resources.insert(value);
398 }
399
400 pub fn resource<T: Send + 'static>(&self) -> &T {
402 self.resources.get::<T>()
403 }
404
405 pub fn resource_mut<T: Send + 'static>(&mut self) -> &mut T {
407 self.resources.get_mut::<T>()
408 }
409
410 pub fn try_resource<T: Send + 'static>(&self) -> Option<&T> {
412 self.resources.try_get::<T>()
413 }
414
415 pub fn take_resource<T: Send + 'static>(&mut self) -> T {
417 self.resources.take::<T>()
418 }
419
420 pub fn try_take_resource<T: Send + 'static>(&mut self) -> Option<T> {
422 self.resources.try_take::<T>()
423 }
424
425 pub fn apply_commands(&mut self) {
434 let commands = self.commands.take();
437 for cmd in commands {
438 cmd(self);
439 }
440 }
441
442 pub fn command_buffer_mut(&mut self) -> &mut CommandBuffer {
447 &mut self.commands
448 }
449
450 pub fn add_event<T: Send + 'static>(&mut self) {
466 if self.registered_events.insert(TypeId::of::<Events<T>>()) {
467 self.resources.insert(Events::<T>::new());
469 self.event_updaters.push(Box::new(|world: &mut World| {
470 world.resources.get_mut::<Events<T>>().update();
471 }));
472 } else if !self.resources.contains::<Events<T>>() {
473 self.resources.insert(Events::<T>::new());
476 }
477 }
478
479 pub fn flush_render_events(&self) {
493 if let Some(registry) = self.try_resource::<crate::render_event::RenderEventRegistry>() {
494 registry.accumulate(self);
495 }
496 }
497
498 pub fn update_events(&mut self) {
499 let mut updaters = std::mem::take(&mut self.event_updaters);
510 for updater in &updaters {
511 updater(self);
512 }
513 std::mem::swap(&mut self.event_updaters, &mut updaters);
515 self.event_swap_epoch += 1;
516 }
517
518 pub fn event_swap_epoch(&self) -> u64 {
521 self.event_swap_epoch
522 }
523
524 pub fn add_deadline_type<T: Send + 'static>(&mut self) {
535 if self.try_resource::<Deadlines<T>>().is_none() {
536 self.insert_resource(Deadlines::<T>::new());
537 }
538 self.add_event::<T>();
540 if self
542 .registered_deadlines
543 .insert(TypeId::of::<Deadlines<T>>())
544 {
545 self.deadline_drainers
546 .push(Box::new(|world: &mut World, now: Timestamp| {
547 world.drain_deadlines::<T>(now);
548 }));
549 }
550 }
551
552 pub fn schedule_deadline<T: Send + 'static>(
561 &mut self,
562 deadline: Timestamp,
563 event: T,
564 ) -> DeadlineId {
565 self.resource_mut::<Deadlines<T>>()
566 .schedule(deadline, event)
567 }
568
569 pub fn cancel_deadline<T: Send + 'static>(&mut self, id: DeadlineId) -> bool {
577 self.resource_mut::<Deadlines<T>>().cancel(id)
578 }
579
580 pub fn drain_deadlines<T: Send + 'static>(&mut self, now: Timestamp) {
591 let fired = self.resource_mut::<Deadlines<T>>().drain_overdue(now);
592 let events = self.resource_mut::<Events<T>>();
593 for event in fired {
594 events.send(event);
595 }
596 }
597
598 pub fn drain_all_deadlines(&mut self) {
611 let now = match self.resources.try_get::<Box<dyn Clock>>() {
613 Some(clock) => clock.now(),
614 None => return,
615 };
616
617 let mut drainers = std::mem::take(&mut self.deadline_drainers);
620 for drainer in &drainers {
621 drainer(self, now);
622 }
623 std::mem::swap(&mut self.deadline_drainers, &mut drainers);
624 }
625
626 pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
632 self.one::<&T>(entity)
633 }
634
635 pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<Mut<'_, T>> {
640 self.one_mut::<&mut T>(entity)
641 }
642
643 pub fn one<Q: QuerySpec>(&self, entity: Entity) -> Option<Q::Item<'_>> {
645 let loc = self.meta.get_location(entity)?;
646 let arch = self.archetypes.get(loc.archetype_id);
647 if !Q::matches(arch.layout()) {
648 return None;
649 }
650 let state = Q::init_state(arch)?;
651 Some(Q::fetch(&state, loc.row as usize))
652 }
653
654 pub fn one_mut<Q: QuerySpecMut>(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
656 let loc = self.meta.get_location(entity)?;
657 let tick = self.change_tick;
658 let arch = self.archetypes.get_mut(loc.archetype_id);
659 if !Q::matches(arch.layout()) {
660 return None;
661 }
662 let mut state = Q::init_state(arch, tick)?;
663 let row = loc.row as usize;
664 let item = unsafe { Q::fetch(&mut state, row) };
669 Some(item)
670 }
671
672 pub fn insert<C: Component>(&mut self, entity: Entity, value: C) {
687 let Some(loc) = self.meta.get_location(entity) else {
688 return; };
690
691 let src_arch_id = loc.archetype_id;
692 let row = loc.row as usize;
693
694 if self
696 .archetypes
697 .get(src_arch_id)
698 .layout()
699 .contains(TypeId::of::<C>())
700 {
701 let tick = self.change_tick;
702 let arch = self.archetypes.get_mut(src_arch_id);
703 if let Some(col) = arch.column_mut::<C>() {
704 if let Some(slot) = col.get_mut(row) {
705 *slot = value;
706 }
707 col.set_changed_tick(row, tick);
708 }
709 return;
710 }
711
712 self.archetypes.register_column::<C>();
714
715 let new_layout = self
717 .archetypes
718 .get(src_arch_id)
719 .layout()
720 .with_added(TypeId::of::<C>());
721 let dst_arch_id = self.archetypes.get_or_create(new_layout);
722
723 let src_type_ids: Vec<TypeId> = self.archetypes.get(src_arch_id).layout().iter().collect();
725
726 let tick = self.change_tick;
727
728 let (src_arch, dst_arch) = self.archetypes.get_two_mut(src_arch_id, dst_arch_id);
731 for &tid in &src_type_ids {
732 let src_col = src_arch.column_raw_mut(tid).unwrap();
733 let dst_col = dst_arch.column_raw_mut(tid).unwrap();
734 src_col.move_to(row, dst_col);
735 }
736
737 dst_arch.column_mut::<C>().unwrap().push(value);
739
740 let (_removed, moved) = src_arch.swap_remove_entity_entry(row);
742
743 let new_row = dst_arch.push_entity(entity);
745
746 dst_arch.stamp_column_ticks(TypeId::of::<C>(), new_row, tick, tick);
748
749 self.meta.set_location(
751 entity,
752 EntityLocation {
753 archetype_id: dst_arch_id,
754 row: new_row,
755 },
756 );
757 if let Some(moved_entity) = moved {
758 self.meta.set_location(
759 moved_entity,
760 EntityLocation {
761 archetype_id: src_arch_id,
762 row: loc.row,
763 },
764 );
765 }
766 }
767
768 pub fn remove<C: Component>(&mut self, entity: Entity) {
772 let Some(loc) = self.meta.get_location(entity) else {
773 return; };
775
776 let src_arch_id = loc.archetype_id;
777 let row = loc.row as usize;
778
779 if !self
781 .archetypes
782 .get(src_arch_id)
783 .layout()
784 .contains(TypeId::of::<C>())
785 {
786 return;
787 }
788
789 let new_layout = self
791 .archetypes
792 .get(src_arch_id)
793 .layout()
794 .with_removed(TypeId::of::<C>());
795 let dst_arch_id = self.archetypes.get_or_create(new_layout);
796
797 let src_type_ids: Vec<TypeId> = self.archetypes.get(src_arch_id).layout().iter().collect();
799
800 let c_type_id = TypeId::of::<C>();
801
802 let (src_arch, dst_arch) = self.archetypes.get_two_mut(src_arch_id, dst_arch_id);
804 for &tid in &src_type_ids {
805 let src_col = src_arch.column_raw_mut(tid).unwrap();
806 if tid == c_type_id {
807 src_col.swap_remove_and_drop(row);
809 } else {
810 let dst_col = dst_arch.column_raw_mut(tid).unwrap();
812 src_col.move_to(row, dst_col);
813 }
814 }
815
816 let (_removed, moved) = src_arch.swap_remove_entity_entry(row);
818
819 let new_row = dst_arch.push_entity(entity);
821
822 self.meta.set_location(
824 entity,
825 EntityLocation {
826 archetype_id: dst_arch_id,
827 row: new_row,
828 },
829 );
830 if let Some(moved_entity) = moved {
831 self.meta.set_location(
832 moved_entity,
833 EntityLocation {
834 archetype_id: src_arch_id,
835 row: loc.row,
836 },
837 );
838 }
839
840 self.component_removals
841 .push((entity, c_type_id, self.change_tick));
842 }
843
844 pub fn component_removals_since<C: Component>(
851 &self,
852 since_tick: u64,
853 ) -> impl Iterator<Item = Entity> + '_ {
854 let tid = TypeId::of::<C>();
855 self.component_removals
856 .iter()
857 .filter(move |(_, t, tick)| *t == tid && *tick > since_tick)
858 .map(|(e, _, _)| *e)
859 }
860
861 pub fn query<Q: QuerySpec>(&self) -> QueryIter<'_, Q> {
867 QueryIter::new(&self.archetypes)
868 }
869
870 pub fn query_filtered<Q: QuerySpec, F: QueryFilter>(&self) -> QueryIter<'_, Q, F> {
872 QueryIter::new(&self.archetypes)
873 }
874
875 pub fn query_mut<Q: QuerySpecMut>(&mut self) -> QueryIterMut<'_, Q> {
877 let tick = self.change_tick;
878 QueryIterMut::new(&mut self.archetypes, tick)
879 }
880
881 pub fn query_filtered_mut<Q: QuerySpecMut, F: QueryFilter>(
883 &mut self,
884 ) -> QueryIterMut<'_, Q, F> {
885 let tick = self.change_tick;
886 QueryIterMut::new(&mut self.archetypes, tick)
887 }
888
889 pub fn query2<A: Component, B: Component>(&self) -> Query2Iter<'_, A, B> {
891 self.query::<(&A, &B)>()
892 }
893
894 pub fn query2_mut<A: Component, B: Component>(&mut self) -> Query2MutIter<'_, A, B> {
896 assert_ne!(
897 TypeId::of::<A>(),
898 TypeId::of::<B>(),
899 "cannot borrow the same column mutably twice"
900 );
901 self.query_mut::<(&mut A, &mut B)>()
902 }
903
904 pub fn query3<A: Component, B: Component, C: Component>(&self) -> Query3Iter<'_, A, B, C> {
906 self.query::<(&A, &B, &C)>()
907 }
908
909 pub fn query3_mut<A: Component, B: Component, C: Component>(
911 &mut self,
912 ) -> Query3MutIter<'_, A, B, C> {
913 assert_ne!(
914 TypeId::of::<A>(),
915 TypeId::of::<B>(),
916 "cannot borrow the same column mutably twice"
917 );
918 assert_ne!(
919 TypeId::of::<A>(),
920 TypeId::of::<C>(),
921 "cannot borrow the same column mutably twice"
922 );
923 assert_ne!(
924 TypeId::of::<B>(),
925 TypeId::of::<C>(),
926 "cannot borrow the same column mutably twice"
927 );
928 self.query_mut::<(&mut A, &mut B, &mut C)>()
929 }
930
931 pub fn query_changed<T: Component>(&self, since_tick: u64) -> ChangedIter<'_, T> {
937 ChangedIter::new(&self.archetypes, since_tick)
938 }
939
940 pub fn query_added<T: Component>(&self, since_tick: u64) -> AddedIter<'_, T> {
942 AddedIter::new(&self.archetypes, since_tick)
943 }
944
945 pub fn entity_count(&self) -> usize {
951 self.meta.alive_entities().count()
952 }
953
954 pub fn archetypes(&self) -> &ArchetypeStore {
956 &self.archetypes
957 }
958
959 pub fn entity_location(&self, entity: Entity) -> Option<EntityLocation> {
961 self.meta.get_location(entity)
962 }
963}
964
965impl Default for World {
966 fn default() -> Self {
967 Self::new()
968 }
969}
970
971#[cfg(test)]
976mod tests {
977 use super::*;
978
979 #[derive(Debug, Clone, PartialEq)]
980 struct Pos {
981 x: f32,
982 y: f32,
983 }
984 impl Component for Pos {}
985
986 #[derive(Debug, Clone, PartialEq)]
987 struct Vel {
988 x: f32,
989 y: f32,
990 }
991 impl Component for Vel {}
992
993 #[derive(Debug, Clone)]
994 #[allow(dead_code)]
995 struct Health(i32);
996 impl Component for Health {}
997
998 #[test]
1001 fn world_is_send() {
1002 fn assert_send<T: Send>() {}
1003 assert_send::<World>();
1004 }
1005
1006 #[test]
1007 fn spawn_and_get() {
1008 let mut world = World::new();
1009 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1010 assert!(world.is_alive(e));
1011 let pos = world.get::<Pos>(e).unwrap();
1012 assert_eq!(pos.x, 1.0);
1013 assert_eq!(pos.y, 2.0);
1014 }
1015
1016 #[test]
1017 fn spawn_multi_component() {
1018 let mut world = World::new();
1019 let e = world.spawn((Pos { x: 0.0, y: 0.0 }, Vel { x: 1.0, y: 2.0 }));
1020 assert!(world.get::<Pos>(e).is_some());
1021 assert!(world.get::<Vel>(e).is_some());
1022 }
1023
1024 #[test]
1025 fn despawn_removes_entity_and_components() {
1026 let mut world = World::new();
1027 let e = world.spawn((Pos { x: 0.0, y: 0.0 }, Health(100)));
1028 assert!(world.despawn(e));
1029 assert!(!world.is_alive(e));
1030 assert!(world.get::<Pos>(e).is_none());
1031 assert!(world.get::<Health>(e).is_none());
1032 }
1033
1034 #[test]
1035 fn query_iterates_matching_entities() {
1036 let mut world = World::new();
1037 world.spawn((Pos { x: 1.0, y: 0.0 },));
1038 world.spawn((Pos { x: 2.0, y: 0.0 }, Vel { x: 0.0, y: 0.0 }));
1039 world.spawn((Vel { x: 3.0, y: 0.0 },)); let positions: Vec<f32> = world.query::<&Pos>().map(|(_, p)| p.x).collect();
1042 assert_eq!(positions.len(), 2);
1043 assert!(positions.contains(&1.0));
1044 assert!(positions.contains(&2.0));
1045 }
1046
1047 #[test]
1048 fn query_mut_allows_modification() {
1049 let mut world = World::new();
1050 world.spawn((Pos { x: 0.0, y: 0.0 },));
1051 world.spawn((Pos { x: 10.0, y: 10.0 },));
1052
1053 for (_, mut pos) in world.query_mut::<&mut Pos>() {
1054 pos.x += 1.0;
1055 }
1056
1057 let xs: Vec<f32> = world.query::<&Pos>().map(|(_, p)| p.x).collect();
1058 assert!(xs.contains(&1.0));
1059 assert!(xs.contains(&11.0));
1060 }
1061
1062 #[test]
1063 fn resources() {
1064 let mut world = World::new();
1065
1066 struct DeltaTime(f64);
1067
1068 world.insert_resource(DeltaTime(0.016));
1069 assert_eq!(world.resource::<DeltaTime>().0, 0.016);
1070
1071 world.resource_mut::<DeltaTime>().0 = 0.032;
1072 assert_eq!(world.resource::<DeltaTime>().0, 0.032);
1073 }
1074
1075 #[test]
1076 fn entity_count() {
1077 let mut world = World::new();
1078 assert_eq!(world.entity_count(), 0);
1079 let e1 = world.spawn((Pos { x: 0.0, y: 0.0 },));
1080 let _e2 = world.spawn((Pos { x: 0.0, y: 0.0 },));
1081 assert_eq!(world.entity_count(), 2);
1082 world.despawn(e1);
1083 assert_eq!(world.entity_count(), 1);
1084 }
1085
1086 #[test]
1087 fn query2_returns_entities_with_both_components() {
1088 let mut world = World::new();
1089 world.spawn((Pos { x: 1.0, y: 0.0 },));
1090 world.spawn((Pos { x: 2.0, y: 0.0 }, Vel { x: 5.0, y: 0.0 }));
1091 world.spawn((Vel { x: 3.0, y: 0.0 },));
1092
1093 let results: Vec<_> = world.query::<(&Pos, &Vel)>().collect();
1094 assert_eq!(results.len(), 1);
1095 assert_eq!(results[0].1.0.x, 2.0);
1096 assert_eq!(results[0].1.1.x, 5.0);
1097 }
1098
1099 #[test]
1100 fn query2_mut_mutates_both_components() {
1101 let mut world = World::new();
1102 let e1 = world.spawn((Pos { x: 1.0, y: 1.0 }, Vel { x: 10.0, y: 10.0 }));
1103 let e2 = world.spawn((Pos { x: 2.0, y: 2.0 }, Vel { x: 20.0, y: 20.0 }));
1104 let e3 = world.spawn((Pos { x: 3.0, y: 3.0 }, Vel { x: 30.0, y: 30.0 }));
1105
1106 for (_, (mut pos, mut vel)) in world.query_mut::<(&mut Pos, &mut Vel)>() {
1107 pos.x += 100.0;
1108 vel.y += 200.0;
1109 }
1110
1111 assert_eq!(world.get::<Pos>(e1).unwrap().x, 101.0);
1112 assert_eq!(world.get::<Vel>(e1).unwrap().y, 210.0);
1113 assert_eq!(world.get::<Pos>(e2).unwrap().x, 102.0);
1114 assert_eq!(world.get::<Vel>(e2).unwrap().y, 220.0);
1115 assert_eq!(world.get::<Pos>(e3).unwrap().x, 103.0);
1116 assert_eq!(world.get::<Vel>(e3).unwrap().y, 230.0);
1117 }
1118
1119 #[test]
1120 fn query2_mut_skips_entities_missing_one_component() {
1121 let mut world = World::new();
1122 let e1 = world.spawn((Pos { x: 5.0, y: 5.0 },));
1123 let e2 = world.spawn((Pos { x: 7.0, y: 7.0 }, Vel { x: 9.0, y: 9.0 }));
1124 let e3 = world.spawn((Vel { x: 11.0, y: 11.0 },));
1125
1126 let results: Vec<_> = world.query_mut::<(&mut Pos, &mut Vel)>().collect();
1127 assert_eq!(results.len(), 1);
1128
1129 let (entity, (pos, vel)) = &results[0];
1130 assert_eq!(*entity, e2);
1131 assert_eq!(pos.x, 7.0);
1132 assert_eq!(vel.x, 9.0);
1133
1134 assert_eq!(world.get::<Pos>(e1).unwrap().x, 5.0);
1136 assert_eq!(world.get::<Vel>(e3).unwrap().x, 11.0);
1138 }
1139
1140 #[test]
1141 #[should_panic(expected = "cannot borrow the same column mutably twice")]
1142 fn query2_mut_same_type_panics() {
1143 let mut world = World::new();
1144 world.spawn((Pos { x: 0.0, y: 0.0 },));
1145 let _ = world.query_mut::<(&mut Pos, &mut Pos)>().next();
1146 }
1147
1148 #[test]
1149 fn query_filtered_with_and_without() {
1150 let mut world = World::new();
1151 let e1 = world.spawn((Pos { x: 1.0, y: 0.0 }, Vel { x: 2.0, y: 0.0 }));
1152 let _e2 = world.spawn((Pos { x: 3.0, y: 0.0 },));
1153 let _e3 = world.spawn((Pos { x: 4.0, y: 0.0 }, Health(100)));
1154
1155 let results: Vec<_> = world
1156 .query_filtered::<&Pos, (crate::query::With<Vel>, crate::query::Without<Health>)>()
1157 .collect();
1158 assert_eq!(results.len(), 1);
1159 assert_eq!(results[0].0, e1);
1160 assert_eq!(results[0].1.x, 1.0);
1161 }
1162
1163 #[test]
1164 fn one_and_one_mut_fetch_single_entity() {
1165 let mut world = World::new();
1166 let e = world.spawn((Pos { x: 1.0, y: 2.0 }, Vel { x: 3.0, y: 4.0 }));
1167
1168 let (pos, vel) = world.one::<(&Pos, &Vel)>(e).unwrap();
1169 assert_eq!(pos.x, 1.0);
1170 assert_eq!(vel.x, 3.0);
1171
1172 let (mut pos, mut vel) = world.one_mut::<(&mut Pos, &mut Vel)>(e).unwrap();
1173 pos.x = 10.0;
1174 vel.y = 20.0;
1175
1176 assert_eq!(world.get::<Pos>(e).unwrap().x, 10.0);
1177 assert_eq!(world.get::<Vel>(e).unwrap().y, 20.0);
1178 }
1179
1180 #[test]
1183 fn insert_adds_component_to_entity() {
1184 let mut world = World::new();
1185 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1186 assert!(world.get::<Vel>(e).is_none());
1187
1188 world.insert(e, Vel { x: 3.0, y: 4.0 });
1189
1190 assert_eq!(world.get::<Vel>(e).unwrap().x, 3.0);
1191 assert_eq!(world.get::<Pos>(e).unwrap().x, 1.0);
1193 }
1194
1195 #[test]
1196 fn insert_overwrites_existing_component() {
1197 let mut world = World::new();
1198 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1199 world.insert(e, Pos { x: 99.0, y: 99.0 });
1200 assert_eq!(world.get::<Pos>(e).unwrap().x, 99.0);
1201 }
1202
1203 #[test]
1204 fn insert_dead_entity_is_noop() {
1205 let mut world = World::new();
1206 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1207 world.despawn(e);
1208 world.insert(e, Vel { x: 1.0, y: 1.0 }); }
1210
1211 #[test]
1212 fn insert_preserves_other_entities() {
1213 let mut world = World::new();
1214 let e1 = world.spawn((Pos { x: 1.0, y: 1.0 },));
1215 let e2 = world.spawn((Pos { x: 2.0, y: 2.0 },));
1216
1217 world.insert(e1, Vel { x: 10.0, y: 10.0 });
1218
1219 assert_eq!(world.get::<Pos>(e1).unwrap().x, 1.0);
1221 assert_eq!(world.get::<Vel>(e1).unwrap().x, 10.0);
1222 assert_eq!(world.get::<Pos>(e2).unwrap().x, 2.0);
1223 assert!(world.get::<Vel>(e2).is_none());
1224 }
1225
1226 #[test]
1227 fn remove_removes_component_from_entity() {
1228 let mut world = World::new();
1229 let e = world.spawn((Pos { x: 1.0, y: 2.0 }, Vel { x: 3.0, y: 4.0 }));
1230 world.remove::<Vel>(e);
1231
1232 assert!(world.get::<Vel>(e).is_none());
1233 assert_eq!(world.get::<Pos>(e).unwrap().x, 1.0);
1235 }
1236
1237 #[test]
1238 fn remove_absent_component_is_noop() {
1239 let mut world = World::new();
1240 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1241 world.remove::<Vel>(e); assert_eq!(world.get::<Pos>(e).unwrap().x, 1.0);
1243 }
1244
1245 #[test]
1246 fn remove_dead_entity_is_noop() {
1247 let mut world = World::new();
1248 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1249 world.despawn(e);
1250 world.remove::<Pos>(e); }
1252
1253 #[test]
1254 fn remove_preserves_other_entities() {
1255 let mut world = World::new();
1256 let e1 = world.spawn((Pos { x: 1.0, y: 1.0 }, Vel { x: 10.0, y: 10.0 }));
1257 let e2 = world.spawn((Pos { x: 2.0, y: 2.0 }, Vel { x: 20.0, y: 20.0 }));
1258
1259 world.remove::<Vel>(e1);
1260
1261 assert!(world.get::<Vel>(e1).is_none());
1262 assert_eq!(world.get::<Pos>(e1).unwrap().x, 1.0);
1263 assert_eq!(world.get::<Pos>(e2).unwrap().x, 2.0);
1265 assert_eq!(world.get::<Vel>(e2).unwrap().x, 20.0);
1266 }
1267
1268 #[test]
1269 fn component_removals_since_records_successful_remove() {
1270 let mut world = World::new();
1271 let e = world.spawn((Pos { x: 1.0, y: 0.0 }, Vel { x: 2.0, y: 0.0 }));
1272 let since = world.change_tick();
1273 world.advance_tick();
1274
1275 world.remove::<Vel>(e);
1276
1277 let rem: Vec<_> = world.component_removals_since::<Vel>(since).collect();
1278 assert_eq!(rem, vec![e]);
1279 assert!(
1280 world
1281 .component_removals_since::<Vel>(world.change_tick())
1282 .next()
1283 .is_none()
1284 );
1285 }
1286
1287 #[test]
1288 fn component_removals_since_ignores_noop_remove() {
1289 let mut world = World::new();
1290 let e = world.spawn((Pos { x: 1.0, y: 0.0 },));
1291 let since = world.change_tick();
1292 world.advance_tick();
1293
1294 world.remove::<Vel>(e);
1295
1296 let rem: Vec<_> = world.component_removals_since::<Vel>(since).collect();
1297 assert!(rem.is_empty());
1298 }
1299
1300 #[test]
1301 fn insert_then_query_finds_migrated_entity() {
1302 let mut world = World::new();
1303 let e1 = world.spawn((Pos { x: 1.0, y: 0.0 },));
1304 let _e2 = world.spawn((Pos { x: 2.0, y: 0.0 }, Vel { x: 20.0, y: 0.0 }));
1305
1306 world.insert(e1, Vel { x: 10.0, y: 0.0 });
1308
1309 let results: Vec<_> = world.query::<(&Pos, &Vel)>().collect();
1311 assert_eq!(results.len(), 2);
1312 }
1313
1314 #[test]
1315 fn remove_last_component_moves_to_empty_archetype() {
1316 let mut world = World::new();
1317 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1318 world.remove::<Pos>(e);
1319 assert!(world.is_alive(e));
1320 assert!(world.get::<Pos>(e).is_none());
1321 assert_eq!(world.entity_count(), 1);
1323 }
1324
1325 #[test]
1326 fn despawn_after_migration_cleans_up() {
1327 let mut world = World::new();
1328 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1329 world.insert(e, Vel { x: 3.0, y: 4.0 });
1330 assert!(world.despawn(e));
1331 assert!(!world.is_alive(e));
1332 assert_eq!(world.entity_count(), 0);
1333 }
1334
1335 #[test]
1336 fn spawn_duplicate_component_types_panics_without_mutating_world() {
1337 let mut world = World::new();
1338
1339 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1340 world.spawn((Pos { x: 1.0, y: 2.0 }, Pos { x: 3.0, y: 4.0 }));
1341 }));
1342
1343 assert!(result.is_err());
1344 assert_eq!(world.entity_count(), 0);
1345 assert!(world.query::<&Pos>().next().is_none());
1346 }
1347
1348 #[test]
1351 fn change_tick_starts_at_one() {
1352 let world = World::new();
1353 assert_eq!(world.change_tick(), 1);
1354 }
1355
1356 #[test]
1357 fn advance_tick_increments() {
1358 let mut world = World::new();
1359 assert_eq!(world.change_tick(), 1);
1360 let t = world.advance_tick();
1361 assert_eq!(t, 2);
1362 assert_eq!(world.change_tick(), 2);
1363 world.advance_tick();
1364 assert_eq!(world.change_tick(), 3);
1365 }
1366
1367 #[test]
1368 fn unsafe_world_cell_reads_change_tick() {
1369 let mut world = World::new();
1370 world.advance_tick();
1371 let cell = unsafe { UnsafeWorldCell::new(&mut world as *mut World) };
1372 assert_eq!(unsafe { cell.change_tick() }, 2);
1373 }
1374
1375 #[test]
1378 fn spawn_stamps_added_and_changed_ticks() {
1379 let mut world = World::new();
1380 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1382 let loc = world.entity_location(e).unwrap();
1383 let arch = world.archetypes().get(loc.archetype_id);
1384 let col = arch.column::<Pos>().unwrap();
1385 assert_eq!(col.added_tick(loc.row as usize), 1);
1386 assert_eq!(col.changed_tick(loc.row as usize), 1);
1387 }
1388
1389 #[test]
1390 fn get_mut_stamps_changed_tick() {
1391 let mut world = World::new();
1392 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1393 world.advance_tick(); world.get_mut::<Pos>(e).unwrap().x = 99.0;
1395
1396 let loc = world.entity_location(e).unwrap();
1397 let arch = world.archetypes().get(loc.archetype_id);
1398 let col = arch.column::<Pos>().unwrap();
1399 assert_eq!(col.added_tick(loc.row as usize), 1); assert_eq!(col.changed_tick(loc.row as usize), 2); }
1402
1403 #[test]
1404 fn insert_overwrite_stamps_changed_tick() {
1405 let mut world = World::new();
1406 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1407 world.advance_tick(); world.insert(e, Pos { x: 99.0, y: 0.0 });
1409
1410 let loc = world.entity_location(e).unwrap();
1411 let arch = world.archetypes().get(loc.archetype_id);
1412 let col = arch.column::<Pos>().unwrap();
1413 assert_eq!(col.added_tick(loc.row as usize), 1);
1414 assert_eq!(col.changed_tick(loc.row as usize), 2);
1415 }
1416
1417 #[test]
1418 fn insert_migration_stamps_new_component_ticks() {
1419 let mut world = World::new();
1420 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1421 world.advance_tick(); world.insert(e, Vel { x: 3.0, y: 4.0 });
1423
1424 let loc = world.entity_location(e).unwrap();
1425 let arch = world.archetypes().get(loc.archetype_id);
1426
1427 let pos_col = arch.column::<Pos>().unwrap();
1429 assert_eq!(pos_col.added_tick(loc.row as usize), 1);
1430 assert_eq!(pos_col.changed_tick(loc.row as usize), 1);
1431
1432 let vel_col = arch.column::<Vel>().unwrap();
1434 assert_eq!(vel_col.added_tick(loc.row as usize), 2);
1435 assert_eq!(vel_col.changed_tick(loc.row as usize), 2);
1436 }
1437
1438 #[test]
1439 fn query_mut_stamps_changed_tick() {
1440 let mut world = World::new();
1441 world.spawn((Pos { x: 1.0, y: 2.0 },));
1442 world.advance_tick(); for (_, mut pos) in world.query_mut::<&mut Pos>() {
1444 pos.x = 99.0;
1445 }
1446
1447 for (e, _) in world.query::<&Pos>() {
1449 let loc = world.entity_location(e).unwrap();
1450 let arch = world.archetypes().get(loc.archetype_id);
1451 let col = arch.column::<Pos>().unwrap();
1452 assert_eq!(col.changed_tick(loc.row as usize), 2);
1453 }
1454 }
1455
1456 #[test]
1457 fn query_mut_read_only_does_not_stamp_tick() {
1458 let mut world = World::new();
1459 let e = world.spawn((Pos { x: 1.0, y: 2.0 },));
1460 world.advance_tick(); for (_, pos) in world.query_mut::<&mut Pos>() {
1464 let _read = pos.x; }
1466
1467 let loc = world.entity_location(e).unwrap();
1469 let arch = world.archetypes().get(loc.archetype_id);
1470 let col = arch.column::<Pos>().unwrap();
1471 assert_eq!(col.changed_tick(loc.row as usize), 1);
1472
1473 let changed: Vec<Entity> = world.query_changed::<Pos>(1).map(|(e, _)| e).collect();
1475 assert!(changed.is_empty());
1476 }
1477
1478 #[test]
1479 fn query_mut_selective_mutation_stamps_only_mutated() {
1480 let mut world = World::new();
1481 let e1 = world.spawn((Pos { x: 1.0, y: 0.0 },));
1482 let _e2 = world.spawn((Pos { x: 2.0, y: 0.0 },));
1483 world.advance_tick(); for (entity, mut pos) in world.query_mut::<&mut Pos>() {
1487 if entity == e1 {
1488 pos.x = 99.0; } else {
1490 let _read = pos.x; }
1492 }
1493
1494 let changed: Vec<Entity> = world.query_changed::<Pos>(1).map(|(e, _)| e).collect();
1495 assert_eq!(changed.len(), 1);
1496 assert_eq!(changed[0], e1);
1497 }
1498
1499 #[test]
1500 fn set_changed_stamps_for_interior_mutability() {
1501 use std::sync::atomic::{AtomicUsize, Ordering};
1502
1503 #[derive(Debug)]
1504 struct Counter(AtomicUsize);
1505 impl crate::Component for Counter {}
1506
1507 let mut world = World::new();
1508 let e = world.spawn((Counter(AtomicUsize::new(0)),));
1509 world.advance_tick(); for (_, mut counter) in world.query_mut::<&mut Counter>() {
1513 counter.0.fetch_add(1, Ordering::Relaxed); counter.set_changed(); }
1516
1517 let changed: Vec<Entity> = world.query_changed::<Counter>(1).map(|(e, _)| e).collect();
1519 assert_eq!(changed, vec![e]);
1520 }
1521
1522 #[test]
1523 fn interior_mutation_without_set_changed_is_invisible() {
1524 use std::sync::atomic::{AtomicUsize, Ordering};
1525
1526 #[derive(Debug)]
1527 struct Counter(AtomicUsize);
1528 impl crate::Component for Counter {}
1529
1530 let mut world = World::new();
1531 let _e = world.spawn((Counter(AtomicUsize::new(0)),));
1532 world.advance_tick(); for (_, counter) in world.query_mut::<&mut Counter>() {
1536 counter.0.fetch_add(1, Ordering::Relaxed);
1537 }
1539
1540 let changed: Vec<Entity> = world.query_changed::<Counter>(1).map(|(e, _)| e).collect();
1541 assert!(
1542 changed.is_empty(),
1543 "interior mutation without set_changed should be invisible"
1544 );
1545 }
1546
1547 #[test]
1550 fn query_changed_returns_mutated_entities() {
1551 let mut world = World::new();
1552 let e1 = world.spawn((Pos { x: 1.0, y: 0.0 },));
1553 let e2 = world.spawn((Pos { x: 2.0, y: 0.0 },));
1554 let _e3 = world.spawn((Pos { x: 3.0, y: 0.0 },));
1555
1556 let since = world.change_tick(); world.advance_tick(); world.get_mut::<Pos>(e1).unwrap().x = 10.0;
1561 world.get_mut::<Pos>(e2).unwrap().x = 20.0;
1562
1563 let changed: Vec<Entity> = world.query_changed::<Pos>(since).map(|(e, _)| e).collect();
1564 assert_eq!(changed.len(), 2);
1565 assert!(changed.contains(&e1));
1566 assert!(changed.contains(&e2));
1567 }
1568
1569 #[test]
1570 fn query_changed_excludes_untouched() {
1571 let mut world = World::new();
1572 world.spawn((Pos { x: 1.0, y: 0.0 },));
1573
1574 let since = world.change_tick();
1575 world.advance_tick();
1576 let changed: Vec<Entity> = world.query_changed::<Pos>(since).map(|(e, _)| e).collect();
1579 assert!(changed.is_empty());
1580 }
1581
1582 #[test]
1583 fn query_added_returns_newly_spawned() {
1584 let mut world = World::new();
1585 let _old = world.spawn((Pos { x: 1.0, y: 0.0 },));
1586
1587 let since = world.change_tick(); world.advance_tick(); let new = world.spawn((Pos { x: 2.0, y: 0.0 },));
1591
1592 let added: Vec<Entity> = world.query_added::<Pos>(since).map(|(e, _)| e).collect();
1593 assert_eq!(added, vec![new]);
1594 }
1595
1596 #[test]
1597 fn query_added_returns_component_inserted_via_migration() {
1598 let mut world = World::new();
1599 let e = world.spawn((Pos { x: 1.0, y: 0.0 },));
1600
1601 let since = world.change_tick();
1602 world.advance_tick();
1603
1604 world.insert(e, Vel { x: 3.0, y: 4.0 });
1605
1606 let added: Vec<Entity> = world.query_added::<Vel>(since).map(|(e, _)| e).collect();
1608 assert_eq!(added, vec![e]);
1609
1610 let added_pos: Vec<Entity> = world.query_added::<Pos>(since).map(|(e, _)| e).collect();
1612 assert!(added_pos.is_empty());
1613 }
1614
1615 #[test]
1616 fn query_changed_across_multiple_archetypes() {
1617 let mut world = World::new();
1618 let e1 = world.spawn((Pos { x: 1.0, y: 0.0 },));
1620 let e2 = world.spawn((Pos { x: 2.0, y: 0.0 }, Vel { x: 0.0, y: 0.0 }));
1622
1623 let since = world.change_tick();
1624 world.advance_tick();
1625
1626 world.get_mut::<Pos>(e1).unwrap().x = 10.0;
1628 world.get_mut::<Pos>(e2).unwrap().x = 20.0;
1629
1630 let changed: Vec<Entity> = world.query_changed::<Pos>(since).map(|(e, _)| e).collect();
1631 assert_eq!(changed.len(), 2);
1632 assert!(changed.contains(&e1));
1633 assert!(changed.contains(&e2));
1634 }
1635}