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}