1use std::alloc::Layout;
4use std::any::{Any, TypeId};
5use std::collections::HashMap;
6
7use crate::bundle::{Bundle, Component};
8use crate::commands::Commands;
9use crate::entity::{Entities, Entity, Location};
10use crate::query::{Query, QueryData};
11use crate::storage::{Archetype, ComponentId, ComponentInfo, DropFn, TypeMap, drop_ptr};
12
13struct BundleInfo {
14 archetype: usize,
15 columns: Box<[usize]>,
17}
18
19pub struct Chunk<'a> {
22 pub entities: &'a [Entity],
24 pub columns: &'a [*mut u8],
26}
27
28impl Chunk<'_> {
29 #[must_use]
31 pub fn len(&self) -> usize {
32 self.entities.len()
33 }
34
35 #[must_use]
37 pub fn is_empty(&self) -> bool {
38 self.entities.is_empty()
39 }
40}
41
42pub struct World {
64 infos: Vec<ComponentInfo>,
65 by_type: TypeMap<ComponentId>,
66 by_name: HashMap<String, ComponentId>,
67 pub(crate) archetypes: Vec<Archetype>,
68 archetype_by_ids: HashMap<Box<[ComponentId]>, usize>,
69 pub(crate) entities: Entities,
70 bundles: TypeMap<BundleInfo>,
71 resources: TypeMap<Box<dyn Any + Send + Sync>>,
72 dynamic_resources: HashMap<String, RawValue>,
74 scratch_ids: Vec<ComponentId>,
75}
76
77struct RawValue {
80 ptr: std::ptr::NonNull<u8>,
81 layout: Layout,
82}
83
84unsafe impl Send for RawValue {}
87unsafe impl Sync for RawValue {}
88
89impl RawValue {
90 unsafe fn copy_of(layout: Layout, data: *const u8) -> Self {
95 let ptr = if layout.size() == 0 {
96 unsafe { std::ptr::NonNull::new_unchecked(std::ptr::without_provenance_mut(layout.align())) }
98 } else {
99 let p = unsafe { std::alloc::alloc(layout) };
101 std::ptr::NonNull::new(p).unwrap_or_else(|| std::alloc::handle_alloc_error(layout))
102 };
103 if layout.size() != 0 {
104 unsafe { std::ptr::copy_nonoverlapping(data, ptr.as_ptr(), layout.size()) };
106 }
107 RawValue { ptr, layout }
108 }
109}
110
111impl Drop for RawValue {
112 fn drop(&mut self) {
113 if self.layout.size() != 0 {
114 unsafe { std::alloc::dealloc(self.ptr.as_ptr(), self.layout) };
116 }
117 }
118}
119
120impl Default for World {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125
126impl World {
127 #[must_use]
129 pub fn new() -> Self {
130 let mut w = World {
131 infos: Vec::new(),
132 by_type: TypeMap::default(),
133 by_name: HashMap::new(),
134 archetypes: Vec::new(),
135 archetype_by_ids: HashMap::new(),
136 entities: Entities::default(),
137 bundles: TypeMap::default(),
138 resources: TypeMap::default(),
139 dynamic_resources: HashMap::new(),
140 scratch_ids: Vec::new(),
141 };
142 w.archetype_for(&[]); w
144 }
145
146 pub fn spawn<B: Bundle>(&mut self, bundle: B) -> Entity {
153 let a = self.bundle_archetype::<B>();
154 let e = self.entities.alloc();
155 self.spawn_in::<B>(a, bundle, e)
156 }
157
158 pub fn spawn_batch<B: Bundle>(&mut self, bundles: impl IntoIterator<Item = B>) {
160 let iter = bundles.into_iter();
161 let a = self.bundle_archetype::<B>();
162 self.archetypes[a].reserve(iter.size_hint().0);
163 for b in iter {
164 let e = self.entities.alloc();
165 self.spawn_in::<B>(a, b, e);
166 }
167 }
168
169 pub fn spawn_at<B: Bundle>(&mut self, e: Entity, bundle: B) -> bool {
186 if !self.entities.alloc_at(e) {
187 return false;
188 }
189 let a = self.bundle_archetype::<B>();
190 self.spawn_in::<B>(a, bundle, e);
191 true
192 }
193
194 pub fn allocated_bytes(&self) -> usize {
208 self.archetypes.iter().map(Archetype::allocated_bytes).sum()
209 }
210
211 pub fn clear(&mut self) {
222 let all: Vec<Entity> = self
223 .archetypes
224 .iter()
225 .flat_map(|a| a.entities.iter().copied())
226 .collect();
227 for e in all {
228 self.despawn(e);
229 }
230 }
231
232 pub fn reset(&mut self) {
248 self.clear();
249 self.entities = Default::default();
250 }
251
252 #[inline]
253 fn spawn_in<B: Bundle>(&mut self, a: usize, bundle: B, e: Entity) -> Entity {
254 let cols = &self.bundles[&TypeId::of::<B>()].columns;
255 let arch = &mut self.archetypes[a];
256 arch.reserve(1);
257 let row = arch.len();
258 unsafe {
259 bundle.write(&mut |i, src| {
260 let c = &arch.columns[cols[i]];
261 std::ptr::copy_nonoverlapping(src, c.ptr(row), c.size());
262 });
263 }
264 arch.entities.push(e);
265 self.entities.set(
266 e,
267 Location {
268 archetype: a as u32,
269 row: row as u32,
270 },
271 );
272 e
273 }
274
275 pub fn despawn(&mut self, e: Entity) -> bool {
278 let Some(loc) = self.entities.get(e) else { return false };
279 self.entities.free(e);
281 let moved = unsafe { self.archetypes[loc.archetype as usize].swap_remove_drop(loc.row as usize) };
282 if let Some(moved) = moved {
283 self.entities.set_row(moved, loc.row as usize);
284 }
285 true
286 }
287
288 #[must_use]
290 pub fn is_alive(&self, e: Entity) -> bool {
291 self.entities.get(e).is_some()
292 }
293
294 #[must_use]
296 pub fn len(&self) -> usize {
297 self.entities.len()
298 }
299
300 #[must_use]
302 pub fn is_empty(&self) -> bool {
303 self.len() == 0
304 }
305
306 #[must_use]
310 pub fn get<T: Component>(&self, e: Entity) -> Option<&T> {
311 let ptr = self.get_dynamic(e, self.component_id::<T>()?)?;
312 Some(unsafe { &*ptr.cast::<T>() })
313 }
314
315 pub fn get_mut<T: Component>(&mut self, e: Entity) -> Option<&mut T> {
317 let ptr = self.get_dynamic(e, self.component_id::<T>()?)?;
318 Some(unsafe { &mut *ptr.cast::<T>() })
319 }
320
321 #[must_use]
323 pub fn has<T: Component>(&self, e: Entity) -> bool {
324 self.component_id::<T>()
325 .is_some_and(|id| self.get_dynamic(e, id).is_some())
326 }
327
328 pub fn insert<T: Component>(&mut self, e: Entity, value: T) -> bool {
331 let id = self.register::<T>();
332 let value = std::mem::ManuallyDrop::new(value);
333 let ok = unsafe { self.insert_dynamic(e, id, (&*value as *const T).cast()) };
334 if !ok {
335 drop(std::mem::ManuallyDrop::into_inner(value));
336 }
337 ok
338 }
339
340 pub fn remove<T: Component>(&mut self, e: Entity) -> Option<T> {
342 let id = self.component_id::<T>()?;
343 let loc = self.entities.get(e)?;
344 let arch = &self.archetypes[loc.archetype as usize];
345 let col = arch.column_index(id)?;
346 let value = unsafe { arch.columns[col].ptr(loc.row as usize).cast::<T>().read() };
347 self.move_without(e, loc, id);
348 Some(value)
349 }
350
351 pub fn query<Q: QueryData>(&mut self) -> Query<'_, Q> {
361 Query::new(self)
362 }
363
364 pub fn sort_by<T: Component>(&mut self, key: impl Fn(&T) -> u64 + Sync) {
385 let Some(id) = self.component_id::<T>() else { return };
386 let mut keyed: Vec<(u64, u32)> = Vec::new();
387 for a in 0..self.archetypes.len() {
388 let arch = &self.archetypes[a];
389 let Some(base) = arch.column_ptr(id) else { continue };
390 let len = arch.len();
391 if len < 2 {
392 continue;
393 }
394 let values = unsafe { std::slice::from_raw_parts(base as *const T, len) };
395 keyed.clear();
396 keyed.extend(values.iter().enumerate().map(|(row, v)| (key(v), row as u32)));
397 if keyed.windows(2).all(|w| w[0].0 <= w[1].0) {
398 continue; }
400 sort_keys(&mut keyed);
401 let perm: Vec<u32> = keyed.iter().map(|&(_, row)| row).collect();
402 let arch = &mut self.archetypes[a];
403 arch.permute(&perm);
404 for (row, &e) in arch.entities.iter().enumerate() {
405 self.entities.set_row(e, row);
406 }
407 }
408 }
409
410 pub fn insert_resource<R: Send + Sync + 'static>(&mut self, value: R) {
415 self.resources.insert(TypeId::of::<R>(), Box::new(value));
416 }
417
418 #[track_caller]
423 #[must_use]
424 pub fn resource<R: Send + Sync + 'static>(&self) -> &R {
425 self.get_resource().unwrap_or_else(|| missing_resource::<R>())
426 }
427
428 #[track_caller]
430 pub fn resource_mut<R: Send + Sync + 'static>(&mut self) -> &mut R {
431 self.get_resource_mut().unwrap_or_else(|| missing_resource::<R>())
432 }
433
434 #[must_use]
436 pub fn get_resource<R: Send + Sync + 'static>(&self) -> Option<&R> {
437 self.resources
438 .get(&TypeId::of::<R>())
439 .map(|r| r.downcast_ref().unwrap())
440 }
441
442 pub fn get_resource_mut<R: Send + Sync + 'static>(&mut self) -> Option<&mut R> {
444 self.resources
445 .get_mut(&TypeId::of::<R>())
446 .map(|r| r.downcast_mut().unwrap())
447 }
448
449 pub fn remove_resource<R: Send + Sync + 'static>(&mut self) -> Option<R> {
451 self.resources
452 .remove(&TypeId::of::<R>())
453 .map(|r| *r.downcast().unwrap())
454 }
455
456 #[track_caller]
479 pub unsafe fn insert_resource_dynamic(&mut self, name: &str, layout: Layout, value: *const u8) {
480 if let Some(old) = self.dynamic_resources.get(name) {
481 assert!(
482 old.layout == layout,
483 "insert_resource_dynamic: `{name}` exists with a different size or alignment"
484 );
485 }
486 let raw = unsafe { RawValue::copy_of(layout, value) };
488 self.dynamic_resources.insert(name.to_string(), raw);
489 }
490
491 #[must_use]
495 pub fn get_resource_dynamic(&self, name: &str) -> Option<*mut u8> {
496 self.dynamic_resources.get(name).map(|r| r.ptr.as_ptr())
497 }
498
499 #[must_use]
501 pub fn resource_layout_dynamic(&self, name: &str) -> Option<Layout> {
502 self.dynamic_resources.get(name).map(|r| r.layout)
503 }
504
505 pub fn remove_resource_dynamic(&mut self, name: &str) -> bool {
507 self.dynamic_resources.remove(name).is_some()
508 }
509
510 pub fn apply(&mut self, commands: &mut Commands) {
515 commands.apply(self);
516 }
517
518 pub fn register<T: Component>(&mut self) -> ComponentId {
522 if let Some(&id) = self.by_type.get(&TypeId::of::<T>()) {
523 return id;
524 }
525 let drop = std::mem::needs_drop::<T>().then_some(drop_ptr::<T> as DropFn);
526 let id = self.push_info(ComponentInfo {
527 name: std::any::type_name::<T>().into(),
528 layout: Layout::new::<T>(),
529 drop,
530 type_id: Some(TypeId::of::<T>()),
531 });
532 self.by_type.insert(TypeId::of::<T>(), id);
533 id
534 }
535
536 pub unsafe fn register_component(
549 &mut self,
550 name: &str,
551 size: usize,
552 align: usize,
553 drop: Option<DropFn>,
554 ) -> ComponentId {
555 let layout = Layout::from_size_align(size, align).expect("invalid component size/alignment");
556 if let Some(&id) = self.by_name.get(name) {
557 let info = &self.infos[id.index()];
558 assert!(
559 info.layout == layout && info.type_id.is_none(),
560 "component name `{name}` is already registered with a different layout"
561 );
562 return id;
563 }
564 self.push_info(ComponentInfo {
565 name: name.into(),
566 layout,
567 drop,
568 type_id: None,
569 })
570 }
571
572 fn push_info(&mut self, info: ComponentInfo) -> ComponentId {
573 let id = ComponentId(u32::try_from(self.infos.len()).expect("too many component types"));
574 self.by_name.entry(info.name.clone()).or_insert(id);
575 self.infos.push(info);
576 id
577 }
578
579 #[inline]
581 #[must_use]
582 pub fn component_id<T: Component>(&self) -> Option<ComponentId> {
583 self.by_type.get(&TypeId::of::<T>()).copied()
584 }
585
586 #[must_use]
588 pub fn component_by_name(&self, name: &str) -> Option<ComponentId> {
589 self.by_name.get(name).copied()
590 }
591
592 #[must_use]
602 pub fn component_at(&self, index: usize) -> Option<ComponentId> {
603 (index < self.infos.len()).then_some(ComponentId(index as u32))
604 }
605
606 #[must_use]
611 pub fn component_info(&self, id: ComponentId) -> &ComponentInfo {
612 &self.infos[id.index()]
613 }
614
615 #[must_use]
617 pub fn components(&self) -> &[ComponentInfo] {
618 &self.infos
619 }
620
621 #[must_use]
623 pub fn archetypes(&self) -> &[Archetype] {
624 &self.archetypes
625 }
626
627 #[must_use]
644 pub fn components_of(&self, e: Entity) -> Option<&[ComponentId]> {
645 let loc = self.entities.get(e)?;
646 Some(self.archetypes[loc.archetype as usize].component_ids())
647 }
648
649 #[must_use]
651 pub fn get_dynamic(&self, e: Entity, id: ComponentId) -> Option<*mut u8> {
652 let loc = self.entities.get(e)?;
653 let arch = &self.archetypes[loc.archetype as usize];
654 let col = arch.column_index(id)?;
655 Some(arch.columns[col].ptr(loc.row as usize))
656 }
657
658 pub unsafe fn spawn_dynamic(&mut self, components: &[(ComponentId, *const u8)]) -> Entity {
667 let a = self.dynamic_archetype(components, "spawn_dynamic");
668 let e = self.entities.alloc();
669 unsafe { self.write_dynamic(a, e, components) };
671 e
672 }
673
674 pub unsafe fn spawn_at_dynamic(&mut self, e: Entity, components: &[(ComponentId, *const u8)]) -> bool {
699 let a = self.dynamic_archetype(components, "spawn_at_dynamic");
700 if !self.entities.alloc_at(e) {
701 return false;
702 }
703 unsafe { self.write_dynamic(a, e, components) };
705 true
706 }
707
708 fn dynamic_archetype(&mut self, components: &[(ComponentId, *const u8)], caller: &str) -> usize {
710 let mut ids = std::mem::take(&mut self.scratch_ids);
711 ids.clear();
712 ids.extend(components.iter().map(|c| c.0));
713 ids.sort_unstable();
714 let unique = ids.windows(2).all(|w| w[0] != w[1]);
715 let a = if unique { Some(self.archetype_for(&ids)) } else { None };
716 self.scratch_ids = ids;
717 a.unwrap_or_else(|| panic!("{caller}: the same component was given twice"))
718 }
719
720 unsafe fn write_dynamic(&mut self, a: usize, e: Entity, components: &[(ComponentId, *const u8)]) {
726 let arch = &mut self.archetypes[a];
727 arch.reserve(1);
728 let row = arch.len();
729 for &(id, src) in components {
730 let c = &arch.columns[arch.column_index(id).unwrap()];
731 unsafe { std::ptr::copy_nonoverlapping(src, c.ptr(row), c.size()) };
734 }
735 arch.entities.push(e);
736 self.entities.set(
737 e,
738 Location {
739 archetype: a as u32,
740 row: row as u32,
741 },
742 );
743 }
744
745 pub unsafe fn insert_dynamic(&mut self, e: Entity, id: ComponentId, value: *const u8) -> bool {
752 let Some(loc) = self.entities.get(e) else { return false };
753 let src = loc.archetype as usize;
754 if let Some(col) = self.archetypes[src].column_index(id) {
755 let c = &self.archetypes[src].columns[col];
756 let dst = c.ptr(loc.row as usize);
757 unsafe {
758 if let Some(d) = c.drop_fn() {
759 d(dst);
760 }
761 std::ptr::copy_nonoverlapping(value, dst, c.size());
762 }
763 return true;
764 }
765 let dst = match self.archetypes[src].add_edges.get(&id) {
766 Some(&d) => d,
767 None => {
768 let mut ids = self.archetypes[src].ids.to_vec();
769 ids.push(id);
770 ids.sort_unstable();
771 let d = self.archetype_for(&ids);
772 self.archetypes[src].add_edges.insert(id, d);
773 self.archetypes[d].remove_edges.insert(id, src);
774 d
775 }
776 };
777 let row = self.move_row(e, loc, dst);
778 let arch = &self.archetypes[dst];
779 let c = &arch.columns[arch.column_index(id).unwrap()];
780 unsafe { std::ptr::copy_nonoverlapping(value, c.ptr(row), c.size()) };
781 true
782 }
783
784 pub fn remove_dynamic(&mut self, e: Entity, id: ComponentId) -> bool {
787 let Some(loc) = self.entities.get(e) else { return false };
788 let arch = &self.archetypes[loc.archetype as usize];
789 let Some(col) = arch.column_index(id) else { return false };
790 let c = &arch.columns[col];
791 let Some(drop) = c.drop_fn() else {
792 self.move_without(e, loc, id);
793 return true;
794 };
795 let ptr = c.ptr(loc.row as usize);
797 let mut tmp = TempValue::new(self.infos[id.index()].layout);
798 unsafe { std::ptr::copy_nonoverlapping(ptr, tmp.ptr(), c.size()) };
799 self.move_without(e, loc, id);
800 unsafe { drop(tmp.ptr()) };
801 true
802 }
803
804 pub fn for_each_chunk(&mut self, ids: &[ComponentId], mut f: impl FnMut(Chunk<'_>)) {
812 const MAX: usize = 32;
813 assert!(ids.len() <= MAX, "for_each_chunk: at most {MAX} components");
814 let mut ptrs = [std::ptr::null_mut(); MAX];
815 'arch: for arch in self.archetypes.iter() {
816 if arch.is_empty() {
817 continue;
818 }
819 for (i, &id) in ids.iter().enumerate() {
820 match arch.column_ptr(id) {
821 Some(p) => ptrs[i] = p,
822 None => continue 'arch,
823 }
824 }
825 f(Chunk {
826 entities: &arch.entities,
827 columns: &ptrs[..ids.len()],
828 });
829 }
830 }
831
832 fn archetype_for(&mut self, ids: &[ComponentId]) -> usize {
836 if let Some(&a) = self.archetype_by_ids.get(ids) {
837 return a;
838 }
839 let a = self.archetypes.len();
840 self.archetypes.push(Archetype::new(ids.into(), &self.infos));
841 self.archetype_by_ids.insert(ids.into(), a);
842 a
843 }
844
845 fn bundle_archetype<B: Bundle>(&mut self) -> usize {
846 if let Some(b) = self.bundles.get(&TypeId::of::<B>()) {
847 return b.archetype;
848 }
849 let mut ids = Vec::new();
850 B::component_ids(self, &mut ids);
851 let mut sorted = ids.clone();
852 sorted.sort_unstable();
853 sorted.dedup();
854 assert_eq!(
855 sorted.len(),
856 ids.len(),
857 "bundle `{}` has the same component twice",
858 std::any::type_name::<B>()
859 );
860 let a = self.archetype_for(&sorted);
861 let columns = ids
862 .iter()
863 .map(|&id| self.archetypes[a].column_index(id).unwrap())
864 .collect();
865 self.bundles
866 .insert(TypeId::of::<B>(), BundleInfo { archetype: a, columns });
867 a
868 }
869
870 fn move_without(&mut self, e: Entity, loc: Location, id: ComponentId) {
873 let src = loc.archetype as usize;
874 let dst = match self.archetypes[src].remove_edges.get(&id) {
875 Some(&d) => d,
876 None => {
877 let ids: Vec<_> = self.archetypes[src].ids.iter().copied().filter(|&c| c != id).collect();
878 let d = self.archetype_for(&ids);
879 self.archetypes[src].remove_edges.insert(id, d);
880 self.archetypes[d].add_edges.insert(id, src);
881 d
882 }
883 };
884 self.move_row(e, loc, dst);
885 }
886
887 fn move_row(&mut self, e: Entity, loc: Location, dst: usize) -> usize {
891 let src = loc.archetype as usize;
892 let row = loc.row as usize;
893 let (s, d) = two_mut(&mut self.archetypes, src, dst);
894 d.reserve(1);
895 let new_row = d.len();
896 let last = s.len() - 1;
897 for (i, col) in s.columns.iter_mut().enumerate() {
898 if let Some(j) = d.column_index(s.ids[i]) {
899 unsafe { std::ptr::copy_nonoverlapping(col.ptr(row), d.columns[j].ptr(new_row), col.size()) };
900 }
901 unsafe { col.swap_remove_forget(row, last) };
902 }
903 s.entities.swap_remove(row);
904 if row != last {
905 let moved = s.entities[row];
906 self.entities.set_row(moved, row);
907 }
908 d.entities.push(e);
909 self.entities.set(
910 e,
911 Location {
912 archetype: dst as u32,
913 row: new_row as u32,
914 },
915 );
916 new_row
917 }
918}
919
920fn sort_keys(keyed: &mut [(u64, u32)]) {
921 #[cfg(feature = "parallel")]
922 if keyed.len() > 50_000 {
923 use rayon::slice::ParallelSliceMut;
924 keyed.par_sort_unstable_by_key(|k| k.0);
925 return;
926 }
927 keyed.sort_unstable_by_key(|k| k.0);
928}
929
930#[cold]
931#[track_caller]
932fn missing_resource<R>() -> ! {
933 panic!(
934 "no resource of type `{0}`; add one first with `world.insert_resource(...)`",
935 std::any::type_name::<R>()
936 )
937}
938
939fn two_mut<T>(v: &mut [T], a: usize, b: usize) -> (&mut T, &mut T) {
940 assert_ne!(a, b);
941 if a < b {
942 let (l, r) = v.split_at_mut(b);
943 (&mut l[a], &mut r[0])
944 } else {
945 let (l, r) = v.split_at_mut(a);
946 (&mut r[0], &mut l[b])
947 }
948}
949
950struct TempValue {
952 ptr: *mut u8,
953 layout: Layout,
954}
955
956impl TempValue {
957 fn new(layout: Layout) -> Self {
958 let ptr = if layout.size() == 0 {
959 std::ptr::without_provenance_mut(layout.align())
960 } else {
961 let p = unsafe { std::alloc::alloc(layout) };
962 if p.is_null() {
963 std::alloc::handle_alloc_error(layout);
964 }
965 p
966 };
967 TempValue { ptr, layout }
968 }
969
970 fn ptr(&mut self) -> *mut u8 {
971 self.ptr
972 }
973}
974
975impl Drop for TempValue {
976 fn drop(&mut self) {
977 if self.layout.size() != 0 {
978 unsafe { std::alloc::dealloc(self.ptr, self.layout) }
979 }
980 }
981}