bevy_ecs/bundle/
info.rs

1use alloc::{boxed::Box, vec, vec::Vec};
2use bevy_platform::{
3    collections::{HashMap, HashSet},
4    hash::FixedHasher,
5};
6use bevy_ptr::{MovingPtr, OwningPtr};
7use bevy_utils::TypeIdMap;
8use core::{any::TypeId, ptr::NonNull};
9use indexmap::{IndexMap, IndexSet};
10
11use crate::{
12    archetype::{Archetype, BundleComponentStatus, ComponentStatus},
13    bundle::{Bundle, DynamicBundle},
14    change_detection::MaybeLocation,
15    component::{
16        ComponentId, Components, ComponentsRegistrator, RequiredComponentConstructor, StorageType,
17        Tick,
18    },
19    entity::Entity,
20    query::DebugCheckedUnwrap as _,
21    storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
22};
23
24/// For a specific [`World`], this stores a unique value identifying a type of a registered [`Bundle`].
25///
26/// [`World`]: crate::world::World
27#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
28pub struct BundleId(usize);
29
30impl BundleId {
31    /// Returns the index of the associated [`Bundle`] type.
32    ///
33    /// Note that this is unique per-world, and should not be reused across them.
34    #[inline]
35    pub fn index(self) -> usize {
36        self.0
37    }
38}
39
40impl SparseSetIndex for BundleId {
41    #[inline]
42    fn sparse_set_index(&self) -> usize {
43        self.index()
44    }
45
46    #[inline]
47    fn get_sparse_set_index(value: usize) -> Self {
48        Self(value)
49    }
50}
51
52/// What to do on insertion if a component already exists.
53#[derive(Clone, Copy, Eq, PartialEq)]
54pub enum InsertMode {
55    /// Any existing components of a matching type will be overwritten.
56    Replace,
57    /// Any existing components of a matching type will be left unchanged.
58    Keep,
59}
60
61/// Stores metadata associated with a specific type of [`Bundle`] for a given [`World`].
62///
63/// [`World`]: crate::world::World
64pub struct BundleInfo {
65    pub(super) id: BundleId,
66
67    /// The list of all components contributed by the bundle (including Required Components). This is in
68    /// the order `[EXPLICIT_COMPONENTS][REQUIRED_COMPONENTS]`
69    ///
70    /// # Safety
71    /// Every ID in this list must be valid within the World that owns the [`BundleInfo`],
72    /// must have its storage initialized (i.e. columns created in tables, sparse set created),
73    /// and the range (0..`explicit_components_len`) must be in the same order as the source bundle
74    /// type writes its components in.
75    pub(super) contributed_component_ids: Box<[ComponentId]>,
76
77    /// The list of constructors for all required components indirectly contributed by this bundle.
78    pub(super) required_component_constructors: Box<[RequiredComponentConstructor]>,
79}
80
81impl BundleInfo {
82    /// Create a new [`BundleInfo`].
83    ///
84    /// # Safety
85    ///
86    /// Every ID in `component_ids` must be valid within the World that owns the `BundleInfo`
87    /// and must be in the same order as the source bundle type writes its components in.
88    unsafe fn new(
89        bundle_type_name: &'static str,
90        storages: &mut Storages,
91        components: &Components,
92        mut component_ids: Vec<ComponentId>,
93        id: BundleId,
94    ) -> BundleInfo {
95        let explicit_component_ids = component_ids
96            .iter()
97            .copied()
98            .collect::<IndexSet<_, FixedHasher>>();
99
100        // check for duplicates
101        if explicit_component_ids.len() != component_ids.len() {
102            // TODO: Replace with `Vec::partition_dedup` once https://github.com/rust-lang/rust/issues/54279 is stabilized
103            let mut seen = <HashSet<_>>::default();
104            let mut dups = Vec::new();
105            for id in component_ids {
106                if !seen.insert(id) {
107                    dups.push(id);
108                }
109            }
110
111            let names = dups
112                .into_iter()
113                .map(|id| {
114                    // SAFETY: the caller ensures component_id is valid.
115                    unsafe { components.get_info_unchecked(id).name() }
116                })
117                .collect::<Vec<_>>();
118
119            panic!("Bundle {bundle_type_name} has duplicate components: {names:?}");
120        }
121
122        let mut depth_first_components = IndexMap::<_, _, FixedHasher>::default();
123        for &component_id in &component_ids {
124            // SAFETY: caller has verified that all ids are valid
125            let info = unsafe { components.get_info_unchecked(component_id) };
126
127            for (&required_id, required_component) in &info.required_components().all {
128                depth_first_components
129                    .entry(required_id)
130                    .or_insert_with(|| required_component.clone());
131            }
132
133            storages.prepare_component(info);
134        }
135
136        let required_components = depth_first_components
137            .into_iter()
138            .filter(|&(required_id, _)| !explicit_component_ids.contains(&required_id))
139            .inspect(|&(required_id, _)| {
140                // SAFETY: These ids came out of the passed `components`, so they must be valid.
141                storages.prepare_component(unsafe { components.get_info_unchecked(required_id) });
142                component_ids.push(required_id);
143            })
144            .map(|(_, required_component)| required_component.constructor)
145            .collect::<Box<_>>();
146
147        // SAFETY: The caller ensures that component_ids:
148        // - is valid for the associated world
149        // - has had its storage initialized
150        // - is in the same order as the source bundle type
151        BundleInfo {
152            id,
153            contributed_component_ids: component_ids.into(),
154            required_component_constructors: required_components,
155        }
156    }
157
158    /// Returns a value identifying the associated [`Bundle`] type.
159    #[inline]
160    pub const fn id(&self) -> BundleId {
161        self.id
162    }
163
164    /// Returns the length of the explicit components part of the [`contributed_components`](Self::contributed_components) list.
165    #[inline]
166    pub(super) fn explicit_components_len(&self) -> usize {
167        self.contributed_component_ids.len() - self.required_component_constructors.len()
168    }
169
170    /// Returns the [ID](ComponentId) of each component explicitly defined in this bundle (ex: Required Components are excluded).
171    ///
172    /// For all components contributed by this bundle (including Required Components), see [`BundleInfo::contributed_components`]
173    #[inline]
174    pub fn explicit_components(&self) -> &[ComponentId] {
175        &self.contributed_component_ids[0..self.explicit_components_len()]
176    }
177
178    /// Returns the [ID](ComponentId) of each Required Component needed by this bundle. This _does not include_ Required Components that are
179    /// explicitly provided by the bundle.
180    #[inline]
181    pub fn required_components(&self) -> &[ComponentId] {
182        &self.contributed_component_ids[self.explicit_components_len()..]
183    }
184
185    /// Returns the [ID](ComponentId) of each component contributed by this bundle. This includes Required Components.
186    ///
187    /// For only components explicitly defined in this bundle, see [`BundleInfo::explicit_components`]
188    #[inline]
189    pub fn contributed_components(&self) -> &[ComponentId] {
190        &self.contributed_component_ids
191    }
192
193    /// Returns an iterator over the [ID](ComponentId) of each component explicitly defined in this bundle (ex: this excludes Required Components).
194    /// To iterate all components contributed by this bundle (including Required Components), see [`BundleInfo::iter_contributed_components`]
195    #[inline]
196    pub fn iter_explicit_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
197        self.explicit_components().iter().copied()
198    }
199
200    /// Returns an iterator over the [ID](ComponentId) of each component contributed by this bundle. This includes Required Components.
201    ///
202    /// To iterate only components explicitly defined in this bundle, see [`BundleInfo::iter_explicit_components`]
203    #[inline]
204    pub fn iter_contributed_components(&self) -> impl Iterator<Item = ComponentId> + Clone + '_ {
205        self.contributed_components().iter().copied()
206    }
207
208    /// Returns an iterator over the [ID](ComponentId) of each Required Component needed by this bundle. This _does not include_ Required Components that are
209    /// explicitly provided by the bundle.
210    pub fn iter_required_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
211        self.required_components().iter().copied()
212    }
213
214    /// This writes components from a given [`Bundle`] to the given entity.
215    ///
216    /// # Safety
217    ///
218    /// `bundle_component_status` must return the "correct" [`ComponentStatus`] for each component
219    /// in the [`Bundle`], with respect to the entity's original archetype (prior to the bundle being added).
220    ///
221    /// For example, if the original archetype already has `ComponentA` and `T` also has `ComponentA`, the status
222    /// should be `Existing`. If the original archetype does not have `ComponentA`, the status should be `Added`.
223    ///
224    /// When "inserting" a bundle into an existing entity, [`ArchetypeAfterBundleInsert`](crate::archetype::SpawnBundleStatus)
225    /// should be used, which will report `Added` vs `Existing` status based on the current archetype's structure.
226    ///
227    /// When spawning a bundle, [`SpawnBundleStatus`](crate::archetype::SpawnBundleStatus) can be used instead,
228    /// which removes the need to look up the [`ArchetypeAfterBundleInsert`](crate::archetype::ArchetypeAfterBundleInsert)
229    /// in the archetype graph, which requires ownership of the entity's current archetype.
230    ///
231    /// Regardless of how this is used, [`apply_effect`] must be called at most once on `bundle` after this function is
232    /// called if `T::Effect: !NoBundleEffect` before returning to user-space safe code before returning to user-space safe code.
233    /// This is currently only doable via use of [`MovingPtr::partial_move`].
234    ///
235    /// `table` must be the "new" table for `entity`. `table_row` must have space allocated for the
236    /// `entity`, `bundle` must match this [`BundleInfo`]'s type
237    ///
238    /// [`apply_effect`]: crate::bundle::DynamicBundle::apply_effect
239    #[inline]
240    pub(super) unsafe fn write_components<'a, T: DynamicBundle, S: BundleComponentStatus>(
241        &self,
242        table: &mut Table,
243        sparse_sets: &mut SparseSets,
244        bundle_component_status: &S,
245        required_components: impl Iterator<Item = &'a RequiredComponentConstructor>,
246        entity: Entity,
247        table_row: TableRow,
248        change_tick: Tick,
249        bundle: MovingPtr<'_, T>,
250        insert_mode: InsertMode,
251        caller: MaybeLocation,
252    ) {
253        // NOTE: get_components calls this closure on each component in "bundle order".
254        // bundle_info.component_ids are also in "bundle order"
255        let mut bundle_component = 0;
256        T::get_components(bundle, &mut |storage_type, component_ptr| {
257            let component_id = *self
258                .contributed_component_ids
259                .get_unchecked(bundle_component);
260            // SAFETY: bundle_component is a valid index for this bundle
261            let status = unsafe { bundle_component_status.get_status(bundle_component) };
262            match storage_type {
263                StorageType::Table => {
264                    let column =
265                        // SAFETY: If component_id is in self.component_ids, BundleInfo::new ensures that
266                        // the target table contains the component.
267                        unsafe { table.get_column_mut(component_id).debug_checked_unwrap() };
268                    match (status, insert_mode) {
269                        (ComponentStatus::Added, _) => {
270                            column.initialize(table_row, component_ptr, change_tick, caller);
271                        }
272                        (ComponentStatus::Existing, InsertMode::Replace) => {
273                            column.replace(table_row, component_ptr, change_tick, caller);
274                        }
275                        (ComponentStatus::Existing, InsertMode::Keep) => {
276                            if let Some(drop_fn) = table.get_drop_for(component_id) {
277                                drop_fn(component_ptr);
278                            }
279                        }
280                    }
281                }
282                StorageType::SparseSet => {
283                    let sparse_set =
284                        // SAFETY: If component_id is in self.component_ids, BundleInfo::new ensures that
285                        // a sparse set exists for the component.
286                        unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
287                    match (status, insert_mode) {
288                        (ComponentStatus::Added, _) | (_, InsertMode::Replace) => {
289                            sparse_set.insert(entity, component_ptr, change_tick, caller);
290                        }
291                        (ComponentStatus::Existing, InsertMode::Keep) => {
292                            if let Some(drop_fn) = sparse_set.get_drop() {
293                                drop_fn(component_ptr);
294                            }
295                        }
296                    }
297                }
298            }
299            bundle_component += 1;
300        });
301
302        for required_component in required_components {
303            required_component.initialize(
304                table,
305                sparse_sets,
306                change_tick,
307                table_row,
308                entity,
309                caller,
310            );
311        }
312    }
313
314    /// Internal method to initialize a required component from an [`OwningPtr`]. This should ultimately be called
315    /// in the context of [`BundleInfo::write_components`], via [`RequiredComponentConstructor::initialize`].
316    ///
317    /// # Safety
318    ///
319    /// `component_ptr` must point to a required component value that matches the given `component_id`. The `storage_type` must match
320    /// the type associated with `component_id`. The `entity` and `table_row` must correspond to an entity with an uninitialized
321    /// component matching `component_id`.
322    ///
323    /// This method _should not_ be called outside of [`BundleInfo::write_components`].
324    /// For more information, read the [`BundleInfo::write_components`] safety docs.
325    /// This function inherits the safety requirements defined there.
326    pub(crate) unsafe fn initialize_required_component(
327        table: &mut Table,
328        sparse_sets: &mut SparseSets,
329        change_tick: Tick,
330        table_row: TableRow,
331        entity: Entity,
332        component_id: ComponentId,
333        storage_type: StorageType,
334        component_ptr: OwningPtr,
335        caller: MaybeLocation,
336    ) {
337        {
338            match storage_type {
339                StorageType::Table => {
340                    let column =
341                        // SAFETY: If component_id is in required_components, BundleInfo::new requires that
342                        // the target table contains the component.
343                        unsafe { table.get_column_mut(component_id).debug_checked_unwrap() };
344                    column.initialize(table_row, component_ptr, change_tick, caller);
345                }
346                StorageType::SparseSet => {
347                    let sparse_set =
348                        // SAFETY: If component_id is in required_components, BundleInfo::new requires that
349                        // a sparse set exists for the component.
350                        unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
351                    sparse_set.insert(entity, component_ptr, change_tick, caller);
352                }
353            }
354        }
355    }
356}
357
358/// The type of archetype move (or lack thereof) that will result from a bundle
359/// being inserted into an entity.
360pub(crate) enum ArchetypeMoveType {
361    /// If the entity already has all of the components that are being inserted,
362    /// its archetype won't change.
363    SameArchetype,
364    /// If only [`sparse set`](StorageType::SparseSet) components are being added,
365    /// the entity's archetype will change while keeping the same table.
366    NewArchetypeSameTable { new_archetype: NonNull<Archetype> },
367    /// If any [`table-stored`](StorageType::Table) components are being added,
368    /// both the entity's archetype and table will change.
369    NewArchetypeNewTable {
370        new_archetype: NonNull<Archetype>,
371        new_table: NonNull<Table>,
372    },
373}
374
375/// Metadata for bundles. Stores a [`BundleInfo`] for each type of [`Bundle`] in a given world.
376#[derive(Default)]
377pub struct Bundles {
378    bundle_infos: Vec<BundleInfo>,
379    /// Cache static [`BundleId`]
380    bundle_ids: TypeIdMap<BundleId>,
381    /// Cache bundles, which contains both explicit and required components of [`Bundle`]
382    contributed_bundle_ids: TypeIdMap<BundleId>,
383    /// Cache dynamic [`BundleId`] with multiple components
384    dynamic_bundle_ids: HashMap<Box<[ComponentId]>, BundleId>,
385    dynamic_bundle_storages: HashMap<BundleId, Vec<StorageType>>,
386    /// Cache optimized dynamic [`BundleId`] with single component
387    dynamic_component_bundle_ids: HashMap<ComponentId, BundleId>,
388    dynamic_component_storages: HashMap<BundleId, StorageType>,
389}
390
391impl Bundles {
392    /// The total number of [`Bundle`] registered in [`Storages`].
393    pub fn len(&self) -> usize {
394        self.bundle_infos.len()
395    }
396
397    /// Returns true if no [`Bundle`] registered in [`Storages`].
398    pub fn is_empty(&self) -> bool {
399        self.len() == 0
400    }
401
402    /// Iterate over [`BundleInfo`].
403    pub fn iter(&self) -> impl Iterator<Item = &BundleInfo> {
404        self.bundle_infos.iter()
405    }
406
407    /// Gets the metadata associated with a specific type of bundle.
408    /// Returns `None` if the bundle is not registered with the world.
409    #[inline]
410    pub fn get(&self, bundle_id: BundleId) -> Option<&BundleInfo> {
411        self.bundle_infos.get(bundle_id.index())
412    }
413
414    /// Gets the value identifying a specific type of bundle.
415    /// Returns `None` if the bundle does not exist in the world,
416    /// or if `type_id` does not correspond to a type of bundle.
417    #[inline]
418    pub fn get_id(&self, type_id: TypeId) -> Option<BundleId> {
419        self.bundle_ids.get(&type_id).cloned()
420    }
421
422    /// Registers a new [`BundleInfo`] for a statically known type.
423    ///
424    /// Also registers all the components in the bundle.
425    ///
426    /// # Safety
427    ///
428    /// `components` and `storages` must be from the same [`World`] as `self`.
429    ///
430    /// [`World`]: crate::world::World
431    #[deny(unsafe_op_in_unsafe_fn)]
432    pub(crate) unsafe fn register_info<T: Bundle>(
433        &mut self,
434        components: &mut ComponentsRegistrator,
435        storages: &mut Storages,
436    ) -> BundleId {
437        let bundle_infos = &mut self.bundle_infos;
438        *self.bundle_ids.entry(TypeId::of::<T>()).or_insert_with(|| {
439            let mut component_ids= Vec::new();
440            T::component_ids(components, &mut |id| component_ids.push(id));
441            let id = BundleId(bundle_infos.len());
442            let bundle_info =
443                // SAFETY: T::component_id ensures:
444                // - its info was created
445                // - appropriate storage for it has been initialized.
446                // - it was created in the same order as the components in T
447                unsafe { BundleInfo::new(core::any::type_name::<T>(), storages, components, component_ids, id) };
448            bundle_infos.push(bundle_info);
449            id
450        })
451    }
452
453    /// Registers a new [`BundleInfo`], which contains both explicit and required components for a statically known type.
454    ///
455    /// Also registers all the components in the bundle.
456    ///
457    /// # Safety
458    ///
459    /// `components` and `storages` must be from the same [`World`] as `self`.
460    ///
461    /// [`World`]: crate::world::World
462    #[deny(unsafe_op_in_unsafe_fn)]
463    pub(crate) unsafe fn register_contributed_bundle_info<T: Bundle>(
464        &mut self,
465        components: &mut ComponentsRegistrator,
466        storages: &mut Storages,
467    ) -> BundleId {
468        if let Some(id) = self.contributed_bundle_ids.get(&TypeId::of::<T>()).cloned() {
469            id
470        } else {
471            // SAFETY: as per the guarantees of this function, components and
472            // storages are from the same world as self
473            let explicit_bundle_id = unsafe { self.register_info::<T>(components, storages) };
474
475            // SAFETY: reading from `explicit_bundle_id` and creating new bundle in same time. Its valid because bundle hashmap allow this
476            let id = unsafe {
477                let (ptr, len) = {
478                    // SAFETY: `explicit_bundle_id` is valid and defined above
479                    let contributed = self
480                        .get_unchecked(explicit_bundle_id)
481                        .contributed_components();
482                    (contributed.as_ptr(), contributed.len())
483                };
484                // SAFETY: this is sound because the contributed_components Vec for explicit_bundle_id will not be accessed mutably as
485                // part of init_dynamic_info. No mutable references will be created and the allocation will remain valid.
486                self.init_dynamic_info(storages, components, core::slice::from_raw_parts(ptr, len))
487            };
488            self.contributed_bundle_ids.insert(TypeId::of::<T>(), id);
489            id
490        }
491    }
492
493    /// # Safety
494    /// A [`BundleInfo`] with the given [`BundleId`] must have been initialized for this instance of `Bundles`.
495    pub(crate) unsafe fn get_unchecked(&self, id: BundleId) -> &BundleInfo {
496        self.bundle_infos.get_unchecked(id.0)
497    }
498
499    /// # Safety
500    /// This [`BundleId`] must have been initialized with a single [`Component`](crate::component::Component)
501    /// (via [`init_component_info`](Self::init_dynamic_info))
502    pub(crate) unsafe fn get_storage_unchecked(&self, id: BundleId) -> StorageType {
503        *self
504            .dynamic_component_storages
505            .get(&id)
506            .debug_checked_unwrap()
507    }
508
509    /// # Safety
510    /// This [`BundleId`] must have been initialized with multiple [`Component`](crate::component::Component)s
511    /// (via [`init_dynamic_info`](Self::init_dynamic_info))
512    pub(crate) unsafe fn get_storages_unchecked(&mut self, id: BundleId) -> &mut Vec<StorageType> {
513        self.dynamic_bundle_storages
514            .get_mut(&id)
515            .debug_checked_unwrap()
516    }
517
518    /// Initializes a new [`BundleInfo`] for a dynamic [`Bundle`].
519    ///
520    /// # Panics
521    ///
522    /// Panics if any of the provided [`ComponentId`]s do not exist in the
523    /// provided [`Components`].
524    pub(crate) fn init_dynamic_info(
525        &mut self,
526        storages: &mut Storages,
527        components: &Components,
528        component_ids: &[ComponentId],
529    ) -> BundleId {
530        let bundle_infos = &mut self.bundle_infos;
531
532        // Use `raw_entry_mut` to avoid cloning `component_ids` to access `Entry`
533        let (_, bundle_id) = self
534            .dynamic_bundle_ids
535            .raw_entry_mut()
536            .from_key(component_ids)
537            .or_insert_with(|| {
538                let (id, storages) = initialize_dynamic_bundle(
539                    bundle_infos,
540                    storages,
541                    components,
542                    Vec::from(component_ids),
543                );
544                // SAFETY: The ID always increases when new bundles are added, and so, the ID is unique.
545                unsafe {
546                    self.dynamic_bundle_storages
547                        .insert_unique_unchecked(id, storages);
548                }
549                (component_ids.into(), id)
550            });
551        *bundle_id
552    }
553
554    /// Initializes a new [`BundleInfo`] for a dynamic [`Bundle`] with single component.
555    ///
556    /// # Panics
557    ///
558    /// Panics if the provided [`ComponentId`] does not exist in the provided [`Components`].
559    pub(crate) fn init_component_info(
560        &mut self,
561        storages: &mut Storages,
562        components: &Components,
563        component_id: ComponentId,
564    ) -> BundleId {
565        let bundle_infos = &mut self.bundle_infos;
566        let bundle_id = self
567            .dynamic_component_bundle_ids
568            .entry(component_id)
569            .or_insert_with(|| {
570                let (id, storage_type) = initialize_dynamic_bundle(
571                    bundle_infos,
572                    storages,
573                    components,
574                    vec![component_id],
575                );
576                self.dynamic_component_storages.insert(id, storage_type[0]);
577                id
578            });
579        *bundle_id
580    }
581}
582
583/// Asserts that all components are part of [`Components`]
584/// and initializes a [`BundleInfo`].
585fn initialize_dynamic_bundle(
586    bundle_infos: &mut Vec<BundleInfo>,
587    storages: &mut Storages,
588    components: &Components,
589    component_ids: Vec<ComponentId>,
590) -> (BundleId, Vec<StorageType>) {
591    // Assert component existence
592    let storage_types = component_ids.iter().map(|&id| {
593        components.get_info(id).unwrap_or_else(|| {
594            panic!(
595                "init_dynamic_info called with component id {id:?} which doesn't exist in this world"
596            )
597        }).storage_type()
598    }).collect();
599
600    let id = BundleId(bundle_infos.len());
601    let bundle_info =
602        // SAFETY: `component_ids` are valid as they were just checked
603        unsafe { BundleInfo::new("<dynamic bundle>", storages, components, component_ids, id) };
604    bundle_infos.push(bundle_info);
605
606    (id, storage_types)
607}