bevy_ecs/
bundle.rs

1//! Types for handling [`Bundle`]s.
2//!
3//! This module contains the [`Bundle`] trait and some other helper types.
4
5pub use bevy_ecs_macros::Bundle;
6
7use crate::{
8    archetype::{
9        AddBundle, Archetype, ArchetypeId, Archetypes, BundleComponentStatus, ComponentStatus,
10        SpawnBundleStatus,
11    },
12    component::{
13        Component, ComponentId, Components, RequiredComponentConstructor, RequiredComponents,
14        StorageType, Tick,
15    },
16    entity::{Entities, Entity, EntityLocation},
17    observer::Observers,
18    prelude::World,
19    query::DebugCheckedUnwrap,
20    storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
21    world::{unsafe_world_cell::UnsafeWorldCell, ON_ADD, ON_INSERT, ON_REPLACE},
22};
23use bevy_ptr::{ConstNonNull, OwningPtr};
24use bevy_utils::{all_tuples, HashMap, HashSet, TypeIdMap};
25#[cfg(feature = "track_change_detection")]
26use core::panic::Location;
27use core::{any::TypeId, ptr::NonNull};
28
29/// The `Bundle` trait enables insertion and removal of [`Component`]s from an entity.
30///
31/// Implementors of the `Bundle` trait are called 'bundles'.
32///
33/// Each bundle represents a static set of [`Component`] types.
34/// Currently, bundles can only contain one of each [`Component`], and will
35/// panic once initialized if this is not met.
36///
37/// ## Insertion
38///
39/// The primary use for bundles is to add a useful collection of components to an entity.
40///
41/// Adding a value of bundle to an entity will add the components from the set it
42/// represents to the entity.
43/// The values of these components are taken from the bundle.
44/// If an entity already had one of these components, the entity's original component value
45/// will be overwritten.
46///
47/// Importantly, bundles are only their constituent set of components.
48/// You **should not** use bundles as a unit of behavior.
49/// The behavior of your app can only be considered in terms of components, as systems,
50/// which drive the behavior of a `bevy` application, operate on combinations of
51/// components.
52///
53/// This rule is also important because multiple bundles may contain the same component type,
54/// calculated in different ways — adding both of these bundles to one entity
55/// would create incoherent behavior.
56/// This would be unexpected if bundles were treated as an abstraction boundary, as
57/// the abstraction would be unmaintainable for these cases.
58///
59/// For this reason, there is intentionally no [`Query`] to match whether an entity
60/// contains the components of a bundle.
61/// Queries should instead only select the components they logically operate on.
62///
63/// ## Removal
64///
65/// Bundles are also used when removing components from an entity.
66///
67/// Removing a bundle from an entity will remove any of its components attached
68/// to the entity from the entity.
69/// That is, if the entity does not have all the components of the bundle, those
70/// which are present will be removed.
71///
72/// # Implementors
73///
74/// Every type which implements [`Component`] also implements `Bundle`, since
75/// [`Component`] types can be added to or removed from an entity.
76///
77/// Additionally, [Tuples](`tuple`) of bundles are also [`Bundle`] (with up to 15 bundles).
78/// These bundles contain the items of the 'inner' bundles.
79/// This is a convenient shorthand which is primarily used when spawning entities.
80///
81/// [`unit`], otherwise known as [`()`](`unit`), is a [`Bundle`] containing no components (since it
82/// can also be considered as the empty tuple).
83/// This can be useful for spawning large numbers of empty entities using
84/// [`World::spawn_batch`](crate::world::World::spawn_batch).
85///
86/// Tuple bundles can be nested, which can be used to create an anonymous bundle with more than
87/// 15 items.
88/// However, in most cases where this is required, the derive macro [`derive@Bundle`] should be
89/// used instead.
90/// The derived `Bundle` implementation contains the items of its fields, which all must
91/// implement `Bundle`.
92/// As explained above, this includes any [`Component`] type, and other derived bundles.
93///
94/// If you want to add `PhantomData` to your `Bundle` you have to mark it with `#[bundle(ignore)]`.
95/// ```
96/// # use std::marker::PhantomData;
97/// use bevy_ecs::{component::Component, bundle::Bundle};
98///
99/// #[derive(Component)]
100/// struct XPosition(i32);
101/// #[derive(Component)]
102/// struct YPosition(i32);
103///
104/// #[derive(Bundle)]
105/// struct PositionBundle {
106///     // A bundle can contain components
107///     x: XPosition,
108///     y: YPosition,
109/// }
110///
111/// // You have to implement `Default` for ignored field types in bundle structs.
112/// #[derive(Default)]
113/// struct Other(f32);
114///
115/// #[derive(Bundle)]
116/// struct NamedPointBundle<T: Send + Sync + 'static> {
117///     // Or other bundles
118///     a: PositionBundle,
119///     // In addition to more components
120///     z: PointName,
121///
122///     // when you need to use `PhantomData` you have to mark it as ignored
123///     #[bundle(ignore)]
124///     _phantom_data: PhantomData<T>
125/// }
126///
127/// #[derive(Component)]
128/// struct PointName(String);
129/// ```
130///
131/// # Safety
132///
133/// Manual implementations of this trait are unsupported.
134/// That is, there is no safe way to implement this trait, and you must not do so.
135/// If you want a type to implement [`Bundle`], you must use [`derive@Bundle`](derive@Bundle).
136///
137/// [`Query`]: crate::system::Query
138// Some safety points:
139// - [`Bundle::component_ids`] must return the [`ComponentId`] for each component type in the
140// bundle, in the _exact_ order that [`DynamicBundle::get_components`] is called.
141// - [`Bundle::from_components`] must call `func` exactly once for each [`ComponentId`] returned by
142//   [`Bundle::component_ids`].
143#[diagnostic::on_unimplemented(
144    message = "`{Self}` is not a `Bundle`",
145    label = "invalid `Bundle`",
146    note = "consider annotating `{Self}` with `#[derive(Component)]` or `#[derive(Bundle)]`"
147)]
148pub unsafe trait Bundle: DynamicBundle + Send + Sync + 'static {
149    /// Gets this [`Bundle`]'s component ids, in the order of this bundle's [`Component`]s
150    #[doc(hidden)]
151    fn component_ids(
152        components: &mut Components,
153        storages: &mut Storages,
154        ids: &mut impl FnMut(ComponentId),
155    );
156
157    /// Gets this [`Bundle`]'s component ids. This will be [`None`] if the component has not been registered.
158    fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>));
159
160    /// Calls `func`, which should return data for each component in the bundle, in the order of
161    /// this bundle's [`Component`]s
162    ///
163    /// # Safety
164    /// Caller must return data for each component in the bundle, in the order of this bundle's
165    /// [`Component`]s
166    #[doc(hidden)]
167    unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
168    where
169        // Ensure that the `OwningPtr` is used correctly
170        F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
171        Self: Sized;
172
173    /// Registers components that are required by the components in this [`Bundle`].
174    fn register_required_components(
175        _components: &mut Components,
176        _storages: &mut Storages,
177        _required_components: &mut RequiredComponents,
178    );
179}
180
181/// The parts from [`Bundle`] that don't require statically knowing the components of the bundle.
182pub trait DynamicBundle {
183    // SAFETY:
184    // The `StorageType` argument passed into [`Bundle::get_components`] must be correct for the
185    // component being fetched.
186    //
187    /// Calls `func` on each value, in the order of this bundle's [`Component`]s. This passes
188    /// ownership of the component values to `func`.
189    #[doc(hidden)]
190    fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>));
191}
192
193// SAFETY:
194// - `Bundle::component_ids` calls `ids` for C's component id (and nothing else)
195// - `Bundle::get_components` is called exactly once for C and passes the component's storage type based on its associated constant.
196// - `Bundle::from_components` calls `func` exactly once for C, which is the exact value returned by `Bundle::component_ids`.
197unsafe impl<C: Component> Bundle for C {
198    fn component_ids(
199        components: &mut Components,
200        storages: &mut Storages,
201        ids: &mut impl FnMut(ComponentId),
202    ) {
203        ids(components.register_component::<C>(storages));
204    }
205
206    unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
207    where
208        // Ensure that the `OwningPtr` is used correctly
209        F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
210        Self: Sized,
211    {
212        let ptr = func(ctx);
213        // Safety: The id given in `component_ids` is for `Self`
214        unsafe { ptr.read() }
215    }
216
217    fn register_required_components(
218        components: &mut Components,
219        storages: &mut Storages,
220        required_components: &mut RequiredComponents,
221    ) {
222        let component_id = components.register_component::<C>(storages);
223        <C as Component>::register_required_components(
224            component_id,
225            components,
226            storages,
227            required_components,
228            0,
229        );
230    }
231
232    fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)) {
233        ids(components.get_id(TypeId::of::<C>()));
234    }
235}
236
237impl<C: Component> DynamicBundle for C {
238    #[inline]
239    fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
240        OwningPtr::make(self, |ptr| func(C::STORAGE_TYPE, ptr));
241    }
242}
243
244macro_rules! tuple_impl {
245    ($(#[$meta:meta])* $($name: ident),*) => {
246        $(#[$meta])*
247        // SAFETY:
248        // - `Bundle::component_ids` calls `ids` for each component type in the
249        // bundle, in the exact order that `DynamicBundle::get_components` is called.
250        // - `Bundle::from_components` calls `func` exactly once for each `ComponentId` returned by `Bundle::component_ids`.
251        // - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
252        //   `StorageType` into the callback.
253        unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
254            #[allow(unused_variables)]
255            fn component_ids(components: &mut Components, storages: &mut Storages, ids: &mut impl FnMut(ComponentId)){
256                $(<$name as Bundle>::component_ids(components, storages, ids);)*
257            }
258
259            #[allow(unused_variables)]
260            fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)){
261                $(<$name as Bundle>::get_component_ids(components, ids);)*
262            }
263
264            #[allow(unused_variables, unused_mut)]
265            #[allow(clippy::unused_unit)]
266            unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
267            where
268                F: FnMut(&mut T) -> OwningPtr<'_>
269            {
270                #[allow(unused_unsafe)]
271                // SAFETY: Rust guarantees that tuple calls are evaluated 'left to right'.
272                // https://doc.rust-lang.org/reference/expressions.html#evaluation-order-of-operands
273                unsafe { ($(<$name as Bundle>::from_components(ctx, func),)*) }
274            }
275
276            fn register_required_components(
277                _components: &mut Components,
278                _storages: &mut Storages,
279                _required_components: &mut RequiredComponents,
280            ) {
281                $(<$name as Bundle>::register_required_components(_components, _storages, _required_components);)*
282            }
283        }
284
285        $(#[$meta])*
286        impl<$($name: Bundle),*> DynamicBundle for ($($name,)*) {
287            #[allow(unused_variables, unused_mut)]
288            #[inline(always)]
289            fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
290                #[allow(non_snake_case)]
291                let ($(mut $name,)*) = self;
292                $(
293                    $name.get_components(&mut *func);
294                )*
295            }
296        }
297    }
298}
299
300all_tuples!(
301    #[doc(fake_variadic)]
302    tuple_impl,
303    0,
304    15,
305    B
306);
307
308/// For a specific [`World`], this stores a unique value identifying a type of a registered [`Bundle`].
309///
310/// [`World`]: crate::world::World
311#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
312pub struct BundleId(usize);
313
314impl BundleId {
315    /// Returns the index of the associated [`Bundle`] type.
316    ///
317    /// Note that this is unique per-world, and should not be reused across them.
318    #[inline]
319    pub fn index(self) -> usize {
320        self.0
321    }
322}
323
324impl SparseSetIndex for BundleId {
325    #[inline]
326    fn sparse_set_index(&self) -> usize {
327        self.index()
328    }
329
330    #[inline]
331    fn get_sparse_set_index(value: usize) -> Self {
332        Self(value)
333    }
334}
335
336// What to do on insertion if component already exists
337#[derive(Clone, Copy, Eq, PartialEq)]
338pub(crate) enum InsertMode {
339    /// Any existing components of a matching type will be overwritten.
340    Replace,
341    /// Any existing components of a matching type will kept unchanged.
342    Keep,
343}
344
345/// Stores metadata associated with a specific type of [`Bundle`] for a given [`World`].
346///
347/// [`World`]: crate::world::World
348pub struct BundleInfo {
349    id: BundleId,
350    /// The list of all components contributed by the bundle (including Required Components). This is in
351    /// the order `[EXPLICIT_COMPONENTS][REQUIRED_COMPONENTS]`
352    ///
353    /// # Safety
354    /// Every ID in this list must be valid within the World that owns the [`BundleInfo`],
355    /// must have its storage initialized (i.e. columns created in tables, sparse set created),
356    /// and the range (0..`explicit_components_len`) must be in the same order as the source bundle
357    /// type writes its components in.
358    component_ids: Vec<ComponentId>,
359    required_components: Vec<RequiredComponentConstructor>,
360    explicit_components_len: usize,
361}
362
363impl BundleInfo {
364    /// Create a new [`BundleInfo`].
365    ///
366    /// # Safety
367    ///
368    /// Every ID in `component_ids` must be valid within the World that owns the `BundleInfo`,
369    /// must have its storage initialized (i.e. columns created in tables, sparse set created),
370    /// and must be in the same order as the source bundle type writes its components in.
371    unsafe fn new(
372        bundle_type_name: &'static str,
373        components: &Components,
374        mut component_ids: Vec<ComponentId>,
375        id: BundleId,
376    ) -> BundleInfo {
377        let mut deduped = component_ids.clone();
378        deduped.sort_unstable();
379        deduped.dedup();
380
381        if deduped.len() != component_ids.len() {
382            // TODO: Replace with `Vec::partition_dedup` once https://github.com/rust-lang/rust/issues/54279 is stabilized
383            let mut seen = HashSet::new();
384            let mut dups = Vec::new();
385            for id in component_ids {
386                if !seen.insert(id) {
387                    dups.push(id);
388                }
389            }
390
391            let names = dups
392                .into_iter()
393                .map(|id| {
394                    // SAFETY: the caller ensures component_id is valid.
395                    unsafe { components.get_info_unchecked(id).name() }
396                })
397                .collect::<Vec<_>>()
398                .join(", ");
399
400            panic!("Bundle {bundle_type_name} has duplicate components: {names}");
401        }
402
403        let explicit_components_len = component_ids.len();
404        let mut required_components = RequiredComponents::default();
405        for component_id in component_ids.iter().copied() {
406            // SAFETY: caller has verified that all ids are valid
407            let info = unsafe { components.get_info_unchecked(component_id) };
408            required_components.merge(info.required_components());
409        }
410        required_components.remove_explicit_components(&component_ids);
411        let required_components = required_components
412            .0
413            .into_iter()
414            .map(|(component_id, v)| {
415                // This adds required components to the component_ids list _after_ using that list to remove explicitly provided
416                // components. This ordering is important!
417                component_ids.push(component_id);
418                v.constructor
419            })
420            .collect();
421
422        // SAFETY: The caller ensures that component_ids:
423        // - is valid for the associated world
424        // - has had its storage initialized
425        // - is in the same order as the source bundle type
426        BundleInfo {
427            id,
428            component_ids,
429            required_components,
430            explicit_components_len,
431        }
432    }
433
434    /// Returns a value identifying the associated [`Bundle`] type.
435    #[inline]
436    pub const fn id(&self) -> BundleId {
437        self.id
438    }
439
440    /// Returns the [ID](ComponentId) of each component explicitly defined in this bundle (ex: Required Components are excluded).
441    ///
442    /// For all components contributed by this bundle (including Required Components), see [`BundleInfo::contributed_components`]
443    #[inline]
444    pub fn explicit_components(&self) -> &[ComponentId] {
445        &self.component_ids[0..self.explicit_components_len]
446    }
447
448    /// Returns the [ID](ComponentId) of each Required Component needed by this bundle. This _does not include_ Required Components that are
449    /// explicitly provided by the bundle.
450    #[inline]
451    pub fn required_components(&self) -> &[ComponentId] {
452        &self.component_ids[self.explicit_components_len..]
453    }
454
455    /// Returns the [ID](ComponentId) of each component contributed by this bundle. This includes Required Components.
456    ///
457    /// For only components explicitly defined in this bundle, see [`BundleInfo::explicit_components`]
458    #[inline]
459    pub fn contributed_components(&self) -> &[ComponentId] {
460        &self.component_ids
461    }
462
463    /// Returns an iterator over the [ID](ComponentId) of each component explicitly defined in this bundle (ex: this excludes Required Components).
464    /// To iterate all components contributed by this bundle (including Required Components), see [`BundleInfo::iter_contributed_components`]
465    #[inline]
466    pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
467        self.explicit_components().iter().copied()
468    }
469
470    /// Returns an iterator over the [ID](ComponentId) of each component contributed by this bundle. This includes Required Components.
471    ///
472    /// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
473    #[inline]
474    pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
475        self.component_ids.iter().copied()
476    }
477
478    /// Returns an iterator over the [ID](ComponentId) of each Required Component needed by this bundle. This _does not include_ Required Components that are
479    /// explicitly provided by the bundle.
480    pub fn iter_required_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
481        self.required_components().iter().copied()
482    }
483
484    /// This writes components from a given [`Bundle`] to the given entity.
485    ///
486    /// # Safety
487    ///
488    /// `bundle_component_status` must return the "correct" [`ComponentStatus`] for each component
489    /// in the [`Bundle`], with respect to the entity's original archetype (prior to the bundle being added)
490    /// For example, if the original archetype already has `ComponentA` and `T` also has `ComponentA`, the status
491    /// should be `Mutated`. If the original archetype does not have `ComponentA`, the status should be `Added`.
492    /// When "inserting" a bundle into an existing entity, [`AddBundle`]
493    /// should be used, which will report `Added` vs `Mutated` status based on the current archetype's structure.
494    /// When spawning a bundle, [`SpawnBundleStatus`] can be used instead, which removes the need
495    /// to look up the [`AddBundle`] in the archetype graph, which requires
496    /// ownership of the entity's current archetype.
497    ///
498    /// `table` must be the "new" table for `entity`. `table_row` must have space allocated for the
499    /// `entity`, `bundle` must match this [`BundleInfo`]'s type
500    #[inline]
501    #[allow(clippy::too_many_arguments)]
502    unsafe fn write_components<'a, T: DynamicBundle, S: BundleComponentStatus>(
503        &self,
504        table: &mut Table,
505        sparse_sets: &mut SparseSets,
506        bundle_component_status: &S,
507        required_components: impl Iterator<Item = &'a RequiredComponentConstructor>,
508        entity: Entity,
509        table_row: TableRow,
510        change_tick: Tick,
511        bundle: T,
512        insert_mode: InsertMode,
513        #[cfg(feature = "track_change_detection")] caller: &'static Location<'static>,
514    ) {
515        // NOTE: get_components calls this closure on each component in "bundle order".
516        // bundle_info.component_ids are also in "bundle order"
517        let mut bundle_component = 0;
518        bundle.get_components(&mut |storage_type, component_ptr| {
519            let component_id = *self.component_ids.get_unchecked(bundle_component);
520            match storage_type {
521                StorageType::Table => {
522                    // SAFETY: bundle_component is a valid index for this bundle
523                    let status = unsafe { bundle_component_status.get_status(bundle_component) };
524                    // SAFETY: If component_id is in self.component_ids, BundleInfo::new requires that
525                    // the target table contains the component.
526                    let column = table.get_column_mut(component_id).debug_checked_unwrap();
527                    match (status, insert_mode) {
528                        (ComponentStatus::Added, _) => column.initialize(
529                            table_row,
530                            component_ptr,
531                            change_tick,
532                            #[cfg(feature = "track_change_detection")]
533                            caller,
534                        ),
535                        (ComponentStatus::Existing, InsertMode::Replace) => column.replace(
536                            table_row,
537                            component_ptr,
538                            change_tick,
539                            #[cfg(feature = "track_change_detection")]
540                            caller,
541                        ),
542                        (ComponentStatus::Existing, InsertMode::Keep) => {
543                            if let Some(drop_fn) = table.get_drop_for(component_id) {
544                                drop_fn(component_ptr);
545                            }
546                        }
547                    }
548                }
549                StorageType::SparseSet => {
550                    let sparse_set =
551                        // SAFETY: If component_id is in self.component_ids, BundleInfo::new requires that
552                        // a sparse set exists for the component.
553                        unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
554                    sparse_set.insert(
555                        entity,
556                        component_ptr,
557                        change_tick,
558                        #[cfg(feature = "track_change_detection")]
559                        caller,
560                    );
561                }
562            }
563            bundle_component += 1;
564        });
565
566        for required_component in required_components {
567            required_component.initialize(
568                table,
569                sparse_sets,
570                change_tick,
571                table_row,
572                entity,
573                #[cfg(feature = "track_change_detection")]
574                caller,
575            );
576        }
577    }
578
579    /// Internal method to initialize a required component from an [`OwningPtr`]. This should ultimately be called
580    /// in the context of [`BundleInfo::write_components`], via [`RequiredComponentConstructor::initialize`].
581    ///
582    /// # Safety
583    ///
584    /// `component_ptr` must point to a required component value that matches the given `component_id`. The `storage_type` must match
585    /// the type associated with `component_id`. The `entity` and `table_row` must correspond to an entity with an uninitialized
586    /// component matching `component_id`.
587    ///
588    /// This method _should not_ be called outside of [`BundleInfo::write_components`].
589    /// For more information, read the [`BundleInfo::write_components`] safety docs.
590    /// This function inherits the safety requirements defined there.
591    #[allow(clippy::too_many_arguments)]
592    pub(crate) unsafe fn initialize_required_component(
593        table: &mut Table,
594        sparse_sets: &mut SparseSets,
595        change_tick: Tick,
596        table_row: TableRow,
597        entity: Entity,
598        component_id: ComponentId,
599        storage_type: StorageType,
600        component_ptr: OwningPtr,
601        #[cfg(feature = "track_change_detection")] caller: &'static Location<'static>,
602    ) {
603        {
604            match storage_type {
605                StorageType::Table => {
606                    let column =
607                        // SAFETY: If component_id is in required_components, BundleInfo::new requires that
608                        // the target table contains the component.
609                        unsafe { table.get_column_mut(component_id).debug_checked_unwrap() };
610                    column.initialize(
611                        table_row,
612                        component_ptr,
613                        change_tick,
614                        #[cfg(feature = "track_change_detection")]
615                        caller,
616                    );
617                }
618                StorageType::SparseSet => {
619                    let sparse_set =
620                        // SAFETY: If component_id is in required_components, BundleInfo::new requires that
621                        // a sparse set exists for the component.
622                        unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
623                    sparse_set.insert(
624                        entity,
625                        component_ptr,
626                        change_tick,
627                        #[cfg(feature = "track_change_detection")]
628                        caller,
629                    );
630                }
631            }
632        }
633    }
634
635    /// Adds a bundle to the given archetype and returns the resulting archetype. This could be the
636    /// same [`ArchetypeId`], in the event that adding the given bundle does not result in an
637    /// [`Archetype`] change. Results are cached in the [`Archetype`] graph to avoid redundant work.
638    /// # Safety
639    /// `components` must be the same components as passed in [`Self::new`]
640    pub(crate) unsafe fn add_bundle_to_archetype(
641        &self,
642        archetypes: &mut Archetypes,
643        storages: &mut Storages,
644        components: &Components,
645        observers: &Observers,
646        archetype_id: ArchetypeId,
647    ) -> ArchetypeId {
648        if let Some(add_bundle_id) = archetypes[archetype_id].edges().get_add_bundle(self.id) {
649            return add_bundle_id;
650        }
651        let mut new_table_components = Vec::new();
652        let mut new_sparse_set_components = Vec::new();
653        let mut bundle_status = Vec::with_capacity(self.explicit_components_len);
654        let mut added_required_components = Vec::new();
655        let mut added = Vec::new();
656        let mut existing = Vec::new();
657
658        let current_archetype = &mut archetypes[archetype_id];
659        for component_id in self.iter_explicit_components() {
660            if current_archetype.contains(component_id) {
661                bundle_status.push(ComponentStatus::Existing);
662                existing.push(component_id);
663            } else {
664                bundle_status.push(ComponentStatus::Added);
665                added.push(component_id);
666                // SAFETY: component_id exists
667                let component_info = unsafe { components.get_info_unchecked(component_id) };
668                match component_info.storage_type() {
669                    StorageType::Table => new_table_components.push(component_id),
670                    StorageType::SparseSet => new_sparse_set_components.push(component_id),
671                }
672            }
673        }
674
675        for (index, component_id) in self.iter_required_components().enumerate() {
676            if !current_archetype.contains(component_id) {
677                added_required_components.push(self.required_components[index].clone());
678                added.push(component_id);
679                // SAFETY: component_id exists
680                let component_info = unsafe { components.get_info_unchecked(component_id) };
681                match component_info.storage_type() {
682                    StorageType::Table => {
683                        new_table_components.push(component_id);
684                    }
685                    StorageType::SparseSet => {
686                        new_sparse_set_components.push(component_id);
687                    }
688                }
689            }
690        }
691
692        if new_table_components.is_empty() && new_sparse_set_components.is_empty() {
693            let edges = current_archetype.edges_mut();
694            // the archetype does not change when we add this bundle
695            edges.insert_add_bundle(
696                self.id,
697                archetype_id,
698                bundle_status,
699                added_required_components,
700                added,
701                existing,
702            );
703            archetype_id
704        } else {
705            let table_id;
706            let table_components;
707            let sparse_set_components;
708            // the archetype changes when we add this bundle. prepare the new archetype and storages
709            {
710                let current_archetype = &archetypes[archetype_id];
711                table_components = if new_table_components.is_empty() {
712                    // if there are no new table components, we can keep using this table
713                    table_id = current_archetype.table_id();
714                    current_archetype.table_components().collect()
715                } else {
716                    new_table_components.extend(current_archetype.table_components());
717                    // sort to ignore order while hashing
718                    new_table_components.sort_unstable();
719                    // SAFETY: all component ids in `new_table_components` exist
720                    table_id = unsafe {
721                        storages
722                            .tables
723                            .get_id_or_insert(&new_table_components, components)
724                    };
725
726                    new_table_components
727                };
728
729                sparse_set_components = if new_sparse_set_components.is_empty() {
730                    current_archetype.sparse_set_components().collect()
731                } else {
732                    new_sparse_set_components.extend(current_archetype.sparse_set_components());
733                    // sort to ignore order while hashing
734                    new_sparse_set_components.sort_unstable();
735                    new_sparse_set_components
736                };
737            };
738            // SAFETY: ids in self must be valid
739            let new_archetype_id = archetypes.get_id_or_insert(
740                components,
741                observers,
742                table_id,
743                table_components,
744                sparse_set_components,
745            );
746            // add an edge from the old archetype to the new archetype
747            archetypes[archetype_id].edges_mut().insert_add_bundle(
748                self.id,
749                new_archetype_id,
750                bundle_status,
751                added_required_components,
752                added,
753                existing,
754            );
755            new_archetype_id
756        }
757    }
758}
759
760// SAFETY: We have exclusive world access so our pointers can't be invalidated externally
761pub(crate) struct BundleInserter<'w> {
762    world: UnsafeWorldCell<'w>,
763    bundle_info: ConstNonNull<BundleInfo>,
764    add_bundle: ConstNonNull<AddBundle>,
765    table: NonNull<Table>,
766    archetype: NonNull<Archetype>,
767    result: InsertBundleResult,
768    change_tick: Tick,
769}
770
771pub(crate) enum InsertBundleResult {
772    SameArchetype,
773    NewArchetypeSameTable {
774        new_archetype: NonNull<Archetype>,
775    },
776    NewArchetypeNewTable {
777        new_archetype: NonNull<Archetype>,
778        new_table: NonNull<Table>,
779    },
780}
781
782impl<'w> BundleInserter<'w> {
783    #[inline]
784    pub(crate) fn new<T: Bundle>(
785        world: &'w mut World,
786        archetype_id: ArchetypeId,
787        change_tick: Tick,
788    ) -> Self {
789        let bundle_id = world
790            .bundles
791            .register_info::<T>(&mut world.components, &mut world.storages);
792        // SAFETY: We just ensured this bundle exists
793        unsafe { Self::new_with_id(world, archetype_id, bundle_id, change_tick) }
794    }
795
796    /// Creates a new [`BundleInserter`].
797    ///
798    /// # Safety
799    /// - Caller must ensure that `bundle_id` exists in `world.bundles`.
800    #[inline]
801    pub(crate) unsafe fn new_with_id(
802        world: &'w mut World,
803        archetype_id: ArchetypeId,
804        bundle_id: BundleId,
805        change_tick: Tick,
806    ) -> Self {
807        // SAFETY: We will not make any accesses to the command queue, component or resource data of this world
808        let bundle_info = world.bundles.get_unchecked(bundle_id);
809        let bundle_id = bundle_info.id();
810        let new_archetype_id = bundle_info.add_bundle_to_archetype(
811            &mut world.archetypes,
812            &mut world.storages,
813            &world.components,
814            &world.observers,
815            archetype_id,
816        );
817        if new_archetype_id == archetype_id {
818            let archetype = &mut world.archetypes[archetype_id];
819            // SAFETY: The edge is assured to be initialized when we called add_bundle_to_archetype
820            let add_bundle = unsafe {
821                archetype
822                    .edges()
823                    .get_add_bundle_internal(bundle_id)
824                    .debug_checked_unwrap()
825            };
826            let table_id = archetype.table_id();
827            let table = &mut world.storages.tables[table_id];
828            Self {
829                add_bundle: add_bundle.into(),
830                archetype: archetype.into(),
831                bundle_info: bundle_info.into(),
832                table: table.into(),
833                result: InsertBundleResult::SameArchetype,
834                change_tick,
835                world: world.as_unsafe_world_cell(),
836            }
837        } else {
838            let (archetype, new_archetype) =
839                world.archetypes.get_2_mut(archetype_id, new_archetype_id);
840            // SAFETY: The edge is assured to be initialized when we called add_bundle_to_archetype
841            let add_bundle = unsafe {
842                archetype
843                    .edges()
844                    .get_add_bundle_internal(bundle_id)
845                    .debug_checked_unwrap()
846            };
847            let table_id = archetype.table_id();
848            let new_table_id = new_archetype.table_id();
849            if table_id == new_table_id {
850                let table = &mut world.storages.tables[table_id];
851                Self {
852                    add_bundle: add_bundle.into(),
853                    archetype: archetype.into(),
854                    bundle_info: bundle_info.into(),
855                    table: table.into(),
856                    result: InsertBundleResult::NewArchetypeSameTable {
857                        new_archetype: new_archetype.into(),
858                    },
859                    change_tick,
860                    world: world.as_unsafe_world_cell(),
861                }
862            } else {
863                let (table, new_table) = world.storages.tables.get_2_mut(table_id, new_table_id);
864                Self {
865                    add_bundle: add_bundle.into(),
866                    archetype: archetype.into(),
867                    bundle_info: bundle_info.into(),
868                    table: table.into(),
869                    result: InsertBundleResult::NewArchetypeNewTable {
870                        new_archetype: new_archetype.into(),
871                        new_table: new_table.into(),
872                    },
873                    change_tick,
874                    world: world.as_unsafe_world_cell(),
875                }
876            }
877        }
878    }
879
880    /// # Safety
881    /// `entity` must currently exist in the source archetype for this inserter. `location`
882    /// must be `entity`'s location in the archetype. `T` must match this [`BundleInfo`]'s type
883    #[inline]
884    pub(crate) unsafe fn insert<T: DynamicBundle>(
885        &mut self,
886        entity: Entity,
887        location: EntityLocation,
888        bundle: T,
889        insert_mode: InsertMode,
890        #[cfg(feature = "track_change_detection")] caller: &'static Location<'static>,
891    ) -> EntityLocation {
892        let bundle_info = self.bundle_info.as_ref();
893        let add_bundle = self.add_bundle.as_ref();
894        let table = self.table.as_mut();
895        let archetype = self.archetype.as_ref();
896
897        // SAFETY: All components in the bundle are guaranteed to exist in the World
898        // as they must be initialized before creating the BundleInfo.
899        unsafe {
900            // SAFETY: Mutable references do not alias and will be dropped after this block
901            let mut deferred_world = self.world.into_deferred();
902
903            if insert_mode == InsertMode::Replace {
904                deferred_world.trigger_on_replace(archetype, entity, add_bundle.iter_existing());
905                if archetype.has_replace_observer() {
906                    deferred_world.trigger_observers(
907                        ON_REPLACE,
908                        entity,
909                        add_bundle.iter_existing(),
910                    );
911                }
912            }
913        }
914
915        // SAFETY: Archetype gets borrowed when running the on_replace observers above,
916        // so this reference can only be promoted from shared to &mut down here, after they have been ran
917        let archetype = self.archetype.as_mut();
918
919        let (new_archetype, new_location) = match &mut self.result {
920            InsertBundleResult::SameArchetype => {
921                // SAFETY: Mutable references do not alias and will be dropped after this block
922                let sparse_sets = {
923                    let world = self.world.world_mut();
924                    &mut world.storages.sparse_sets
925                };
926
927                bundle_info.write_components(
928                    table,
929                    sparse_sets,
930                    add_bundle,
931                    add_bundle.required_components.iter(),
932                    entity,
933                    location.table_row,
934                    self.change_tick,
935                    bundle,
936                    insert_mode,
937                    #[cfg(feature = "track_change_detection")]
938                    caller,
939                );
940
941                (archetype, location)
942            }
943            InsertBundleResult::NewArchetypeSameTable { new_archetype } => {
944                let new_archetype = new_archetype.as_mut();
945
946                // SAFETY: Mutable references do not alias and will be dropped after this block
947                let (sparse_sets, entities) = {
948                    let world = self.world.world_mut();
949                    (&mut world.storages.sparse_sets, &mut world.entities)
950                };
951
952                let result = archetype.swap_remove(location.archetype_row);
953                if let Some(swapped_entity) = result.swapped_entity {
954                    let swapped_location =
955                        // SAFETY: If the swap was successful, swapped_entity must be valid.
956                        unsafe { entities.get(swapped_entity).debug_checked_unwrap() };
957                    entities.set(
958                        swapped_entity.index(),
959                        EntityLocation {
960                            archetype_id: swapped_location.archetype_id,
961                            archetype_row: location.archetype_row,
962                            table_id: swapped_location.table_id,
963                            table_row: swapped_location.table_row,
964                        },
965                    );
966                }
967                let new_location = new_archetype.allocate(entity, result.table_row);
968                entities.set(entity.index(), new_location);
969                bundle_info.write_components(
970                    table,
971                    sparse_sets,
972                    add_bundle,
973                    add_bundle.required_components.iter(),
974                    entity,
975                    result.table_row,
976                    self.change_tick,
977                    bundle,
978                    insert_mode,
979                    #[cfg(feature = "track_change_detection")]
980                    caller,
981                );
982
983                (new_archetype, new_location)
984            }
985            InsertBundleResult::NewArchetypeNewTable {
986                new_archetype,
987                new_table,
988            } => {
989                let new_table = new_table.as_mut();
990                let new_archetype = new_archetype.as_mut();
991
992                // SAFETY: Mutable references do not alias and will be dropped after this block
993                let (archetypes_ptr, sparse_sets, entities) = {
994                    let world = self.world.world_mut();
995                    let archetype_ptr: *mut Archetype = world.archetypes.archetypes.as_mut_ptr();
996                    (
997                        archetype_ptr,
998                        &mut world.storages.sparse_sets,
999                        &mut world.entities,
1000                    )
1001                };
1002                let result = archetype.swap_remove(location.archetype_row);
1003                if let Some(swapped_entity) = result.swapped_entity {
1004                    let swapped_location =
1005                        // SAFETY: If the swap was successful, swapped_entity must be valid.
1006                        unsafe { entities.get(swapped_entity).debug_checked_unwrap() };
1007                    entities.set(
1008                        swapped_entity.index(),
1009                        EntityLocation {
1010                            archetype_id: swapped_location.archetype_id,
1011                            archetype_row: location.archetype_row,
1012                            table_id: swapped_location.table_id,
1013                            table_row: swapped_location.table_row,
1014                        },
1015                    );
1016                }
1017                // PERF: store "non bundle" components in edge, then just move those to avoid
1018                // redundant copies
1019                let move_result = table.move_to_superset_unchecked(result.table_row, new_table);
1020                let new_location = new_archetype.allocate(entity, move_result.new_row);
1021                entities.set(entity.index(), new_location);
1022
1023                // if an entity was moved into this entity's table spot, update its table row
1024                if let Some(swapped_entity) = move_result.swapped_entity {
1025                    let swapped_location =
1026                        // SAFETY: If the swap was successful, swapped_entity must be valid.
1027                        unsafe { entities.get(swapped_entity).debug_checked_unwrap() };
1028
1029                    entities.set(
1030                        swapped_entity.index(),
1031                        EntityLocation {
1032                            archetype_id: swapped_location.archetype_id,
1033                            archetype_row: swapped_location.archetype_row,
1034                            table_id: swapped_location.table_id,
1035                            table_row: result.table_row,
1036                        },
1037                    );
1038
1039                    if archetype.id() == swapped_location.archetype_id {
1040                        archetype
1041                            .set_entity_table_row(swapped_location.archetype_row, result.table_row);
1042                    } else if new_archetype.id() == swapped_location.archetype_id {
1043                        new_archetype
1044                            .set_entity_table_row(swapped_location.archetype_row, result.table_row);
1045                    } else {
1046                        // SAFETY: the only two borrowed archetypes are above and we just did collision checks
1047                        (*archetypes_ptr.add(swapped_location.archetype_id.index()))
1048                            .set_entity_table_row(swapped_location.archetype_row, result.table_row);
1049                    }
1050                }
1051
1052                bundle_info.write_components(
1053                    new_table,
1054                    sparse_sets,
1055                    add_bundle,
1056                    add_bundle.required_components.iter(),
1057                    entity,
1058                    move_result.new_row,
1059                    self.change_tick,
1060                    bundle,
1061                    insert_mode,
1062                    #[cfg(feature = "track_change_detection")]
1063                    caller,
1064                );
1065
1066                (new_archetype, new_location)
1067            }
1068        };
1069
1070        let new_archetype = &*new_archetype;
1071        // SAFETY: We have no outstanding mutable references to world as they were dropped
1072        let mut deferred_world = unsafe { self.world.into_deferred() };
1073
1074        // SAFETY: All components in the bundle are guaranteed to exist in the World
1075        // as they must be initialized before creating the BundleInfo.
1076        unsafe {
1077            deferred_world.trigger_on_add(new_archetype, entity, add_bundle.iter_added());
1078            if new_archetype.has_add_observer() {
1079                deferred_world.trigger_observers(ON_ADD, entity, add_bundle.iter_added());
1080            }
1081            match insert_mode {
1082                InsertMode::Replace => {
1083                    // insert triggers for both new and existing components if we're replacing them
1084                    deferred_world.trigger_on_insert(
1085                        new_archetype,
1086                        entity,
1087                        add_bundle.iter_inserted(),
1088                    );
1089                    if new_archetype.has_insert_observer() {
1090                        deferred_world.trigger_observers(
1091                            ON_INSERT,
1092                            entity,
1093                            add_bundle.iter_inserted(),
1094                        );
1095                    }
1096                }
1097                InsertMode::Keep => {
1098                    // insert triggers only for new components if we're not replacing them (since
1099                    // nothing is actually inserted).
1100                    deferred_world.trigger_on_insert(
1101                        new_archetype,
1102                        entity,
1103                        add_bundle.iter_added(),
1104                    );
1105                    if new_archetype.has_insert_observer() {
1106                        deferred_world.trigger_observers(
1107                            ON_INSERT,
1108                            entity,
1109                            add_bundle.iter_added(),
1110                        );
1111                    }
1112                }
1113            }
1114        }
1115
1116        new_location
1117    }
1118
1119    #[inline]
1120    pub(crate) fn entities(&mut self) -> &mut Entities {
1121        // SAFETY: No outstanding references to self.world, changes to entities cannot invalidate our internal pointers
1122        unsafe { &mut self.world.world_mut().entities }
1123    }
1124}
1125
1126// SAFETY: We have exclusive world access so our pointers can't be invalidated externally
1127pub(crate) struct BundleSpawner<'w> {
1128    world: UnsafeWorldCell<'w>,
1129    bundle_info: ConstNonNull<BundleInfo>,
1130    table: NonNull<Table>,
1131    archetype: NonNull<Archetype>,
1132    change_tick: Tick,
1133}
1134
1135impl<'w> BundleSpawner<'w> {
1136    #[inline]
1137    pub fn new<T: Bundle>(world: &'w mut World, change_tick: Tick) -> Self {
1138        let bundle_id = world
1139            .bundles
1140            .register_info::<T>(&mut world.components, &mut world.storages);
1141        // SAFETY: we initialized this bundle_id in `init_info`
1142        unsafe { Self::new_with_id(world, bundle_id, change_tick) }
1143    }
1144
1145    /// Creates a new [`BundleSpawner`].
1146    ///
1147    /// # Safety
1148    /// Caller must ensure that `bundle_id` exists in `world.bundles`
1149    #[inline]
1150    pub(crate) unsafe fn new_with_id(
1151        world: &'w mut World,
1152        bundle_id: BundleId,
1153        change_tick: Tick,
1154    ) -> Self {
1155        let bundle_info = world.bundles.get_unchecked(bundle_id);
1156        let new_archetype_id = bundle_info.add_bundle_to_archetype(
1157            &mut world.archetypes,
1158            &mut world.storages,
1159            &world.components,
1160            &world.observers,
1161            ArchetypeId::EMPTY,
1162        );
1163        let archetype = &mut world.archetypes[new_archetype_id];
1164        let table = &mut world.storages.tables[archetype.table_id()];
1165        Self {
1166            bundle_info: bundle_info.into(),
1167            table: table.into(),
1168            archetype: archetype.into(),
1169            change_tick,
1170            world: world.as_unsafe_world_cell(),
1171        }
1172    }
1173
1174    #[inline]
1175    pub fn reserve_storage(&mut self, additional: usize) {
1176        // SAFETY: There are no outstanding world references
1177        let (archetype, table) = unsafe { (self.archetype.as_mut(), self.table.as_mut()) };
1178        archetype.reserve(additional);
1179        table.reserve(additional);
1180    }
1181
1182    /// # Safety
1183    /// `entity` must be allocated (but non-existent), `T` must match this [`BundleInfo`]'s type
1184    #[inline]
1185    pub unsafe fn spawn_non_existent<T: DynamicBundle>(
1186        &mut self,
1187        entity: Entity,
1188        bundle: T,
1189        #[cfg(feature = "track_change_detection")] caller: &'static Location<'static>,
1190    ) -> EntityLocation {
1191        // SAFETY: We do not make any structural changes to the archetype graph through self.world so these pointers always remain valid
1192        let bundle_info = self.bundle_info.as_ref();
1193        let location = {
1194            let table = self.table.as_mut();
1195            let archetype = self.archetype.as_mut();
1196
1197            // SAFETY: Mutable references do not alias and will be dropped after this block
1198            let (sparse_sets, entities) = {
1199                let world = self.world.world_mut();
1200                (&mut world.storages.sparse_sets, &mut world.entities)
1201            };
1202            let table_row = table.allocate(entity);
1203            let location = archetype.allocate(entity, table_row);
1204            bundle_info.write_components(
1205                table,
1206                sparse_sets,
1207                &SpawnBundleStatus,
1208                bundle_info.required_components.iter(),
1209                entity,
1210                table_row,
1211                self.change_tick,
1212                bundle,
1213                InsertMode::Replace,
1214                #[cfg(feature = "track_change_detection")]
1215                caller,
1216            );
1217            entities.set(entity.index(), location);
1218            location
1219        };
1220
1221        // SAFETY: We have no outstanding mutable references to world as they were dropped
1222        let mut deferred_world = unsafe { self.world.into_deferred() };
1223        // SAFETY: `DeferredWorld` cannot provide mutable access to `Archetypes`.
1224        let archetype = self.archetype.as_ref();
1225        // SAFETY: All components in the bundle are guaranteed to exist in the World
1226        // as they must be initialized before creating the BundleInfo.
1227        unsafe {
1228            deferred_world.trigger_on_add(
1229                archetype,
1230                entity,
1231                bundle_info.iter_contributed_components(),
1232            );
1233            if archetype.has_add_observer() {
1234                deferred_world.trigger_observers(
1235                    ON_ADD,
1236                    entity,
1237                    bundle_info.iter_contributed_components(),
1238                );
1239            }
1240            deferred_world.trigger_on_insert(
1241                archetype,
1242                entity,
1243                bundle_info.iter_contributed_components(),
1244            );
1245            if archetype.has_insert_observer() {
1246                deferred_world.trigger_observers(
1247                    ON_INSERT,
1248                    entity,
1249                    bundle_info.iter_contributed_components(),
1250                );
1251            }
1252        };
1253
1254        location
1255    }
1256
1257    /// # Safety
1258    /// `T` must match this [`BundleInfo`]'s type
1259    #[inline]
1260    pub unsafe fn spawn<T: Bundle>(
1261        &mut self,
1262        bundle: T,
1263        #[cfg(feature = "track_change_detection")] caller: &'static Location<'static>,
1264    ) -> Entity {
1265        let entity = self.entities().alloc();
1266        // SAFETY: entity is allocated (but non-existent), `T` matches this BundleInfo's type
1267        unsafe {
1268            self.spawn_non_existent(
1269                entity,
1270                bundle,
1271                #[cfg(feature = "track_change_detection")]
1272                caller,
1273            );
1274        }
1275        entity
1276    }
1277
1278    #[inline]
1279    pub(crate) fn entities(&mut self) -> &mut Entities {
1280        // SAFETY: No outstanding references to self.world, changes to entities cannot invalidate our internal pointers
1281        unsafe { &mut self.world.world_mut().entities }
1282    }
1283
1284    /// # Safety
1285    /// - `Self` must be dropped after running this function as it may invalidate internal pointers.
1286    #[inline]
1287    pub(crate) unsafe fn flush_commands(&mut self) {
1288        // SAFETY: pointers on self can be invalidated,
1289        self.world.world_mut().flush();
1290    }
1291}
1292
1293/// Metadata for bundles. Stores a [`BundleInfo`] for each type of [`Bundle`] in a given world.
1294#[derive(Default)]
1295pub struct Bundles {
1296    bundle_infos: Vec<BundleInfo>,
1297    /// Cache static [`BundleId`]
1298    bundle_ids: TypeIdMap<BundleId>,
1299    /// Cache bundles, which contains both explicit and required components of [`Bundle`]
1300    contributed_bundle_ids: TypeIdMap<BundleId>,
1301    /// Cache dynamic [`BundleId`] with multiple components
1302    dynamic_bundle_ids: HashMap<Box<[ComponentId]>, BundleId>,
1303    dynamic_bundle_storages: HashMap<BundleId, Vec<StorageType>>,
1304    /// Cache optimized dynamic [`BundleId`] with single component
1305    dynamic_component_bundle_ids: HashMap<ComponentId, BundleId>,
1306    dynamic_component_storages: HashMap<BundleId, StorageType>,
1307}
1308
1309impl Bundles {
1310    /// Gets the metadata associated with a specific type of bundle.
1311    /// Returns `None` if the bundle is not registered with the world.
1312    #[inline]
1313    pub fn get(&self, bundle_id: BundleId) -> Option<&BundleInfo> {
1314        self.bundle_infos.get(bundle_id.index())
1315    }
1316
1317    /// Gets the value identifying a specific type of bundle.
1318    /// Returns `None` if the bundle does not exist in the world,
1319    /// or if `type_id` does not correspond to a type of bundle.
1320    #[inline]
1321    pub fn get_id(&self, type_id: TypeId) -> Option<BundleId> {
1322        self.bundle_ids.get(&type_id).cloned()
1323    }
1324
1325    /// Registers a new [`BundleInfo`] for a statically known type.
1326    ///
1327    /// Also registers all the components in the bundle.
1328    pub(crate) fn register_info<T: Bundle>(
1329        &mut self,
1330        components: &mut Components,
1331        storages: &mut Storages,
1332    ) -> BundleId {
1333        let bundle_infos = &mut self.bundle_infos;
1334        let id = *self.bundle_ids.entry(TypeId::of::<T>()).or_insert_with(|| {
1335            let mut component_ids= Vec::new();
1336            T::component_ids(components, storages, &mut |id| component_ids.push(id));
1337            let id = BundleId(bundle_infos.len());
1338            let bundle_info =
1339                // SAFETY: T::component_id ensures:
1340                // - its info was created
1341                // - appropriate storage for it has been initialized.
1342                // - it was created in the same order as the components in T
1343                unsafe { BundleInfo::new(core::any::type_name::<T>(), components, component_ids, id) };
1344            bundle_infos.push(bundle_info);
1345            id
1346        });
1347        id
1348    }
1349
1350    /// Registers a new [`BundleInfo`], which contains both explicit and required components for a statically known type.
1351    ///
1352    /// Also registers all the components in the bundle.
1353    pub(crate) fn register_contributed_bundle_info<T: Bundle>(
1354        &mut self,
1355        components: &mut Components,
1356        storages: &mut Storages,
1357    ) -> BundleId {
1358        if let Some(id) = self.contributed_bundle_ids.get(&TypeId::of::<T>()).cloned() {
1359            id
1360        } else {
1361            let explicit_bundle_id = self.register_info::<T>(components, storages);
1362            // SAFETY: reading from `explicit_bundle_id` and creating new bundle in same time. Its valid because bundle hashmap allow this
1363            let id = unsafe {
1364                let (ptr, len) = {
1365                    // SAFETY: `explicit_bundle_id` is valid and defined above
1366                    let contributed = self
1367                        .get_unchecked(explicit_bundle_id)
1368                        .contributed_components();
1369                    (contributed.as_ptr(), contributed.len())
1370                };
1371                // SAFETY: this is sound because the contributed_components Vec for explicit_bundle_id will not be accessed mutably as
1372                // part of init_dynamic_info. No mutable references will be created and the allocation will remain valid.
1373                self.init_dynamic_info(components, core::slice::from_raw_parts(ptr, len))
1374            };
1375            self.contributed_bundle_ids.insert(TypeId::of::<T>(), id);
1376            id
1377        }
1378    }
1379
1380    /// # Safety
1381    /// A [`BundleInfo`] with the given [`BundleId`] must have been initialized for this instance of `Bundles`.
1382    pub(crate) unsafe fn get_unchecked(&self, id: BundleId) -> &BundleInfo {
1383        self.bundle_infos.get_unchecked(id.0)
1384    }
1385
1386    /// # Safety
1387    /// This [`BundleId`] must have been initialized with a single [`Component`] (via [`init_component_info`](Self::init_dynamic_info))
1388    pub(crate) unsafe fn get_storage_unchecked(&self, id: BundleId) -> StorageType {
1389        *self
1390            .dynamic_component_storages
1391            .get(&id)
1392            .debug_checked_unwrap()
1393    }
1394
1395    /// # Safety
1396    /// This [`BundleId`] must have been initialized with multiple [`Component`]s (via [`init_dynamic_info`](Self::init_dynamic_info))
1397    pub(crate) unsafe fn get_storages_unchecked(&mut self, id: BundleId) -> &mut Vec<StorageType> {
1398        self.dynamic_bundle_storages
1399            .get_mut(&id)
1400            .debug_checked_unwrap()
1401    }
1402
1403    /// Initializes a new [`BundleInfo`] for a dynamic [`Bundle`].
1404    ///
1405    /// # Panics
1406    ///
1407    /// Panics if any of the provided [`ComponentId`]s do not exist in the
1408    /// provided [`Components`].
1409    pub(crate) fn init_dynamic_info(
1410        &mut self,
1411        components: &Components,
1412        component_ids: &[ComponentId],
1413    ) -> BundleId {
1414        let bundle_infos = &mut self.bundle_infos;
1415
1416        // Use `raw_entry_mut` to avoid cloning `component_ids` to access `Entry`
1417        let (_, bundle_id) = self
1418            .dynamic_bundle_ids
1419            .raw_entry_mut()
1420            .from_key(component_ids)
1421            .or_insert_with(|| {
1422                let (id, storages) =
1423                    initialize_dynamic_bundle(bundle_infos, components, Vec::from(component_ids));
1424                self.dynamic_bundle_storages
1425                    .insert_unique_unchecked(id, storages);
1426                (component_ids.into(), id)
1427            });
1428        *bundle_id
1429    }
1430
1431    /// Initializes a new [`BundleInfo`] for a dynamic [`Bundle`] with single component.
1432    ///
1433    /// # Panics
1434    ///
1435    /// Panics if the provided [`ComponentId`] does not exist in the provided [`Components`].
1436    pub(crate) fn init_component_info(
1437        &mut self,
1438        components: &Components,
1439        component_id: ComponentId,
1440    ) -> BundleId {
1441        let bundle_infos = &mut self.bundle_infos;
1442        let bundle_id = self
1443            .dynamic_component_bundle_ids
1444            .entry(component_id)
1445            .or_insert_with(|| {
1446                let (id, storage_type) =
1447                    initialize_dynamic_bundle(bundle_infos, components, vec![component_id]);
1448                self.dynamic_component_storages.insert(id, storage_type[0]);
1449                id
1450            });
1451        *bundle_id
1452    }
1453}
1454
1455/// Asserts that all components are part of [`Components`]
1456/// and initializes a [`BundleInfo`].
1457fn initialize_dynamic_bundle(
1458    bundle_infos: &mut Vec<BundleInfo>,
1459    components: &Components,
1460    component_ids: Vec<ComponentId>,
1461) -> (BundleId, Vec<StorageType>) {
1462    // Assert component existence
1463    let storage_types = component_ids.iter().map(|&id| {
1464        components.get_info(id).unwrap_or_else(|| {
1465            panic!(
1466                "init_dynamic_info called with component id {id:?} which doesn't exist in this world"
1467            )
1468        }).storage_type()
1469    }).collect();
1470
1471    let id = BundleId(bundle_infos.len());
1472    let bundle_info =
1473        // SAFETY: `component_ids` are valid as they were just checked
1474        unsafe { BundleInfo::new("<dynamic bundle>", components, component_ids, id) };
1475    bundle_infos.push(bundle_info);
1476
1477    (id, storage_types)
1478}
1479
1480#[cfg(test)]
1481mod tests {
1482    use crate as bevy_ecs;
1483    use crate::{component::ComponentId, prelude::*, world::DeferredWorld};
1484
1485    #[derive(Component)]
1486    struct A;
1487
1488    #[derive(Component)]
1489    #[component(on_add = a_on_add, on_insert = a_on_insert, on_replace = a_on_replace, on_remove = a_on_remove)]
1490    struct AMacroHooks;
1491
1492    fn a_on_add(mut world: DeferredWorld, _: Entity, _: ComponentId) {
1493        world.resource_mut::<R>().assert_order(0);
1494    }
1495
1496    fn a_on_insert<T1, T2>(mut world: DeferredWorld, _: T1, _: T2) {
1497        world.resource_mut::<R>().assert_order(1);
1498    }
1499
1500    fn a_on_replace<T1, T2>(mut world: DeferredWorld, _: T1, _: T2) {
1501        world.resource_mut::<R>().assert_order(2);
1502    }
1503
1504    fn a_on_remove<T1, T2>(mut world: DeferredWorld, _: T1, _: T2) {
1505        world.resource_mut::<R>().assert_order(3);
1506    }
1507
1508    #[derive(Component)]
1509    struct B;
1510
1511    #[derive(Component)]
1512    struct C;
1513
1514    #[derive(Component)]
1515    struct D;
1516
1517    #[derive(Component, Eq, PartialEq, Debug)]
1518    struct V(&'static str); // component with a value
1519
1520    #[derive(Resource, Default)]
1521    struct R(usize);
1522
1523    impl R {
1524        #[track_caller]
1525        fn assert_order(&mut self, count: usize) {
1526            assert_eq!(count, self.0);
1527            self.0 += 1;
1528        }
1529    }
1530
1531    #[test]
1532    fn component_hook_order_spawn_despawn() {
1533        let mut world = World::new();
1534        world.init_resource::<R>();
1535        world
1536            .register_component_hooks::<A>()
1537            .on_add(|mut world, _, _| world.resource_mut::<R>().assert_order(0))
1538            .on_insert(|mut world, _, _| world.resource_mut::<R>().assert_order(1))
1539            .on_replace(|mut world, _, _| world.resource_mut::<R>().assert_order(2))
1540            .on_remove(|mut world, _, _| world.resource_mut::<R>().assert_order(3));
1541
1542        let entity = world.spawn(A).id();
1543        world.despawn(entity);
1544        assert_eq!(4, world.resource::<R>().0);
1545    }
1546
1547    #[test]
1548    fn component_hook_order_spawn_despawn_with_macro_hooks() {
1549        let mut world = World::new();
1550        world.init_resource::<R>();
1551
1552        let entity = world.spawn(AMacroHooks).id();
1553        world.despawn(entity);
1554
1555        assert_eq!(4, world.resource::<R>().0);
1556    }
1557
1558    #[test]
1559    fn component_hook_order_insert_remove() {
1560        let mut world = World::new();
1561        world.init_resource::<R>();
1562        world
1563            .register_component_hooks::<A>()
1564            .on_add(|mut world, _, _| world.resource_mut::<R>().assert_order(0))
1565            .on_insert(|mut world, _, _| world.resource_mut::<R>().assert_order(1))
1566            .on_replace(|mut world, _, _| world.resource_mut::<R>().assert_order(2))
1567            .on_remove(|mut world, _, _| world.resource_mut::<R>().assert_order(3));
1568
1569        let mut entity = world.spawn_empty();
1570        entity.insert(A);
1571        entity.remove::<A>();
1572        entity.flush();
1573        assert_eq!(4, world.resource::<R>().0);
1574    }
1575
1576    #[test]
1577    fn component_hook_order_replace() {
1578        let mut world = World::new();
1579        world
1580            .register_component_hooks::<A>()
1581            .on_replace(|mut world, _, _| world.resource_mut::<R>().assert_order(0))
1582            .on_insert(|mut world, _, _| {
1583                if let Some(mut r) = world.get_resource_mut::<R>() {
1584                    r.assert_order(1);
1585                }
1586            });
1587
1588        let entity = world.spawn(A).id();
1589        world.init_resource::<R>();
1590        let mut entity = world.entity_mut(entity);
1591        entity.insert(A);
1592        entity.insert_if_new(A); // this will not trigger on_replace or on_insert
1593        entity.flush();
1594        assert_eq!(2, world.resource::<R>().0);
1595    }
1596
1597    #[test]
1598    fn component_hook_order_recursive() {
1599        let mut world = World::new();
1600        world.init_resource::<R>();
1601        world
1602            .register_component_hooks::<A>()
1603            .on_add(|mut world, entity, _| {
1604                world.resource_mut::<R>().assert_order(0);
1605                world.commands().entity(entity).insert(B);
1606            })
1607            .on_remove(|mut world, entity, _| {
1608                world.resource_mut::<R>().assert_order(2);
1609                world.commands().entity(entity).remove::<B>();
1610            });
1611
1612        world
1613            .register_component_hooks::<B>()
1614            .on_add(|mut world, entity, _| {
1615                world.resource_mut::<R>().assert_order(1);
1616                world.commands().entity(entity).remove::<A>();
1617            })
1618            .on_remove(|mut world, _, _| {
1619                world.resource_mut::<R>().assert_order(3);
1620            });
1621
1622        let entity = world.spawn(A).flush();
1623        let entity = world.get_entity(entity).unwrap();
1624        assert!(!entity.contains::<A>());
1625        assert!(!entity.contains::<B>());
1626        assert_eq!(4, world.resource::<R>().0);
1627    }
1628
1629    #[test]
1630    fn component_hook_order_recursive_multiple() {
1631        let mut world = World::new();
1632        world.init_resource::<R>();
1633        world
1634            .register_component_hooks::<A>()
1635            .on_add(|mut world, entity, _| {
1636                world.resource_mut::<R>().assert_order(0);
1637                world.commands().entity(entity).insert(B).insert(C);
1638            });
1639
1640        world
1641            .register_component_hooks::<B>()
1642            .on_add(|mut world, entity, _| {
1643                world.resource_mut::<R>().assert_order(1);
1644                world.commands().entity(entity).insert(D);
1645            });
1646
1647        world
1648            .register_component_hooks::<C>()
1649            .on_add(|mut world, _, _| {
1650                world.resource_mut::<R>().assert_order(3);
1651            });
1652
1653        world
1654            .register_component_hooks::<D>()
1655            .on_add(|mut world, _, _| {
1656                world.resource_mut::<R>().assert_order(2);
1657            });
1658
1659        world.spawn(A).flush();
1660        assert_eq!(4, world.resource::<R>().0);
1661    }
1662
1663    #[test]
1664    fn insert_if_new() {
1665        let mut world = World::new();
1666        let id = world.spawn(V("one")).id();
1667        let mut entity = world.entity_mut(id);
1668        entity.insert_if_new(V("two"));
1669        entity.insert_if_new((A, V("three")));
1670        entity.flush();
1671        // should still contain "one"
1672        let entity = world.entity(id);
1673        assert!(entity.contains::<A>());
1674        assert_eq!(entity.get(), Some(&V("one")));
1675    }
1676}