1pub use bevy_ecs_macros::Bundle;
6
7use crate::{
8 archetype::{
9 Archetype, ArchetypeAfterBundleInsert, ArchetypeId, Archetypes, BundleComponentStatus,
10 ComponentStatus, SpawnBundleStatus,
11 },
12 change_detection::MaybeLocation,
13 component::{
14 Component, ComponentId, Components, ComponentsRegistrator, RequiredComponentConstructor,
15 RequiredComponents, StorageType, Tick,
16 },
17 entity::{Entities, Entity, EntityLocation},
18 observer::Observers,
19 prelude::World,
20 query::DebugCheckedUnwrap,
21 relationship::RelationshipHookMode,
22 storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
23 world::{unsafe_world_cell::UnsafeWorldCell, EntityWorldMut, ON_ADD, ON_INSERT, ON_REPLACE},
24};
25use alloc::{boxed::Box, vec, vec::Vec};
26use bevy_platform::collections::{HashMap, HashSet};
27use bevy_ptr::{ConstNonNull, OwningPtr};
28use bevy_utils::TypeIdMap;
29use core::{any::TypeId, ptr::NonNull};
30use variadics_please::all_tuples;
31
32#[diagnostic::on_unimplemented(
147 message = "`{Self}` is not a `Bundle`",
148 label = "invalid `Bundle`",
149 note = "consider annotating `{Self}` with `#[derive(Component)]` or `#[derive(Bundle)]`"
150)]
151pub unsafe trait Bundle: DynamicBundle + Send + Sync + 'static {
152 #[doc(hidden)]
154 fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId));
155
156 fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>));
158
159 fn register_required_components(
161 _components: &mut ComponentsRegistrator,
162 _required_components: &mut RequiredComponents,
163 );
164}
165
166pub unsafe trait BundleFromComponents {
181 #[doc(hidden)]
188 unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
189 where
190 F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
192 Self: Sized;
193}
194
195pub trait DynamicBundle {
197 type Effect: BundleEffect;
199 #[doc(hidden)]
206 fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) -> Self::Effect;
207}
208
209pub trait BundleEffect {
218 fn apply(self, entity: &mut EntityWorldMut);
220}
221
222unsafe impl<C: Component> Bundle for C {
226 fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)) {
227 ids(components.register_component::<C>());
228 }
229
230 fn register_required_components(
231 components: &mut ComponentsRegistrator,
232 required_components: &mut RequiredComponents,
233 ) {
234 let component_id = components.register_component::<C>();
235 <C as Component>::register_required_components(
236 component_id,
237 components,
238 required_components,
239 0,
240 &mut Vec::new(),
241 );
242 }
243
244 fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)) {
245 ids(components.get_id(TypeId::of::<C>()));
246 }
247}
248
249unsafe impl<C: Component> BundleFromComponents for C {
252 unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
253 where
254 F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
256 Self: Sized,
257 {
258 let ptr = func(ctx);
259 unsafe { ptr.read() }
261 }
262}
263
264impl<C: Component> DynamicBundle for C {
265 type Effect = ();
266 #[inline]
267 fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) -> Self::Effect {
268 OwningPtr::make(self, |ptr| func(C::STORAGE_TYPE, ptr));
269 }
270}
271
272macro_rules! tuple_impl {
273 ($(#[$meta:meta])* $($name: ident),*) => {
274 #[expect(
275 clippy::allow_attributes,
276 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
277 )]
278 #[allow(
279 unused_mut,
280 unused_variables,
281 reason = "Zero-length tuples won't use any of the parameters."
282 )]
283 $(#[$meta])*
284 unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
291 fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)){
292 $(<$name as Bundle>::component_ids(components, ids);)*
293 }
294
295 fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)){
296 $(<$name as Bundle>::get_component_ids(components, ids);)*
297 }
298
299 fn register_required_components(
300 components: &mut ComponentsRegistrator,
301 required_components: &mut RequiredComponents,
302 ) {
303 $(<$name as Bundle>::register_required_components(components, required_components);)*
304 }
305 }
306
307 #[expect(
308 clippy::allow_attributes,
309 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
310 )]
311 #[allow(
312 unused_mut,
313 unused_variables,
314 reason = "Zero-length tuples won't use any of the parameters."
315 )]
316 $(#[$meta])*
317 unsafe impl<$($name: BundleFromComponents),*> BundleFromComponents for ($($name,)*) {
324 #[allow(
325 clippy::unused_unit,
326 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
327 )]
328 unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
329 where
330 F: FnMut(&mut T) -> OwningPtr<'_>
331 {
332 #[allow(
333 unused_unsafe,
334 reason = "Zero-length tuples will not run anything in the unsafe block. Additionally, rewriting this to move the () outside of the unsafe would require putting the safety comment inside the tuple, hurting readability of the code."
335 )]
336 unsafe { ($(<$name as BundleFromComponents>::from_components(ctx, func),)*) }
339 }
340 }
341
342 #[expect(
343 clippy::allow_attributes,
344 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
345 )]
346 #[allow(
347 unused_mut,
348 unused_variables,
349 reason = "Zero-length tuples won't use any of the parameters."
350 )]
351 $(#[$meta])*
352 impl<$($name: Bundle),*> DynamicBundle for ($($name,)*) {
353 type Effect = ($($name::Effect,)*);
354 #[allow(
355 clippy::unused_unit,
356 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
357 )]
358 #[inline(always)]
359 fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) -> Self::Effect {
360 #[allow(
361 non_snake_case,
362 reason = "The names of these variables are provided by the caller, not by us."
363 )]
364 let ($(mut $name,)*) = self;
365 ($(
366 $name.get_components(&mut *func),
367 )*)
368 }
369 }
370 }
371}
372
373all_tuples!(
374 #[doc(fake_variadic)]
375 tuple_impl,
376 0,
377 15,
378 B
379);
380
381pub trait NoBundleEffect {}
384
385macro_rules! after_effect_impl {
386 ($($after_effect: ident),*) => {
387 #[expect(
388 clippy::allow_attributes,
389 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
390 )]
391 impl<$($after_effect: BundleEffect),*> BundleEffect for ($($after_effect,)*) {
392 #[allow(
393 clippy::unused_unit,
394 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case.")
395 ]
396 fn apply(self, _entity: &mut EntityWorldMut) {
397 #[allow(
398 non_snake_case,
399 reason = "The names of these variables are provided by the caller, not by us."
400 )]
401 let ($($after_effect,)*) = self;
402 $($after_effect.apply(_entity);)*
403 }
404 }
405
406 impl<$($after_effect: NoBundleEffect),*> NoBundleEffect for ($($after_effect,)*) { }
407 }
408}
409
410all_tuples!(after_effect_impl, 0, 15, P);
411
412#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
416pub struct BundleId(usize);
417
418impl BundleId {
419 #[inline]
423 pub fn index(self) -> usize {
424 self.0
425 }
426}
427
428impl SparseSetIndex for BundleId {
429 #[inline]
430 fn sparse_set_index(&self) -> usize {
431 self.index()
432 }
433
434 #[inline]
435 fn get_sparse_set_index(value: usize) -> Self {
436 Self(value)
437 }
438}
439
440#[derive(Clone, Copy, Eq, PartialEq)]
442pub enum InsertMode {
443 Replace,
445 Keep,
447}
448
449pub struct BundleInfo {
453 id: BundleId,
454 component_ids: Vec<ComponentId>,
463 required_components: Vec<RequiredComponentConstructor>,
464 explicit_components_len: usize,
465}
466
467impl BundleInfo {
468 unsafe fn new(
475 bundle_type_name: &'static str,
476 storages: &mut Storages,
477 components: &Components,
478 mut component_ids: Vec<ComponentId>,
479 id: BundleId,
480 ) -> BundleInfo {
481 let mut deduped = component_ids.clone();
483 deduped.sort_unstable();
484 deduped.dedup();
485 if deduped.len() != component_ids.len() {
486 let mut seen = <HashSet<_>>::default();
488 let mut dups = Vec::new();
489 for id in component_ids {
490 if !seen.insert(id) {
491 dups.push(id);
492 }
493 }
494
495 let names = dups
496 .into_iter()
497 .map(|id| {
498 unsafe { components.get_info_unchecked(id).name() }
500 })
501 .collect::<Vec<_>>()
502 .join(", ");
503
504 panic!("Bundle {bundle_type_name} has duplicate components: {names}");
505 }
506
507 let explicit_components_len = component_ids.len();
509 let mut required_components = RequiredComponents::default();
510 for component_id in component_ids.iter().copied() {
511 let info = unsafe { components.get_info_unchecked(component_id) };
513 required_components.merge(info.required_components());
514 storages.prepare_component(info);
515 }
516 required_components.remove_explicit_components(&component_ids);
517
518 let required_components = required_components
520 .0
521 .into_iter()
522 .map(|(component_id, v)| {
523 let info = unsafe { components.get_info_unchecked(component_id) };
525 storages.prepare_component(info);
526 component_ids.push(component_id);
529 v.constructor
530 })
531 .collect();
532
533 BundleInfo {
538 id,
539 component_ids,
540 required_components,
541 explicit_components_len,
542 }
543 }
544
545 #[inline]
547 pub const fn id(&self) -> BundleId {
548 self.id
549 }
550
551 #[inline]
555 pub fn explicit_components(&self) -> &[ComponentId] {
556 &self.component_ids[0..self.explicit_components_len]
557 }
558
559 #[inline]
562 pub fn required_components(&self) -> &[ComponentId] {
563 &self.component_ids[self.explicit_components_len..]
564 }
565
566 #[inline]
570 pub fn contributed_components(&self) -> &[ComponentId] {
571 &self.component_ids
572 }
573
574 #[inline]
577 pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
578 self.explicit_components().iter().copied()
579 }
580
581 #[inline]
585 pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
586 self.component_ids.iter().copied()
587 }
588
589 pub fn iter_required_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
592 self.required_components().iter().copied()
593 }
594
595 #[inline]
615 unsafe fn write_components<'a, T: DynamicBundle, S: BundleComponentStatus>(
616 &self,
617 table: &mut Table,
618 sparse_sets: &mut SparseSets,
619 bundle_component_status: &S,
620 required_components: impl Iterator<Item = &'a RequiredComponentConstructor>,
621 entity: Entity,
622 table_row: TableRow,
623 change_tick: Tick,
624 bundle: T,
625 insert_mode: InsertMode,
626 caller: MaybeLocation,
627 ) -> T::Effect {
628 let mut bundle_component = 0;
631 let after_effect = bundle.get_components(&mut |storage_type, component_ptr| {
632 let component_id = *self.component_ids.get_unchecked(bundle_component);
633 match storage_type {
634 StorageType::Table => {
635 let status = unsafe { bundle_component_status.get_status(bundle_component) };
637 let column = table.get_column_mut(component_id).debug_checked_unwrap();
640 match (status, insert_mode) {
641 (ComponentStatus::Added, _) => {
642 column.initialize(table_row, component_ptr, change_tick, caller);
643 }
644 (ComponentStatus::Existing, InsertMode::Replace) => {
645 column.replace(table_row, component_ptr, change_tick, caller);
646 }
647 (ComponentStatus::Existing, InsertMode::Keep) => {
648 if let Some(drop_fn) = table.get_drop_for(component_id) {
649 drop_fn(component_ptr);
650 }
651 }
652 }
653 }
654 StorageType::SparseSet => {
655 let sparse_set =
656 unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
659 sparse_set.insert(entity, component_ptr, change_tick, caller);
660 }
661 }
662 bundle_component += 1;
663 });
664
665 for required_component in required_components {
666 required_component.initialize(
667 table,
668 sparse_sets,
669 change_tick,
670 table_row,
671 entity,
672 caller,
673 );
674 }
675
676 after_effect
677 }
678
679 pub(crate) unsafe fn initialize_required_component(
692 table: &mut Table,
693 sparse_sets: &mut SparseSets,
694 change_tick: Tick,
695 table_row: TableRow,
696 entity: Entity,
697 component_id: ComponentId,
698 storage_type: StorageType,
699 component_ptr: OwningPtr,
700 caller: MaybeLocation,
701 ) {
702 {
703 match storage_type {
704 StorageType::Table => {
705 let column =
706 unsafe { table.get_column_mut(component_id).debug_checked_unwrap() };
709 column.initialize(table_row, component_ptr, change_tick, caller);
710 }
711 StorageType::SparseSet => {
712 let sparse_set =
713 unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
716 sparse_set.insert(entity, component_ptr, change_tick, caller);
717 }
718 }
719 }
720 }
721
722 pub(crate) unsafe fn insert_bundle_into_archetype(
731 &self,
732 archetypes: &mut Archetypes,
733 storages: &mut Storages,
734 components: &Components,
735 observers: &Observers,
736 archetype_id: ArchetypeId,
737 ) -> ArchetypeId {
738 if let Some(archetype_after_insert_id) = archetypes[archetype_id]
739 .edges()
740 .get_archetype_after_bundle_insert(self.id)
741 {
742 return archetype_after_insert_id;
743 }
744 let mut new_table_components = Vec::new();
745 let mut new_sparse_set_components = Vec::new();
746 let mut bundle_status = Vec::with_capacity(self.explicit_components_len);
747 let mut added_required_components = Vec::new();
748 let mut added = Vec::new();
749 let mut existing = Vec::new();
750
751 let current_archetype = &mut archetypes[archetype_id];
752 for component_id in self.iter_explicit_components() {
753 if current_archetype.contains(component_id) {
754 bundle_status.push(ComponentStatus::Existing);
755 existing.push(component_id);
756 } else {
757 bundle_status.push(ComponentStatus::Added);
758 added.push(component_id);
759 let component_info = unsafe { components.get_info_unchecked(component_id) };
761 match component_info.storage_type() {
762 StorageType::Table => new_table_components.push(component_id),
763 StorageType::SparseSet => new_sparse_set_components.push(component_id),
764 }
765 }
766 }
767
768 for (index, component_id) in self.iter_required_components().enumerate() {
769 if !current_archetype.contains(component_id) {
770 added_required_components.push(self.required_components[index].clone());
771 added.push(component_id);
772 let component_info = unsafe { components.get_info_unchecked(component_id) };
774 match component_info.storage_type() {
775 StorageType::Table => {
776 new_table_components.push(component_id);
777 }
778 StorageType::SparseSet => {
779 new_sparse_set_components.push(component_id);
780 }
781 }
782 }
783 }
784
785 if new_table_components.is_empty() && new_sparse_set_components.is_empty() {
786 let edges = current_archetype.edges_mut();
787 edges.cache_archetype_after_bundle_insert(
789 self.id,
790 archetype_id,
791 bundle_status,
792 added_required_components,
793 added,
794 existing,
795 );
796 archetype_id
797 } else {
798 let table_id;
799 let table_components;
800 let sparse_set_components;
801 {
803 let current_archetype = &archetypes[archetype_id];
804 table_components = if new_table_components.is_empty() {
805 table_id = current_archetype.table_id();
807 current_archetype.table_components().collect()
808 } else {
809 new_table_components.extend(current_archetype.table_components());
810 new_table_components.sort_unstable();
812 table_id = unsafe {
814 storages
815 .tables
816 .get_id_or_insert(&new_table_components, components)
817 };
818
819 new_table_components
820 };
821
822 sparse_set_components = if new_sparse_set_components.is_empty() {
823 current_archetype.sparse_set_components().collect()
824 } else {
825 new_sparse_set_components.extend(current_archetype.sparse_set_components());
826 new_sparse_set_components.sort_unstable();
828 new_sparse_set_components
829 };
830 };
831 let new_archetype_id = archetypes.get_id_or_insert(
833 components,
834 observers,
835 table_id,
836 table_components,
837 sparse_set_components,
838 );
839 archetypes[archetype_id]
841 .edges_mut()
842 .cache_archetype_after_bundle_insert(
843 self.id,
844 new_archetype_id,
845 bundle_status,
846 added_required_components,
847 added,
848 existing,
849 );
850 new_archetype_id
851 }
852 }
853
854 pub(crate) unsafe fn remove_bundle_from_archetype(
870 &self,
871 archetypes: &mut Archetypes,
872 storages: &mut Storages,
873 components: &Components,
874 observers: &Observers,
875 archetype_id: ArchetypeId,
876 intersection: bool,
877 ) -> Option<ArchetypeId> {
878 let archetype_after_remove_result = {
881 let edges = archetypes[archetype_id].edges();
882 if intersection {
883 edges.get_archetype_after_bundle_remove(self.id())
884 } else {
885 edges.get_archetype_after_bundle_take(self.id())
886 }
887 };
888 let result = if let Some(result) = archetype_after_remove_result {
889 result
891 } else {
892 let mut next_table_components;
893 let mut next_sparse_set_components;
894 let next_table_id;
895 {
896 let current_archetype = &mut archetypes[archetype_id];
897 let mut removed_table_components = Vec::new();
898 let mut removed_sparse_set_components = Vec::new();
899 for component_id in self.iter_explicit_components() {
900 if current_archetype.contains(component_id) {
901 let component_info = unsafe { components.get_info_unchecked(component_id) };
903 match component_info.storage_type() {
904 StorageType::Table => removed_table_components.push(component_id),
905 StorageType::SparseSet => {
906 removed_sparse_set_components.push(component_id);
907 }
908 }
909 } else if !intersection {
910 current_archetype
913 .edges_mut()
914 .cache_archetype_after_bundle_take(self.id(), None);
915 return None;
916 }
917 }
918
919 removed_table_components.sort_unstable();
922 removed_sparse_set_components.sort_unstable();
923 next_table_components = current_archetype.table_components().collect();
924 next_sparse_set_components = current_archetype.sparse_set_components().collect();
925 sorted_remove(&mut next_table_components, &removed_table_components);
926 sorted_remove(
927 &mut next_sparse_set_components,
928 &removed_sparse_set_components,
929 );
930
931 next_table_id = if removed_table_components.is_empty() {
932 current_archetype.table_id()
933 } else {
934 unsafe {
936 storages
937 .tables
938 .get_id_or_insert(&next_table_components, components)
939 }
940 };
941 }
942
943 let new_archetype_id = archetypes.get_id_or_insert(
944 components,
945 observers,
946 next_table_id,
947 next_table_components,
948 next_sparse_set_components,
949 );
950 Some(new_archetype_id)
951 };
952 let current_archetype = &mut archetypes[archetype_id];
953 if intersection {
955 current_archetype
956 .edges_mut()
957 .cache_archetype_after_bundle_remove(self.id(), result);
958 } else {
959 current_archetype
960 .edges_mut()
961 .cache_archetype_after_bundle_take(self.id(), result);
962 }
963 result
964 }
965}
966
967pub(crate) struct BundleInserter<'w> {
969 world: UnsafeWorldCell<'w>,
970 bundle_info: ConstNonNull<BundleInfo>,
971 archetype_after_insert: ConstNonNull<ArchetypeAfterBundleInsert>,
972 table: NonNull<Table>,
973 archetype: NonNull<Archetype>,
974 archetype_move_type: ArchetypeMoveType,
975 change_tick: Tick,
976}
977
978pub(crate) enum ArchetypeMoveType {
981 SameArchetype,
984 NewArchetypeSameTable { new_archetype: NonNull<Archetype> },
987 NewArchetypeNewTable {
990 new_archetype: NonNull<Archetype>,
991 new_table: NonNull<Table>,
992 },
993}
994
995impl<'w> BundleInserter<'w> {
996 #[inline]
997 pub(crate) fn new<T: Bundle>(
998 world: &'w mut World,
999 archetype_id: ArchetypeId,
1000 change_tick: Tick,
1001 ) -> Self {
1002 let mut registrator =
1004 unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
1005 let bundle_id = world
1006 .bundles
1007 .register_info::<T>(&mut registrator, &mut world.storages);
1008 unsafe { Self::new_with_id(world, archetype_id, bundle_id, change_tick) }
1010 }
1011
1012 #[inline]
1017 pub(crate) unsafe fn new_with_id(
1018 world: &'w mut World,
1019 archetype_id: ArchetypeId,
1020 bundle_id: BundleId,
1021 change_tick: Tick,
1022 ) -> Self {
1023 let bundle_info = world.bundles.get_unchecked(bundle_id);
1025 let bundle_id = bundle_info.id();
1026 let new_archetype_id = bundle_info.insert_bundle_into_archetype(
1027 &mut world.archetypes,
1028 &mut world.storages,
1029 &world.components,
1030 &world.observers,
1031 archetype_id,
1032 );
1033 if new_archetype_id == archetype_id {
1034 let archetype = &mut world.archetypes[archetype_id];
1035 let archetype_after_insert = unsafe {
1037 archetype
1038 .edges()
1039 .get_archetype_after_bundle_insert_internal(bundle_id)
1040 .debug_checked_unwrap()
1041 };
1042 let table_id = archetype.table_id();
1043 let table = &mut world.storages.tables[table_id];
1044 Self {
1045 archetype_after_insert: archetype_after_insert.into(),
1046 archetype: archetype.into(),
1047 bundle_info: bundle_info.into(),
1048 table: table.into(),
1049 archetype_move_type: ArchetypeMoveType::SameArchetype,
1050 change_tick,
1051 world: world.as_unsafe_world_cell(),
1052 }
1053 } else {
1054 let (archetype, new_archetype) =
1055 world.archetypes.get_2_mut(archetype_id, new_archetype_id);
1056 let archetype_after_insert = unsafe {
1058 archetype
1059 .edges()
1060 .get_archetype_after_bundle_insert_internal(bundle_id)
1061 .debug_checked_unwrap()
1062 };
1063 let table_id = archetype.table_id();
1064 let new_table_id = new_archetype.table_id();
1065 if table_id == new_table_id {
1066 let table = &mut world.storages.tables[table_id];
1067 Self {
1068 archetype_after_insert: archetype_after_insert.into(),
1069 archetype: archetype.into(),
1070 bundle_info: bundle_info.into(),
1071 table: table.into(),
1072 archetype_move_type: ArchetypeMoveType::NewArchetypeSameTable {
1073 new_archetype: new_archetype.into(),
1074 },
1075 change_tick,
1076 world: world.as_unsafe_world_cell(),
1077 }
1078 } else {
1079 let (table, new_table) = world.storages.tables.get_2_mut(table_id, new_table_id);
1080 Self {
1081 archetype_after_insert: archetype_after_insert.into(),
1082 archetype: archetype.into(),
1083 bundle_info: bundle_info.into(),
1084 table: table.into(),
1085 archetype_move_type: ArchetypeMoveType::NewArchetypeNewTable {
1086 new_archetype: new_archetype.into(),
1087 new_table: new_table.into(),
1088 },
1089 change_tick,
1090 world: world.as_unsafe_world_cell(),
1091 }
1092 }
1093 }
1094 }
1095
1096 #[inline]
1100 pub(crate) unsafe fn insert<T: DynamicBundle>(
1101 &mut self,
1102 entity: Entity,
1103 location: EntityLocation,
1104 bundle: T,
1105 insert_mode: InsertMode,
1106 caller: MaybeLocation,
1107 relationship_hook_mode: RelationshipHookMode,
1108 ) -> (EntityLocation, T::Effect) {
1109 let bundle_info = self.bundle_info.as_ref();
1110 let archetype_after_insert = self.archetype_after_insert.as_ref();
1111 let archetype = self.archetype.as_ref();
1112
1113 unsafe {
1116 let mut deferred_world = self.world.into_deferred();
1118
1119 if insert_mode == InsertMode::Replace {
1120 if archetype.has_replace_observer() {
1121 deferred_world.trigger_observers(
1122 ON_REPLACE,
1123 entity,
1124 archetype_after_insert.iter_existing(),
1125 caller,
1126 );
1127 }
1128 deferred_world.trigger_on_replace(
1129 archetype,
1130 entity,
1131 archetype_after_insert.iter_existing(),
1132 caller,
1133 relationship_hook_mode,
1134 );
1135 }
1136 }
1137
1138 let table = self.table.as_mut();
1139
1140 let archetype = self.archetype.as_mut();
1143
1144 let (new_archetype, new_location, after_effect) = match &mut self.archetype_move_type {
1145 ArchetypeMoveType::SameArchetype => {
1146 let sparse_sets = {
1148 let world = self.world.world_mut();
1149 &mut world.storages.sparse_sets
1150 };
1151
1152 let after_effect = bundle_info.write_components(
1153 table,
1154 sparse_sets,
1155 archetype_after_insert,
1156 archetype_after_insert.required_components.iter(),
1157 entity,
1158 location.table_row,
1159 self.change_tick,
1160 bundle,
1161 insert_mode,
1162 caller,
1163 );
1164
1165 (archetype, location, after_effect)
1166 }
1167 ArchetypeMoveType::NewArchetypeSameTable { new_archetype } => {
1168 let new_archetype = new_archetype.as_mut();
1169
1170 let (sparse_sets, entities) = {
1172 let world = self.world.world_mut();
1173 (&mut world.storages.sparse_sets, &mut world.entities)
1174 };
1175
1176 let result = archetype.swap_remove(location.archetype_row);
1177 if let Some(swapped_entity) = result.swapped_entity {
1178 let swapped_location =
1179 unsafe { entities.get(swapped_entity).debug_checked_unwrap() };
1181 entities.set(
1182 swapped_entity.index(),
1183 EntityLocation {
1184 archetype_id: swapped_location.archetype_id,
1185 archetype_row: location.archetype_row,
1186 table_id: swapped_location.table_id,
1187 table_row: swapped_location.table_row,
1188 },
1189 );
1190 }
1191 let new_location = new_archetype.allocate(entity, result.table_row);
1192 entities.set(entity.index(), new_location);
1193 let after_effect = bundle_info.write_components(
1194 table,
1195 sparse_sets,
1196 archetype_after_insert,
1197 archetype_after_insert.required_components.iter(),
1198 entity,
1199 result.table_row,
1200 self.change_tick,
1201 bundle,
1202 insert_mode,
1203 caller,
1204 );
1205
1206 (new_archetype, new_location, after_effect)
1207 }
1208 ArchetypeMoveType::NewArchetypeNewTable {
1209 new_archetype,
1210 new_table,
1211 } => {
1212 let new_table = new_table.as_mut();
1213 let new_archetype = new_archetype.as_mut();
1214
1215 let (archetypes_ptr, sparse_sets, entities) = {
1217 let world = self.world.world_mut();
1218 let archetype_ptr: *mut Archetype = world.archetypes.archetypes.as_mut_ptr();
1219 (
1220 archetype_ptr,
1221 &mut world.storages.sparse_sets,
1222 &mut world.entities,
1223 )
1224 };
1225 let result = archetype.swap_remove(location.archetype_row);
1226 if let Some(swapped_entity) = result.swapped_entity {
1227 let swapped_location =
1228 unsafe { entities.get(swapped_entity).debug_checked_unwrap() };
1230 entities.set(
1231 swapped_entity.index(),
1232 EntityLocation {
1233 archetype_id: swapped_location.archetype_id,
1234 archetype_row: location.archetype_row,
1235 table_id: swapped_location.table_id,
1236 table_row: swapped_location.table_row,
1237 },
1238 );
1239 }
1240 let move_result = table.move_to_superset_unchecked(result.table_row, new_table);
1243 let new_location = new_archetype.allocate(entity, move_result.new_row);
1244 entities.set(entity.index(), new_location);
1245
1246 if let Some(swapped_entity) = move_result.swapped_entity {
1248 let swapped_location =
1249 unsafe { entities.get(swapped_entity).debug_checked_unwrap() };
1251
1252 entities.set(
1253 swapped_entity.index(),
1254 EntityLocation {
1255 archetype_id: swapped_location.archetype_id,
1256 archetype_row: swapped_location.archetype_row,
1257 table_id: swapped_location.table_id,
1258 table_row: result.table_row,
1259 },
1260 );
1261
1262 if archetype.id() == swapped_location.archetype_id {
1263 archetype
1264 .set_entity_table_row(swapped_location.archetype_row, result.table_row);
1265 } else if new_archetype.id() == swapped_location.archetype_id {
1266 new_archetype
1267 .set_entity_table_row(swapped_location.archetype_row, result.table_row);
1268 } else {
1269 (*archetypes_ptr.add(swapped_location.archetype_id.index()))
1271 .set_entity_table_row(swapped_location.archetype_row, result.table_row);
1272 }
1273 }
1274
1275 let after_effect = bundle_info.write_components(
1276 new_table,
1277 sparse_sets,
1278 archetype_after_insert,
1279 archetype_after_insert.required_components.iter(),
1280 entity,
1281 move_result.new_row,
1282 self.change_tick,
1283 bundle,
1284 insert_mode,
1285 caller,
1286 );
1287
1288 (new_archetype, new_location, after_effect)
1289 }
1290 };
1291
1292 let new_archetype = &*new_archetype;
1293 let mut deferred_world = unsafe { self.world.into_deferred() };
1295
1296 unsafe {
1299 deferred_world.trigger_on_add(
1300 new_archetype,
1301 entity,
1302 archetype_after_insert.iter_added(),
1303 caller,
1304 );
1305 if new_archetype.has_add_observer() {
1306 deferred_world.trigger_observers(
1307 ON_ADD,
1308 entity,
1309 archetype_after_insert.iter_added(),
1310 caller,
1311 );
1312 }
1313 match insert_mode {
1314 InsertMode::Replace => {
1315 deferred_world.trigger_on_insert(
1317 new_archetype,
1318 entity,
1319 archetype_after_insert.iter_inserted(),
1320 caller,
1321 relationship_hook_mode,
1322 );
1323 if new_archetype.has_insert_observer() {
1324 deferred_world.trigger_observers(
1325 ON_INSERT,
1326 entity,
1327 archetype_after_insert.iter_inserted(),
1328 caller,
1329 );
1330 }
1331 }
1332 InsertMode::Keep => {
1333 deferred_world.trigger_on_insert(
1336 new_archetype,
1337 entity,
1338 archetype_after_insert.iter_added(),
1339 caller,
1340 relationship_hook_mode,
1341 );
1342 if new_archetype.has_insert_observer() {
1343 deferred_world.trigger_observers(
1344 ON_INSERT,
1345 entity,
1346 archetype_after_insert.iter_added(),
1347 caller,
1348 );
1349 }
1350 }
1351 }
1352 }
1353
1354 (new_location, after_effect)
1355 }
1356
1357 #[inline]
1358 pub(crate) fn entities(&mut self) -> &mut Entities {
1359 unsafe { &mut self.world.world_mut().entities }
1361 }
1362}
1363
1364pub(crate) struct BundleSpawner<'w> {
1366 world: UnsafeWorldCell<'w>,
1367 bundle_info: ConstNonNull<BundleInfo>,
1368 table: NonNull<Table>,
1369 archetype: NonNull<Archetype>,
1370 change_tick: Tick,
1371}
1372
1373impl<'w> BundleSpawner<'w> {
1374 #[inline]
1375 pub fn new<T: Bundle>(world: &'w mut World, change_tick: Tick) -> Self {
1376 let mut registrator =
1378 unsafe { ComponentsRegistrator::new(&mut world.components, &mut world.component_ids) };
1379 let bundle_id = world
1380 .bundles
1381 .register_info::<T>(&mut registrator, &mut world.storages);
1382 unsafe { Self::new_with_id(world, bundle_id, change_tick) }
1384 }
1385
1386 #[inline]
1391 pub(crate) unsafe fn new_with_id(
1392 world: &'w mut World,
1393 bundle_id: BundleId,
1394 change_tick: Tick,
1395 ) -> Self {
1396 let bundle_info = world.bundles.get_unchecked(bundle_id);
1397 let new_archetype_id = bundle_info.insert_bundle_into_archetype(
1398 &mut world.archetypes,
1399 &mut world.storages,
1400 &world.components,
1401 &world.observers,
1402 ArchetypeId::EMPTY,
1403 );
1404 let archetype = &mut world.archetypes[new_archetype_id];
1405 let table = &mut world.storages.tables[archetype.table_id()];
1406 Self {
1407 bundle_info: bundle_info.into(),
1408 table: table.into(),
1409 archetype: archetype.into(),
1410 change_tick,
1411 world: world.as_unsafe_world_cell(),
1412 }
1413 }
1414
1415 #[inline]
1416 pub fn reserve_storage(&mut self, additional: usize) {
1417 let (archetype, table) = unsafe { (self.archetype.as_mut(), self.table.as_mut()) };
1419 archetype.reserve(additional);
1420 table.reserve(additional);
1421 }
1422
1423 #[inline]
1426 #[track_caller]
1427 pub unsafe fn spawn_non_existent<T: DynamicBundle>(
1428 &mut self,
1429 entity: Entity,
1430 bundle: T,
1431 caller: MaybeLocation,
1432 ) -> (EntityLocation, T::Effect) {
1433 let bundle_info = self.bundle_info.as_ref();
1435 let (location, after_effect) = {
1436 let table = self.table.as_mut();
1437 let archetype = self.archetype.as_mut();
1438
1439 let (sparse_sets, entities) = {
1441 let world = self.world.world_mut();
1442 (&mut world.storages.sparse_sets, &mut world.entities)
1443 };
1444 let table_row = table.allocate(entity);
1445 let location = archetype.allocate(entity, table_row);
1446 let after_effect = bundle_info.write_components(
1447 table,
1448 sparse_sets,
1449 &SpawnBundleStatus,
1450 bundle_info.required_components.iter(),
1451 entity,
1452 table_row,
1453 self.change_tick,
1454 bundle,
1455 InsertMode::Replace,
1456 caller,
1457 );
1458 entities.set(entity.index(), location);
1459 (location, after_effect)
1460 };
1461
1462 let mut deferred_world = unsafe { self.world.into_deferred() };
1464 let archetype = self.archetype.as_ref();
1466 unsafe {
1469 deferred_world.trigger_on_add(
1470 archetype,
1471 entity,
1472 bundle_info.iter_contributed_components(),
1473 caller,
1474 );
1475 if archetype.has_add_observer() {
1476 deferred_world.trigger_observers(
1477 ON_ADD,
1478 entity,
1479 bundle_info.iter_contributed_components(),
1480 caller,
1481 );
1482 }
1483 deferred_world.trigger_on_insert(
1484 archetype,
1485 entity,
1486 bundle_info.iter_contributed_components(),
1487 caller,
1488 RelationshipHookMode::Run,
1489 );
1490 if archetype.has_insert_observer() {
1491 deferred_world.trigger_observers(
1492 ON_INSERT,
1493 entity,
1494 bundle_info.iter_contributed_components(),
1495 caller,
1496 );
1497 }
1498 };
1499
1500 (location, after_effect)
1501 }
1502
1503 #[inline]
1506 pub unsafe fn spawn<T: Bundle>(
1507 &mut self,
1508 bundle: T,
1509 caller: MaybeLocation,
1510 ) -> (Entity, T::Effect) {
1511 let entity = self.entities().alloc();
1512 let (_, after_effect) = unsafe { self.spawn_non_existent(entity, bundle, caller) };
1514 (entity, after_effect)
1515 }
1516
1517 #[inline]
1518 pub(crate) fn entities(&mut self) -> &mut Entities {
1519 unsafe { &mut self.world.world_mut().entities }
1521 }
1522
1523 #[inline]
1526 pub(crate) unsafe fn flush_commands(&mut self) {
1527 self.world.world_mut().flush();
1529 }
1530}
1531
1532#[derive(Default)]
1534pub struct Bundles {
1535 bundle_infos: Vec<BundleInfo>,
1536 bundle_ids: TypeIdMap<BundleId>,
1538 contributed_bundle_ids: TypeIdMap<BundleId>,
1540 dynamic_bundle_ids: HashMap<Box<[ComponentId]>, BundleId>,
1542 dynamic_bundle_storages: HashMap<BundleId, Vec<StorageType>>,
1543 dynamic_component_bundle_ids: HashMap<ComponentId, BundleId>,
1545 dynamic_component_storages: HashMap<BundleId, StorageType>,
1546}
1547
1548impl Bundles {
1549 pub fn len(&self) -> usize {
1551 self.bundle_infos.len()
1552 }
1553
1554 pub fn is_empty(&self) -> bool {
1556 self.len() == 0
1557 }
1558
1559 pub fn iter(&self) -> impl Iterator<Item = &BundleInfo> {
1561 self.bundle_infos.iter()
1562 }
1563
1564 #[inline]
1567 pub fn get(&self, bundle_id: BundleId) -> Option<&BundleInfo> {
1568 self.bundle_infos.get(bundle_id.index())
1569 }
1570
1571 #[inline]
1575 pub fn get_id(&self, type_id: TypeId) -> Option<BundleId> {
1576 self.bundle_ids.get(&type_id).cloned()
1577 }
1578
1579 pub(crate) fn register_info<T: Bundle>(
1583 &mut self,
1584 components: &mut ComponentsRegistrator,
1585 storages: &mut Storages,
1586 ) -> BundleId {
1587 let bundle_infos = &mut self.bundle_infos;
1588 *self.bundle_ids.entry(TypeId::of::<T>()).or_insert_with(|| {
1589 let mut component_ids= Vec::new();
1590 T::component_ids(components, &mut |id| component_ids.push(id));
1591 let id = BundleId(bundle_infos.len());
1592 let bundle_info =
1593 unsafe { BundleInfo::new(core::any::type_name::<T>(), storages, components, component_ids, id) };
1598 bundle_infos.push(bundle_info);
1599 id
1600 })
1601 }
1602
1603 pub(crate) fn register_contributed_bundle_info<T: Bundle>(
1607 &mut self,
1608 components: &mut ComponentsRegistrator,
1609 storages: &mut Storages,
1610 ) -> BundleId {
1611 if let Some(id) = self.contributed_bundle_ids.get(&TypeId::of::<T>()).cloned() {
1612 id
1613 } else {
1614 let explicit_bundle_id = self.register_info::<T>(components, storages);
1615 let id = unsafe {
1617 let (ptr, len) = {
1618 let contributed = self
1620 .get_unchecked(explicit_bundle_id)
1621 .contributed_components();
1622 (contributed.as_ptr(), contributed.len())
1623 };
1624 self.init_dynamic_info(storages, components, core::slice::from_raw_parts(ptr, len))
1627 };
1628 self.contributed_bundle_ids.insert(TypeId::of::<T>(), id);
1629 id
1630 }
1631 }
1632
1633 pub(crate) unsafe fn get_unchecked(&self, id: BundleId) -> &BundleInfo {
1636 self.bundle_infos.get_unchecked(id.0)
1637 }
1638
1639 pub(crate) unsafe fn get_storage_unchecked(&self, id: BundleId) -> StorageType {
1642 *self
1643 .dynamic_component_storages
1644 .get(&id)
1645 .debug_checked_unwrap()
1646 }
1647
1648 pub(crate) unsafe fn get_storages_unchecked(&mut self, id: BundleId) -> &mut Vec<StorageType> {
1651 self.dynamic_bundle_storages
1652 .get_mut(&id)
1653 .debug_checked_unwrap()
1654 }
1655
1656 pub(crate) fn init_dynamic_info(
1663 &mut self,
1664 storages: &mut Storages,
1665 components: &Components,
1666 component_ids: &[ComponentId],
1667 ) -> BundleId {
1668 let bundle_infos = &mut self.bundle_infos;
1669
1670 let (_, bundle_id) = self
1672 .dynamic_bundle_ids
1673 .raw_entry_mut()
1674 .from_key(component_ids)
1675 .or_insert_with(|| {
1676 let (id, storages) = initialize_dynamic_bundle(
1677 bundle_infos,
1678 storages,
1679 components,
1680 Vec::from(component_ids),
1681 );
1682 unsafe {
1684 self.dynamic_bundle_storages
1685 .insert_unique_unchecked(id, storages);
1686 }
1687 (component_ids.into(), id)
1688 });
1689 *bundle_id
1690 }
1691
1692 pub(crate) fn init_component_info(
1698 &mut self,
1699 storages: &mut Storages,
1700 components: &Components,
1701 component_id: ComponentId,
1702 ) -> BundleId {
1703 let bundle_infos = &mut self.bundle_infos;
1704 let bundle_id = self
1705 .dynamic_component_bundle_ids
1706 .entry(component_id)
1707 .or_insert_with(|| {
1708 let (id, storage_type) = initialize_dynamic_bundle(
1709 bundle_infos,
1710 storages,
1711 components,
1712 vec![component_id],
1713 );
1714 self.dynamic_component_storages.insert(id, storage_type[0]);
1715 id
1716 });
1717 *bundle_id
1718 }
1719}
1720
1721fn initialize_dynamic_bundle(
1724 bundle_infos: &mut Vec<BundleInfo>,
1725 storages: &mut Storages,
1726 components: &Components,
1727 component_ids: Vec<ComponentId>,
1728) -> (BundleId, Vec<StorageType>) {
1729 let storage_types = component_ids.iter().map(|&id| {
1731 components.get_info(id).unwrap_or_else(|| {
1732 panic!(
1733 "init_dynamic_info called with component id {id:?} which doesn't exist in this world"
1734 )
1735 }).storage_type()
1736 }).collect();
1737
1738 let id = BundleId(bundle_infos.len());
1739 let bundle_info =
1740 unsafe { BundleInfo::new("<dynamic bundle>", storages, components, component_ids, id) };
1742 bundle_infos.push(bundle_info);
1743
1744 (id, storage_types)
1745}
1746
1747fn sorted_remove<T: Eq + Ord + Copy>(source: &mut Vec<T>, remove: &[T]) {
1748 let mut remove_index = 0;
1749 source.retain(|value| {
1750 while remove_index < remove.len() && *value > remove[remove_index] {
1751 remove_index += 1;
1752 }
1753
1754 if remove_index < remove.len() {
1755 *value != remove[remove_index]
1756 } else {
1757 true
1758 }
1759 });
1760}
1761
1762#[cfg(test)]
1763mod tests {
1764 use crate::{component::HookContext, prelude::*, world::DeferredWorld};
1765 use alloc::vec;
1766
1767 #[derive(Component)]
1768 struct A;
1769
1770 #[derive(Component)]
1771 #[component(on_add = a_on_add, on_insert = a_on_insert, on_replace = a_on_replace, on_remove = a_on_remove)]
1772 struct AMacroHooks;
1773
1774 fn a_on_add(mut world: DeferredWorld, _: HookContext) {
1775 world.resource_mut::<R>().assert_order(0);
1776 }
1777
1778 fn a_on_insert(mut world: DeferredWorld, _: HookContext) {
1779 world.resource_mut::<R>().assert_order(1);
1780 }
1781
1782 fn a_on_replace(mut world: DeferredWorld, _: HookContext) {
1783 world.resource_mut::<R>().assert_order(2);
1784 }
1785
1786 fn a_on_remove(mut world: DeferredWorld, _: HookContext) {
1787 world.resource_mut::<R>().assert_order(3);
1788 }
1789
1790 #[derive(Component)]
1791 struct B;
1792
1793 #[derive(Component)]
1794 struct C;
1795
1796 #[derive(Component)]
1797 struct D;
1798
1799 #[derive(Component, Eq, PartialEq, Debug)]
1800 struct V(&'static str); #[derive(Resource, Default)]
1803 struct R(usize);
1804
1805 impl R {
1806 #[track_caller]
1807 fn assert_order(&mut self, count: usize) {
1808 assert_eq!(count, self.0);
1809 self.0 += 1;
1810 }
1811 }
1812
1813 #[test]
1814 fn component_hook_order_spawn_despawn() {
1815 let mut world = World::new();
1816 world.init_resource::<R>();
1817 world
1818 .register_component_hooks::<A>()
1819 .on_add(|mut world, _| world.resource_mut::<R>().assert_order(0))
1820 .on_insert(|mut world, _| world.resource_mut::<R>().assert_order(1))
1821 .on_replace(|mut world, _| world.resource_mut::<R>().assert_order(2))
1822 .on_remove(|mut world, _| world.resource_mut::<R>().assert_order(3));
1823
1824 let entity = world.spawn(A).id();
1825 world.despawn(entity);
1826 assert_eq!(4, world.resource::<R>().0);
1827 }
1828
1829 #[test]
1830 fn component_hook_order_spawn_despawn_with_macro_hooks() {
1831 let mut world = World::new();
1832 world.init_resource::<R>();
1833
1834 let entity = world.spawn(AMacroHooks).id();
1835 world.despawn(entity);
1836
1837 assert_eq!(4, world.resource::<R>().0);
1838 }
1839
1840 #[test]
1841 fn component_hook_order_insert_remove() {
1842 let mut world = World::new();
1843 world.init_resource::<R>();
1844 world
1845 .register_component_hooks::<A>()
1846 .on_add(|mut world, _| world.resource_mut::<R>().assert_order(0))
1847 .on_insert(|mut world, _| world.resource_mut::<R>().assert_order(1))
1848 .on_replace(|mut world, _| world.resource_mut::<R>().assert_order(2))
1849 .on_remove(|mut world, _| world.resource_mut::<R>().assert_order(3));
1850
1851 let mut entity = world.spawn_empty();
1852 entity.insert(A);
1853 entity.remove::<A>();
1854 entity.flush();
1855 assert_eq!(4, world.resource::<R>().0);
1856 }
1857
1858 #[test]
1859 fn component_hook_order_replace() {
1860 let mut world = World::new();
1861 world
1862 .register_component_hooks::<A>()
1863 .on_replace(|mut world, _| world.resource_mut::<R>().assert_order(0))
1864 .on_insert(|mut world, _| {
1865 if let Some(mut r) = world.get_resource_mut::<R>() {
1866 r.assert_order(1);
1867 }
1868 });
1869
1870 let entity = world.spawn(A).id();
1871 world.init_resource::<R>();
1872 let mut entity = world.entity_mut(entity);
1873 entity.insert(A);
1874 entity.insert_if_new(A); entity.flush();
1876 assert_eq!(2, world.resource::<R>().0);
1877 }
1878
1879 #[test]
1880 fn component_hook_order_recursive() {
1881 let mut world = World::new();
1882 world.init_resource::<R>();
1883 world
1884 .register_component_hooks::<A>()
1885 .on_add(|mut world, context| {
1886 world.resource_mut::<R>().assert_order(0);
1887 world.commands().entity(context.entity).insert(B);
1888 })
1889 .on_remove(|mut world, context| {
1890 world.resource_mut::<R>().assert_order(2);
1891 world.commands().entity(context.entity).remove::<B>();
1892 });
1893
1894 world
1895 .register_component_hooks::<B>()
1896 .on_add(|mut world, context| {
1897 world.resource_mut::<R>().assert_order(1);
1898 world.commands().entity(context.entity).remove::<A>();
1899 })
1900 .on_remove(|mut world, _| {
1901 world.resource_mut::<R>().assert_order(3);
1902 });
1903
1904 let entity = world.spawn(A).flush();
1905 let entity = world.get_entity(entity).unwrap();
1906 assert!(!entity.contains::<A>());
1907 assert!(!entity.contains::<B>());
1908 assert_eq!(4, world.resource::<R>().0);
1909 }
1910
1911 #[test]
1912 fn component_hook_order_recursive_multiple() {
1913 let mut world = World::new();
1914 world.init_resource::<R>();
1915 world
1916 .register_component_hooks::<A>()
1917 .on_add(|mut world, context| {
1918 world.resource_mut::<R>().assert_order(0);
1919 world.commands().entity(context.entity).insert(B).insert(C);
1920 });
1921
1922 world
1923 .register_component_hooks::<B>()
1924 .on_add(|mut world, context| {
1925 world.resource_mut::<R>().assert_order(1);
1926 world.commands().entity(context.entity).insert(D);
1927 });
1928
1929 world
1930 .register_component_hooks::<C>()
1931 .on_add(|mut world, _| {
1932 world.resource_mut::<R>().assert_order(3);
1933 });
1934
1935 world
1936 .register_component_hooks::<D>()
1937 .on_add(|mut world, _| {
1938 world.resource_mut::<R>().assert_order(2);
1939 });
1940
1941 world.spawn(A).flush();
1942 assert_eq!(4, world.resource::<R>().0);
1943 }
1944
1945 #[test]
1946 fn insert_if_new() {
1947 let mut world = World::new();
1948 let id = world.spawn(V("one")).id();
1949 let mut entity = world.entity_mut(id);
1950 entity.insert_if_new(V("two"));
1951 entity.insert_if_new((A, V("three")));
1952 entity.flush();
1953 let entity = world.entity(id);
1955 assert!(entity.contains::<A>());
1956 assert_eq!(entity.get(), Some(&V("one")));
1957 }
1958
1959 #[test]
1960 fn sorted_remove() {
1961 let mut a = vec![1, 2, 3, 4, 5, 6, 7];
1962 let b = vec![1, 2, 3, 5, 7];
1963 super::sorted_remove(&mut a, &b);
1964
1965 assert_eq!(a, vec![4, 6]);
1966
1967 let mut a = vec![1];
1968 let b = vec![1];
1969 super::sorted_remove(&mut a, &b);
1970
1971 assert_eq!(a, vec![]);
1972
1973 let mut a = vec![1];
1974 let b = vec![2];
1975 super::sorted_remove(&mut a, &b);
1976
1977 assert_eq!(a, vec![1]);
1978 }
1979}