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