use alloc::{borrow::Cow, vec::Vec};1use bevy_platform::{hash::FixedHasher, sync::PoisonError};2use bevy_ptr::OwningPtr;3#[cfg(feature = "bevy_reflect")]4use bevy_reflect::Reflect;5use bevy_utils::{prelude::DebugName, TypeIdMap};6use core::{7alloc::Layout,8any::{Any, TypeId},9fmt::Debug,10mem::needs_drop,11};12use indexmap::IndexSet;1314use crate::{15archetype::ArchetypeFlags,16component::{17Component, ComponentCloneBehavior, ComponentMutability, QueuedComponents,18RequiredComponents, StorageType,19},20lifecycle::ComponentHooks,21query::DebugCheckedUnwrap as _,22resource::Resource,23storage::SparseSetIndex,24};2526/// Stores metadata for a type of component or resource stored in a specific [`World`](crate::world::World).27#[derive(Debug, Clone)]28pub struct ComponentInfo {29pub(super) id: ComponentId,30pub(super) descriptor: ComponentDescriptor,31pub(super) hooks: ComponentHooks,32pub(super) required_components: RequiredComponents,33/// The set of components that require this components.34/// Invariant: components in this set always appear after the components that they require.35pub(super) required_by: IndexSet<ComponentId, FixedHasher>,36}3738impl ComponentInfo {39/// Returns a value uniquely identifying the current component.40#[inline]41pub fn id(&self) -> ComponentId {42self.id43}4445/// Returns the name of the current component.46#[inline]47pub fn name(&self) -> DebugName {48self.descriptor.name.clone()49}5051/// Returns `true` if the current component is mutable.52#[inline]53pub fn mutable(&self) -> bool {54self.descriptor.mutable55}5657/// Returns [`ComponentCloneBehavior`] of the current component.58#[inline]59pub fn clone_behavior(&self) -> &ComponentCloneBehavior {60&self.descriptor.clone_behavior61}6263/// Returns the [`TypeId`] of the underlying component type.64/// Returns `None` if the component does not correspond to a Rust type.65#[inline]66pub fn type_id(&self) -> Option<TypeId> {67self.descriptor.type_id68}6970/// Returns the layout used to store values of this component in memory.71#[inline]72pub fn layout(&self) -> Layout {73self.descriptor.layout74}7576#[inline]77/// Get the function which should be called to clean up values of78/// the underlying component type. This maps to the79/// [`Drop`] implementation for 'normal' Rust components80///81/// Returns `None` if values of the underlying component type don't82/// need to be dropped, e.g. as reported by [`needs_drop`].83pub fn drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {84self.descriptor.drop85}8687/// Returns a value indicating the storage strategy for the current component.88#[inline]89pub fn storage_type(&self) -> StorageType {90self.descriptor.storage_type91}9293/// Returns `true` if the underlying component type can be freely shared between threads.94/// If this returns `false`, then extra care must be taken to ensure that components95/// are not accessed from the wrong thread.96#[inline]97pub fn is_send_and_sync(&self) -> bool {98self.descriptor.is_send_and_sync99}100101/// Create a new [`ComponentInfo`].102pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self {103ComponentInfo {104id,105descriptor,106hooks: Default::default(),107required_components: Default::default(),108required_by: Default::default(),109}110}111112/// Update the given flags to include any [`ComponentHook`](crate::component::ComponentHook) registered to self113#[inline]114pub(crate) fn update_archetype_flags(&self, flags: &mut ArchetypeFlags) {115if self.hooks().on_add.is_some() {116flags.insert(ArchetypeFlags::ON_ADD_HOOK);117}118if self.hooks().on_insert.is_some() {119flags.insert(ArchetypeFlags::ON_INSERT_HOOK);120}121if self.hooks().on_replace.is_some() {122flags.insert(ArchetypeFlags::ON_REPLACE_HOOK);123}124if self.hooks().on_remove.is_some() {125flags.insert(ArchetypeFlags::ON_REMOVE_HOOK);126}127if self.hooks().on_despawn.is_some() {128flags.insert(ArchetypeFlags::ON_DESPAWN_HOOK);129}130}131132/// Provides a reference to the collection of hooks associated with this [`Component`]133pub fn hooks(&self) -> &ComponentHooks {134&self.hooks135}136137/// Retrieves the [`RequiredComponents`] collection, which contains all required components (and their constructors)138/// needed by this component. This includes _recursive_ required components.139pub fn required_components(&self) -> &RequiredComponents {140&self.required_components141}142}143144/// A value which uniquely identifies the type of a [`Component`] or [`Resource`] within a145/// [`World`](crate::world::World).146///147/// Each time a new `Component` type is registered within a `World` using148/// e.g. [`World::register_component`](crate::world::World::register_component) or149/// [`World::register_component_with_descriptor`](crate::world::World::register_component_with_descriptor)150/// or a Resource with e.g. [`World::init_resource`](crate::world::World::init_resource),151/// a corresponding `ComponentId` is created to track it.152///153/// While the distinction between `ComponentId` and [`TypeId`] may seem superficial, breaking them154/// into two separate but related concepts allows components to exist outside of Rust's type system.155/// Each Rust type registered as a `Component` will have a corresponding `ComponentId`, but additional156/// `ComponentId`s may exist in a `World` to track components which cannot be157/// represented as Rust types for scripting or other advanced use-cases.158///159/// A `ComponentId` is tightly coupled to its parent `World`. Attempting to use a `ComponentId` from160/// one `World` to access the metadata of a `Component` in a different `World` is undefined behavior161/// and must not be attempted.162///163/// Given a type `T` which implements [`Component`], the `ComponentId` for `T` can be retrieved164/// from a `World` using [`World::component_id()`](crate::world::World::component_id) or via [`Components::component_id()`].165/// Access to the `ComponentId` for a [`Resource`] is available via [`Components::resource_id()`].166#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]167#[cfg_attr(168feature = "bevy_reflect",169derive(Reflect),170reflect(Debug, Hash, PartialEq, Clone)171)]172pub struct ComponentId(pub(super) usize);173174impl ComponentId {175/// Creates a new [`ComponentId`].176///177/// The `index` is a unique value associated with each type of component in a given world.178/// Usually, this value is taken from a counter incremented for each type of component registered with the world.179#[inline]180pub const fn new(index: usize) -> ComponentId {181ComponentId(index)182}183184/// Returns the index of the current component.185#[inline]186pub fn index(self) -> usize {187self.0188}189}190191impl SparseSetIndex for ComponentId {192#[inline]193fn sparse_set_index(&self) -> usize {194self.index()195}196197#[inline]198fn get_sparse_set_index(value: usize) -> Self {199Self(value)200}201}202203/// A value describing a component or resource, which may or may not correspond to a Rust type.204#[derive(Clone)]205pub struct ComponentDescriptor {206name: DebugName,207// SAFETY: This must remain private. It must match the statically known StorageType of the208// associated rust component type if one exists.209storage_type: StorageType,210// SAFETY: This must remain private. It must only be set to "true" if this component is211// actually Send + Sync212is_send_and_sync: bool,213type_id: Option<TypeId>,214layout: Layout,215// SAFETY: this function must be safe to call with pointers pointing to items of the type216// this descriptor describes.217// None if the underlying type doesn't need to be dropped218drop: Option<for<'a> unsafe fn(OwningPtr<'a>)>,219mutable: bool,220clone_behavior: ComponentCloneBehavior,221}222223// We need to ignore the `drop` field in our `Debug` impl224impl Debug for ComponentDescriptor {225fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {226f.debug_struct("ComponentDescriptor")227.field("name", &self.name)228.field("storage_type", &self.storage_type)229.field("is_send_and_sync", &self.is_send_and_sync)230.field("type_id", &self.type_id)231.field("layout", &self.layout)232.field("mutable", &self.mutable)233.field("clone_behavior", &self.clone_behavior)234.finish()235}236}237238impl ComponentDescriptor {239/// # Safety240///241/// `x` must point to a valid value of type `T`.242unsafe fn drop_ptr<T>(x: OwningPtr<'_>) {243// SAFETY: Contract is required to be upheld by the caller.244unsafe {245x.drop_as::<T>();246}247}248249/// Create a new `ComponentDescriptor` for the type `T`.250pub fn new<T: Component>() -> Self {251Self {252name: DebugName::type_name::<T>(),253storage_type: T::STORAGE_TYPE,254is_send_and_sync: true,255type_id: Some(TypeId::of::<T>()),256layout: Layout::new::<T>(),257drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),258mutable: T::Mutability::MUTABLE,259clone_behavior: T::clone_behavior(),260}261}262263/// Create a new `ComponentDescriptor`.264///265/// # Safety266/// - the `drop` fn must be usable on a pointer with a value of the layout `layout`267/// - the component type must be safe to access from any thread (Send + Sync in rust terms)268pub unsafe fn new_with_layout(269name: impl Into<Cow<'static, str>>,270storage_type: StorageType,271layout: Layout,272drop: Option<for<'a> unsafe fn(OwningPtr<'a>)>,273mutable: bool,274clone_behavior: ComponentCloneBehavior,275) -> Self {276Self {277name: name.into().into(),278storage_type,279is_send_and_sync: true,280type_id: None,281layout,282drop,283mutable,284clone_behavior,285}286}287288/// Create a new `ComponentDescriptor` for a resource.289///290/// The [`StorageType`] for resources is always [`StorageType::Table`].291pub fn new_resource<T: Resource>() -> Self {292Self {293name: DebugName::type_name::<T>(),294// PERF: `SparseStorage` may actually be a more295// reasonable choice as `storage_type` for resources.296storage_type: StorageType::Table,297is_send_and_sync: true,298type_id: Some(TypeId::of::<T>()),299layout: Layout::new::<T>(),300drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),301mutable: true,302clone_behavior: ComponentCloneBehavior::Default,303}304}305306pub(super) fn new_non_send<T: Any>(storage_type: StorageType) -> Self {307Self {308name: DebugName::type_name::<T>(),309storage_type,310is_send_and_sync: false,311type_id: Some(TypeId::of::<T>()),312layout: Layout::new::<T>(),313drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),314mutable: true,315clone_behavior: ComponentCloneBehavior::Default,316}317}318319/// Returns a value indicating the storage strategy for the current component.320#[inline]321pub fn storage_type(&self) -> StorageType {322self.storage_type323}324325/// Returns the [`TypeId`] of the underlying component type.326/// Returns `None` if the component does not correspond to a Rust type.327#[inline]328pub fn type_id(&self) -> Option<TypeId> {329self.type_id330}331332/// Returns the name of the current component.333#[inline]334pub fn name(&self) -> DebugName {335self.name.clone()336}337338/// Returns whether this component is mutable.339#[inline]340pub fn mutable(&self) -> bool {341self.mutable342}343}344345/// Stores metadata associated with each kind of [`Component`] in a given [`World`](crate::world::World).346#[derive(Debug, Default)]347pub struct Components {348pub(super) components: Vec<Option<ComponentInfo>>,349pub(super) indices: TypeIdMap<ComponentId>,350pub(super) resource_indices: TypeIdMap<ComponentId>,351// This is kept internal and local to verify that no deadlocks can occor.352pub(super) queued: bevy_platform::sync::RwLock<QueuedComponents>,353}354355impl Components {356/// This registers any descriptor, component or resource.357///358/// # Safety359///360/// The id must have never been registered before. This must be a fresh registration.361#[inline]362pub(super) unsafe fn register_component_inner(363&mut self,364id: ComponentId,365descriptor: ComponentDescriptor,366) {367let info = ComponentInfo::new(id, descriptor);368let least_len = id.0 + 1;369if self.components.len() < least_len {370self.components.resize_with(least_len, || None);371}372// SAFETY: We just extended the vec to make this index valid.373let slot = unsafe { self.components.get_mut(id.0).debug_checked_unwrap() };374// Caller ensures id is unique375debug_assert!(slot.is_none());376*slot = Some(info);377}378379/// Returns the number of components registered or queued with this instance.380#[inline]381pub fn len(&self) -> usize {382self.num_queued() + self.num_registered()383}384385/// Returns `true` if there are no components registered or queued with this instance. Otherwise, this returns `false`.386#[inline]387pub fn is_empty(&self) -> bool {388self.len() == 0389}390391/// Returns the number of components registered with this instance.392#[inline]393pub fn num_queued(&self) -> usize {394let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);395queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len()396}397398/// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`.399#[inline]400pub fn any_queued(&self) -> bool {401self.num_queued() > 0402}403404/// A faster version of [`Self::num_queued`].405#[inline]406pub fn num_queued_mut(&mut self) -> usize {407let queued = self408.queued409.get_mut()410.unwrap_or_else(PoisonError::into_inner);411queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len()412}413414/// A faster version of [`Self::any_queued`].415#[inline]416pub fn any_queued_mut(&mut self) -> bool {417self.num_queued_mut() > 0418}419420/// Returns the number of components registered with this instance.421#[inline]422pub fn num_registered(&self) -> usize {423self.components.len()424}425426/// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`.427#[inline]428pub fn any_registered(&self) -> bool {429self.num_registered() > 0430}431432/// Gets the metadata associated with the given component, if it is registered.433/// This will return `None` if the id is not registered or is queued.434///435/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.436#[inline]437pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> {438self.components.get(id.0).and_then(|info| info.as_ref())439}440441/// Gets the [`ComponentDescriptor`] of the component with this [`ComponentId`] if it is present.442/// This will return `None` only if the id is neither registered nor queued to be registered.443///444/// Currently, the [`Cow`] will be [`Cow::Owned`] if and only if the component is queued. It will be [`Cow::Borrowed`] otherwise.445///446/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.447#[inline]448pub fn get_descriptor<'a>(&'a self, id: ComponentId) -> Option<Cow<'a, ComponentDescriptor>> {449self.components450.get(id.0)451.and_then(|info| info.as_ref().map(|info| Cow::Borrowed(&info.descriptor)))452.or_else(|| {453let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);454// first check components, then resources, then dynamic455queued456.components457.values()458.chain(queued.resources.values())459.chain(queued.dynamic_registrations.iter())460.find(|queued| queued.id == id)461.map(|queued| Cow::Owned(queued.descriptor.clone()))462})463}464465/// Gets the name of the component with this [`ComponentId`] if it is present.466/// This will return `None` only if the id is neither registered nor queued to be registered.467///468/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.469#[inline]470pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<DebugName> {471self.components472.get(id.0)473.and_then(|info| info.as_ref().map(|info| info.descriptor.name()))474.or_else(|| {475let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);476// first check components, then resources, then dynamic477queued478.components479.values()480.chain(queued.resources.values())481.chain(queued.dynamic_registrations.iter())482.find(|queued| queued.id == id)483.map(|queued| queued.descriptor.name.clone())484})485}486487/// Gets the metadata associated with the given component.488/// # Safety489///490/// `id` must be a valid and fully registered [`ComponentId`].491#[inline]492pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo {493// SAFETY: The caller ensures `id` is valid.494unsafe {495self.components496.get(id.0)497.debug_checked_unwrap()498.as_ref()499.debug_checked_unwrap()500}501}502503#[inline]504pub(crate) fn get_hooks_mut(&mut self, id: ComponentId) -> Option<&mut ComponentHooks> {505self.components506.get_mut(id.0)507.and_then(|info| info.as_mut().map(|info| &mut info.hooks))508}509510#[inline]511pub(crate) fn get_required_components(&self, id: ComponentId) -> Option<&RequiredComponents> {512self.components513.get(id.0)514.and_then(|info| info.as_ref().map(|info| &info.required_components))515}516517#[inline]518pub(crate) fn get_required_components_mut(519&mut self,520id: ComponentId,521) -> Option<&mut RequiredComponents> {522self.components523.get_mut(id.0)524.and_then(|info| info.as_mut().map(|info| &mut info.required_components))525}526527#[inline]528pub(crate) fn get_required_by(529&self,530id: ComponentId,531) -> Option<&IndexSet<ComponentId, FixedHasher>> {532self.components533.get(id.0)534.and_then(|info| info.as_ref().map(|info| &info.required_by))535}536537#[inline]538pub(crate) fn get_required_by_mut(539&mut self,540id: ComponentId,541) -> Option<&mut IndexSet<ComponentId, FixedHasher>> {542self.components543.get_mut(id.0)544.and_then(|info| info.as_mut().map(|info| &mut info.required_by))545}546547/// Returns true if the [`ComponentId`] is fully registered and valid.548/// Ids may be invalid if they are still queued to be registered.549/// Those ids are still correct, but they are not usable in every context yet.550#[inline]551pub fn is_id_valid(&self, id: ComponentId) -> bool {552self.components.get(id.0).is_some_and(Option::is_some)553}554555/// Type-erased equivalent of [`Components::valid_component_id()`].556#[inline]557pub fn get_valid_id(&self, type_id: TypeId) -> Option<ComponentId> {558self.indices.get(&type_id).copied()559}560561/// Returns the [`ComponentId`] of the given [`Component`] type `T` if it is fully registered.562/// If you want to include queued registration, see [`Components::component_id()`].563///564/// ```565/// use bevy_ecs::prelude::*;566///567/// let mut world = World::new();568///569/// #[derive(Component)]570/// struct ComponentA;571///572/// let component_a_id = world.register_component::<ComponentA>();573///574/// assert_eq!(component_a_id, world.components().valid_component_id::<ComponentA>().unwrap())575/// ```576///577/// # See also578///579/// * [`Components::get_valid_id()`]580/// * [`Components::valid_resource_id()`]581/// * [`World::component_id()`](crate::world::World::component_id)582#[inline]583pub fn valid_component_id<T: Component>(&self) -> Option<ComponentId> {584self.get_valid_id(TypeId::of::<T>())585}586587/// Type-erased equivalent of [`Components::valid_resource_id()`].588#[inline]589pub fn get_valid_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {590self.resource_indices.get(&type_id).copied()591}592593/// Returns the [`ComponentId`] of the given [`Resource`] type `T` if it is fully registered.594/// If you want to include queued registration, see [`Components::resource_id()`].595///596/// ```597/// use bevy_ecs::prelude::*;598///599/// let mut world = World::new();600///601/// #[derive(Resource, Default)]602/// struct ResourceA;603///604/// let resource_a_id = world.init_resource::<ResourceA>();605///606/// assert_eq!(resource_a_id, world.components().valid_resource_id::<ResourceA>().unwrap())607/// ```608///609/// # See also610///611/// * [`Components::valid_component_id()`]612/// * [`Components::get_resource_id()`]613#[inline]614pub fn valid_resource_id<T: Resource>(&self) -> Option<ComponentId> {615self.get_valid_resource_id(TypeId::of::<T>())616}617618/// Type-erased equivalent of [`Components::component_id()`].619#[inline]620pub fn get_id(&self, type_id: TypeId) -> Option<ComponentId> {621self.indices.get(&type_id).copied().or_else(|| {622self.queued623.read()624.unwrap_or_else(PoisonError::into_inner)625.components626.get(&type_id)627.map(|queued| queued.id)628})629}630631/// Returns the [`ComponentId`] of the given [`Component`] type `T`.632///633/// The returned `ComponentId` is specific to the `Components` instance634/// it was retrieved from and should not be used with another `Components`635/// instance.636///637/// Returns [`None`] if the `Component` type has not yet been initialized using638/// [`ComponentsRegistrator::register_component()`](super::ComponentsRegistrator::register_component) or639/// [`ComponentsQueuedRegistrator::queue_register_component()`](super::ComponentsQueuedRegistrator::queue_register_component).640///641/// ```642/// use bevy_ecs::prelude::*;643///644/// let mut world = World::new();645///646/// #[derive(Component)]647/// struct ComponentA;648///649/// let component_a_id = world.register_component::<ComponentA>();650///651/// assert_eq!(component_a_id, world.components().component_id::<ComponentA>().unwrap())652/// ```653///654/// # See also655///656/// * [`ComponentIdFor`](super::ComponentIdFor)657/// * [`Components::get_id()`]658/// * [`Components::resource_id()`]659/// * [`World::component_id()`](crate::world::World::component_id)660#[inline]661pub fn component_id<T: Component>(&self) -> Option<ComponentId> {662self.get_id(TypeId::of::<T>())663}664665/// Type-erased equivalent of [`Components::resource_id()`].666#[inline]667pub fn get_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {668self.resource_indices.get(&type_id).copied().or_else(|| {669self.queued670.read()671.unwrap_or_else(PoisonError::into_inner)672.resources673.get(&type_id)674.map(|queued| queued.id)675})676}677678/// Returns the [`ComponentId`] of the given [`Resource`] type `T`.679///680/// The returned `ComponentId` is specific to the `Components` instance681/// it was retrieved from and should not be used with another `Components`682/// instance.683///684/// Returns [`None`] if the `Resource` type has not yet been initialized using685/// [`ComponentsRegistrator::register_resource()`](super::ComponentsRegistrator::register_resource) or686/// [`ComponentsQueuedRegistrator::queue_register_resource()`](super::ComponentsQueuedRegistrator::queue_register_resource).687///688/// ```689/// use bevy_ecs::prelude::*;690///691/// let mut world = World::new();692///693/// #[derive(Resource, Default)]694/// struct ResourceA;695///696/// let resource_a_id = world.init_resource::<ResourceA>();697///698/// assert_eq!(resource_a_id, world.components().resource_id::<ResourceA>().unwrap())699/// ```700///701/// # See also702///703/// * [`Components::component_id()`]704/// * [`Components::get_resource_id()`]705#[inline]706pub fn resource_id<T: Resource>(&self) -> Option<ComponentId> {707self.get_resource_id(TypeId::of::<T>())708}709710/// # Safety711///712/// The [`ComponentDescriptor`] must match the [`TypeId`].713/// The [`ComponentId`] must be unique.714/// The [`TypeId`] and [`ComponentId`] must not be registered or queued.715#[inline]716pub(super) unsafe fn register_resource_unchecked(717&mut self,718type_id: TypeId,719component_id: ComponentId,720descriptor: ComponentDescriptor,721) {722// SAFETY: ensured by caller723unsafe {724self.register_component_inner(component_id, descriptor);725}726let prev = self.resource_indices.insert(type_id, component_id);727debug_assert!(prev.is_none());728}729730/// Gets an iterator over all components fully registered with this instance.731pub fn iter_registered(&self) -> impl Iterator<Item = &ComponentInfo> + '_ {732self.components.iter().filter_map(Option::as_ref)733}734}735736737