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 _,22relationship::RelationshipAccessor,23resource::Resource,24storage::SparseSetIndex,25};2627/// Stores metadata for a type of component or resource stored in a specific [`World`](crate::world::World).28#[derive(Debug, Clone)]29pub struct ComponentInfo {30pub(super) id: ComponentId,31pub(super) descriptor: ComponentDescriptor,32pub(super) hooks: ComponentHooks,33pub(super) required_components: RequiredComponents,34/// The set of components that require this components.35/// Invariant: components in this set always appear after the components that they require.36pub(super) required_by: IndexSet<ComponentId, FixedHasher>,37}3839impl ComponentInfo {40/// Returns a value uniquely identifying the current component.41#[inline]42pub fn id(&self) -> ComponentId {43self.id44}4546/// Returns the name of the current component.47#[inline]48pub fn name(&self) -> DebugName {49self.descriptor.name.clone()50}5152/// Returns `true` if the current component is mutable.53#[inline]54pub fn mutable(&self) -> bool {55self.descriptor.mutable56}5758/// Returns [`ComponentCloneBehavior`] of the current component.59#[inline]60pub fn clone_behavior(&self) -> &ComponentCloneBehavior {61&self.descriptor.clone_behavior62}6364/// Returns the [`TypeId`] of the underlying component type.65/// Returns `None` if the component does not correspond to a Rust type.66#[inline]67pub fn type_id(&self) -> Option<TypeId> {68self.descriptor.type_id69}7071/// Returns the layout used to store values of this component in memory.72#[inline]73pub fn layout(&self) -> Layout {74self.descriptor.layout75}7677#[inline]78/// Get the function which should be called to clean up values of79/// the underlying component type. This maps to the80/// [`Drop`] implementation for 'normal' Rust components81///82/// Returns `None` if values of the underlying component type don't83/// need to be dropped, e.g. as reported by [`needs_drop`].84pub fn drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {85self.descriptor.drop86}8788/// Returns a value indicating the storage strategy for the current component.89#[inline]90pub fn storage_type(&self) -> StorageType {91self.descriptor.storage_type92}9394/// Returns `true` if the underlying component type can be freely shared between threads.95/// If this returns `false`, then extra care must be taken to ensure that components96/// are not accessed from the wrong thread.97#[inline]98pub fn is_send_and_sync(&self) -> bool {99self.descriptor.is_send_and_sync100}101102/// Create a new [`ComponentInfo`].103pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self {104ComponentInfo {105id,106descriptor,107hooks: Default::default(),108required_components: Default::default(),109required_by: Default::default(),110}111}112113/// Update the given flags to include any [`ComponentHook`](crate::component::ComponentHook) registered to self114#[inline]115pub(crate) fn update_archetype_flags(&self, flags: &mut ArchetypeFlags) {116if self.hooks().on_add.is_some() {117flags.insert(ArchetypeFlags::ON_ADD_HOOK);118}119if self.hooks().on_insert.is_some() {120flags.insert(ArchetypeFlags::ON_INSERT_HOOK);121}122if self.hooks().on_replace.is_some() {123flags.insert(ArchetypeFlags::ON_REPLACE_HOOK);124}125if self.hooks().on_remove.is_some() {126flags.insert(ArchetypeFlags::ON_REMOVE_HOOK);127}128if self.hooks().on_despawn.is_some() {129flags.insert(ArchetypeFlags::ON_DESPAWN_HOOK);130}131}132133/// Provides a reference to the collection of hooks associated with this [`Component`]134pub fn hooks(&self) -> &ComponentHooks {135&self.hooks136}137138/// Retrieves the [`RequiredComponents`] collection, which contains all required components (and their constructors)139/// needed by this component. This includes _recursive_ required components.140pub fn required_components(&self) -> &RequiredComponents {141&self.required_components142}143144/// Returns [`RelationshipAccessor`] for this component if it is a [`Relationship`](crate::relationship::Relationship) or [`RelationshipTarget`](crate::relationship::RelationshipTarget) , `None` otherwise.145pub fn relationship_accessor(&self) -> Option<&RelationshipAccessor> {146self.descriptor.relationship_accessor.as_ref()147}148}149150/// A value which uniquely identifies the type of a [`Component`] or [`Resource`] within a151/// [`World`](crate::world::World).152///153/// Each time a new `Component` type is registered within a `World` using154/// e.g. [`World::register_component`](crate::world::World::register_component) or155/// [`World::register_component_with_descriptor`](crate::world::World::register_component_with_descriptor)156/// or a Resource with e.g. [`World::init_resource`](crate::world::World::init_resource),157/// a corresponding `ComponentId` is created to track it.158///159/// While the distinction between `ComponentId` and [`TypeId`] may seem superficial, breaking them160/// into two separate but related concepts allows components to exist outside of Rust's type system.161/// Each Rust type registered as a `Component` will have a corresponding `ComponentId`, but additional162/// `ComponentId`s may exist in a `World` to track components which cannot be163/// represented as Rust types for scripting or other advanced use-cases.164///165/// A `ComponentId` is tightly coupled to its parent `World`. Attempting to use a `ComponentId` from166/// one `World` to access the metadata of a `Component` in a different `World` is undefined behavior167/// and must not be attempted.168///169/// Given a type `T` which implements [`Component`], the `ComponentId` for `T` can be retrieved170/// from a `World` using [`World::component_id()`](crate::world::World::component_id) or via [`Components::component_id()`].171/// Access to the `ComponentId` for a [`Resource`] is available via [`Components::resource_id()`].172#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]173#[cfg_attr(174feature = "bevy_reflect",175derive(Reflect),176reflect(Debug, Hash, PartialEq, Clone)177)]178pub struct ComponentId(pub(super) usize);179180impl ComponentId {181/// Creates a new [`ComponentId`].182///183/// The `index` is a unique value associated with each type of component in a given world.184/// Usually, this value is taken from a counter incremented for each type of component registered with the world.185#[inline]186pub const fn new(index: usize) -> ComponentId {187ComponentId(index)188}189190/// Returns the index of the current component.191#[inline]192pub fn index(self) -> usize {193self.0194}195}196197impl SparseSetIndex for ComponentId {198#[inline]199fn sparse_set_index(&self) -> usize {200self.index()201}202203#[inline]204fn get_sparse_set_index(value: usize) -> Self {205Self(value)206}207}208209/// A value describing a component or resource, which may or may not correspond to a Rust type.210#[derive(Clone)]211pub struct ComponentDescriptor {212name: DebugName,213// SAFETY: This must remain private. It must match the statically known StorageType of the214// associated rust component type if one exists.215storage_type: StorageType,216// SAFETY: This must remain private. It must only be set to "true" if this component is217// actually Send + Sync218is_send_and_sync: bool,219type_id: Option<TypeId>,220layout: Layout,221// SAFETY: this function must be safe to call with pointers pointing to items of the type222// this descriptor describes.223// None if the underlying type doesn't need to be dropped224drop: Option<for<'a> unsafe fn(OwningPtr<'a>)>,225mutable: bool,226clone_behavior: ComponentCloneBehavior,227relationship_accessor: Option<RelationshipAccessor>,228}229230// We need to ignore the `drop` field in our `Debug` impl231impl Debug for ComponentDescriptor {232fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {233f.debug_struct("ComponentDescriptor")234.field("name", &self.name)235.field("storage_type", &self.storage_type)236.field("is_send_and_sync", &self.is_send_and_sync)237.field("type_id", &self.type_id)238.field("layout", &self.layout)239.field("mutable", &self.mutable)240.field("clone_behavior", &self.clone_behavior)241.field("relationship_accessor", &self.relationship_accessor)242.finish()243}244}245246impl ComponentDescriptor {247/// # Safety248///249/// `x` must point to a valid value of type `T`.250unsafe fn drop_ptr<T>(x: OwningPtr<'_>) {251// SAFETY: Contract is required to be upheld by the caller.252unsafe {253x.drop_as::<T>();254}255}256257/// Create a new `ComponentDescriptor` for the type `T`.258pub fn new<T: Component>() -> Self {259Self {260name: DebugName::type_name::<T>(),261storage_type: T::STORAGE_TYPE,262is_send_and_sync: true,263type_id: Some(TypeId::of::<T>()),264layout: Layout::new::<T>(),265drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),266mutable: T::Mutability::MUTABLE,267clone_behavior: T::clone_behavior(),268relationship_accessor: T::relationship_accessor().map(|v| v.accessor),269}270}271272/// Create a new `ComponentDescriptor`.273///274/// # Safety275/// - the `drop` fn must be usable on a pointer with a value of the layout `layout`276/// - the component type must be safe to access from any thread (Send + Sync in rust terms)277/// - `relationship_accessor` must be valid for this component type if not `None`278pub unsafe fn new_with_layout(279name: impl Into<Cow<'static, str>>,280storage_type: StorageType,281layout: Layout,282drop: Option<for<'a> unsafe fn(OwningPtr<'a>)>,283mutable: bool,284clone_behavior: ComponentCloneBehavior,285relationship_accessor: Option<RelationshipAccessor>,286) -> Self {287Self {288name: name.into().into(),289storage_type,290is_send_and_sync: true,291type_id: None,292layout,293drop,294mutable,295clone_behavior,296relationship_accessor,297}298}299300/// Create a new `ComponentDescriptor` for a resource.301///302/// The [`StorageType`] for resources is always [`StorageType::Table`].303pub fn new_resource<T: Resource>() -> Self {304Self {305name: DebugName::type_name::<T>(),306// PERF: `SparseStorage` may actually be a more307// reasonable choice as `storage_type` for resources.308storage_type: StorageType::Table,309is_send_and_sync: true,310type_id: Some(TypeId::of::<T>()),311layout: Layout::new::<T>(),312drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),313mutable: true,314clone_behavior: ComponentCloneBehavior::Default,315relationship_accessor: None,316}317}318319pub(super) fn new_non_send<T: Any>(storage_type: StorageType) -> Self {320Self {321name: DebugName::type_name::<T>(),322storage_type,323is_send_and_sync: false,324type_id: Some(TypeId::of::<T>()),325layout: Layout::new::<T>(),326drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),327mutable: true,328clone_behavior: ComponentCloneBehavior::Default,329relationship_accessor: None,330}331}332333/// Returns a value indicating the storage strategy for the current component.334#[inline]335pub fn storage_type(&self) -> StorageType {336self.storage_type337}338339/// Returns the [`TypeId`] of the underlying component type.340/// Returns `None` if the component does not correspond to a Rust type.341#[inline]342pub fn type_id(&self) -> Option<TypeId> {343self.type_id344}345346/// Returns the name of the current component.347#[inline]348pub fn name(&self) -> DebugName {349self.name.clone()350}351352/// Returns whether this component is mutable.353#[inline]354pub fn mutable(&self) -> bool {355self.mutable356}357}358359/// Stores metadata associated with each kind of [`Component`] in a given [`World`](crate::world::World).360#[derive(Debug, Default)]361pub struct Components {362pub(super) components: Vec<Option<ComponentInfo>>,363pub(super) indices: TypeIdMap<ComponentId>,364pub(super) resource_indices: TypeIdMap<ComponentId>,365// This is kept internal and local to verify that no deadlocks can occur.366pub(super) queued: bevy_platform::sync::RwLock<QueuedComponents>,367}368369impl Components {370/// This registers any descriptor, component or resource.371///372/// # Safety373///374/// The id must have never been registered before. This must be a fresh registration.375#[inline]376pub(super) unsafe fn register_component_inner(377&mut self,378id: ComponentId,379descriptor: ComponentDescriptor,380) {381let info = ComponentInfo::new(id, descriptor);382let least_len = id.0 + 1;383if self.components.len() < least_len {384self.components.resize_with(least_len, || None);385}386// SAFETY: We just extended the vec to make this index valid.387let slot = unsafe { self.components.get_mut(id.0).debug_checked_unwrap() };388// Caller ensures id is unique389debug_assert!(slot.is_none());390*slot = Some(info);391}392393/// Returns the number of components registered or queued with this instance.394#[inline]395pub fn len(&self) -> usize {396self.num_queued() + self.num_registered()397}398399/// Returns `true` if there are no components registered or queued with this instance. Otherwise, this returns `false`.400#[inline]401pub fn is_empty(&self) -> bool {402self.len() == 0403}404405/// Returns the number of components registered with this instance.406#[inline]407pub fn num_queued(&self) -> usize {408let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);409queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len()410}411412/// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`.413#[inline]414pub fn any_queued(&self) -> bool {415self.num_queued() > 0416}417418/// A faster version of [`Self::num_queued`].419#[inline]420pub fn num_queued_mut(&mut self) -> usize {421let queued = self422.queued423.get_mut()424.unwrap_or_else(PoisonError::into_inner);425queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len()426}427428/// A faster version of [`Self::any_queued`].429#[inline]430pub fn any_queued_mut(&mut self) -> bool {431self.num_queued_mut() > 0432}433434/// Returns the number of components registered with this instance.435#[inline]436pub fn num_registered(&self) -> usize {437self.components.len()438}439440/// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`.441#[inline]442pub fn any_registered(&self) -> bool {443self.num_registered() > 0444}445446/// Gets the metadata associated with the given component, if it is registered.447/// This will return `None` if the id is not registered or is queued.448///449/// 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.450#[inline]451pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> {452self.components.get(id.0).and_then(|info| info.as_ref())453}454455/// Gets the [`ComponentDescriptor`] of the component with this [`ComponentId`] if it is present.456/// This will return `None` only if the id is neither registered nor queued to be registered.457///458/// Currently, the [`Cow`] will be [`Cow::Owned`] if and only if the component is queued. It will be [`Cow::Borrowed`] otherwise.459///460/// 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.461#[inline]462pub fn get_descriptor<'a>(&'a self, id: ComponentId) -> Option<Cow<'a, ComponentDescriptor>> {463self.components464.get(id.0)465.and_then(|info| info.as_ref().map(|info| Cow::Borrowed(&info.descriptor)))466.or_else(|| {467let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);468// first check components, then resources, then dynamic469queued470.components471.values()472.chain(queued.resources.values())473.chain(queued.dynamic_registrations.iter())474.find(|queued| queued.id == id)475.map(|queued| Cow::Owned(queued.descriptor.clone()))476})477}478479/// Gets the name of the component with this [`ComponentId`] if it is present.480/// This will return `None` only if the id is neither registered nor queued to be registered.481///482/// 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.483#[inline]484pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<DebugName> {485self.components486.get(id.0)487.and_then(|info| info.as_ref().map(|info| info.descriptor.name()))488.or_else(|| {489let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);490// first check components, then resources, then dynamic491queued492.components493.values()494.chain(queued.resources.values())495.chain(queued.dynamic_registrations.iter())496.find(|queued| queued.id == id)497.map(|queued| queued.descriptor.name.clone())498})499}500501/// Gets the metadata associated with the given component.502/// # Safety503///504/// `id` must be a valid and fully registered [`ComponentId`].505#[inline]506pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo {507// SAFETY: The caller ensures `id` is valid.508unsafe {509self.components510.get(id.0)511.debug_checked_unwrap()512.as_ref()513.debug_checked_unwrap()514}515}516517#[inline]518pub(crate) fn get_hooks_mut(&mut self, id: ComponentId) -> Option<&mut ComponentHooks> {519self.components520.get_mut(id.0)521.and_then(|info| info.as_mut().map(|info| &mut info.hooks))522}523524#[inline]525pub(crate) fn get_required_components(&self, id: ComponentId) -> Option<&RequiredComponents> {526self.components527.get(id.0)528.and_then(|info| info.as_ref().map(|info| &info.required_components))529}530531#[inline]532pub(crate) fn get_required_components_mut(533&mut self,534id: ComponentId,535) -> Option<&mut RequiredComponents> {536self.components537.get_mut(id.0)538.and_then(|info| info.as_mut().map(|info| &mut info.required_components))539}540541#[inline]542pub(crate) fn get_required_by(543&self,544id: ComponentId,545) -> Option<&IndexSet<ComponentId, FixedHasher>> {546self.components547.get(id.0)548.and_then(|info| info.as_ref().map(|info| &info.required_by))549}550551#[inline]552pub(crate) fn get_required_by_mut(553&mut self,554id: ComponentId,555) -> Option<&mut IndexSet<ComponentId, FixedHasher>> {556self.components557.get_mut(id.0)558.and_then(|info| info.as_mut().map(|info| &mut info.required_by))559}560561/// Returns true if the [`ComponentId`] is fully registered and valid.562/// Ids may be invalid if they are still queued to be registered.563/// Those ids are still correct, but they are not usable in every context yet.564#[inline]565pub fn is_id_valid(&self, id: ComponentId) -> bool {566self.components.get(id.0).is_some_and(Option::is_some)567}568569/// Type-erased equivalent of [`Components::valid_component_id()`].570#[inline]571pub fn get_valid_id(&self, type_id: TypeId) -> Option<ComponentId> {572self.indices.get(&type_id).copied()573}574575/// Returns the [`ComponentId`] of the given [`Component`] type `T` if it is fully registered.576/// If you want to include queued registration, see [`Components::component_id()`].577///578/// ```579/// use bevy_ecs::prelude::*;580///581/// let mut world = World::new();582///583/// #[derive(Component)]584/// struct ComponentA;585///586/// let component_a_id = world.register_component::<ComponentA>();587///588/// assert_eq!(component_a_id, world.components().valid_component_id::<ComponentA>().unwrap())589/// ```590///591/// # See also592///593/// * [`Components::get_valid_id()`]594/// * [`Components::valid_resource_id()`]595/// * [`World::component_id()`](crate::world::World::component_id)596#[inline]597pub fn valid_component_id<T: Component>(&self) -> Option<ComponentId> {598self.get_valid_id(TypeId::of::<T>())599}600601/// Type-erased equivalent of [`Components::valid_resource_id()`].602#[inline]603pub fn get_valid_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {604self.resource_indices.get(&type_id).copied()605}606607/// Returns the [`ComponentId`] of the given [`Resource`] type `T` if it is fully registered.608/// If you want to include queued registration, see [`Components::resource_id()`].609///610/// ```611/// use bevy_ecs::prelude::*;612///613/// let mut world = World::new();614///615/// #[derive(Resource, Default)]616/// struct ResourceA;617///618/// let resource_a_id = world.init_resource::<ResourceA>();619///620/// assert_eq!(resource_a_id, world.components().valid_resource_id::<ResourceA>().unwrap())621/// ```622///623/// # See also624///625/// * [`Components::valid_component_id()`]626/// * [`Components::get_resource_id()`]627#[inline]628pub fn valid_resource_id<T: Resource>(&self) -> Option<ComponentId> {629self.get_valid_resource_id(TypeId::of::<T>())630}631632/// Type-erased equivalent of [`Components::component_id()`].633#[inline]634pub fn get_id(&self, type_id: TypeId) -> Option<ComponentId> {635self.indices.get(&type_id).copied().or_else(|| {636self.queued637.read()638.unwrap_or_else(PoisonError::into_inner)639.components640.get(&type_id)641.map(|queued| queued.id)642})643}644645/// Returns the [`ComponentId`] of the given [`Component`] type `T`.646///647/// The returned `ComponentId` is specific to the `Components` instance648/// it was retrieved from and should not be used with another `Components`649/// instance.650///651/// Returns [`None`] if the `Component` type has not yet been initialized using652/// [`ComponentsRegistrator::register_component()`](super::ComponentsRegistrator::register_component) or653/// [`ComponentsQueuedRegistrator::queue_register_component()`](super::ComponentsQueuedRegistrator::queue_register_component).654///655/// ```656/// use bevy_ecs::prelude::*;657///658/// let mut world = World::new();659///660/// #[derive(Component)]661/// struct ComponentA;662///663/// let component_a_id = world.register_component::<ComponentA>();664///665/// assert_eq!(component_a_id, world.components().component_id::<ComponentA>().unwrap())666/// ```667///668/// # See also669///670/// * [`ComponentIdFor`](super::ComponentIdFor)671/// * [`Components::get_id()`]672/// * [`Components::resource_id()`]673/// * [`World::component_id()`](crate::world::World::component_id)674#[inline]675pub fn component_id<T: Component>(&self) -> Option<ComponentId> {676self.get_id(TypeId::of::<T>())677}678679/// Type-erased equivalent of [`Components::resource_id()`].680#[inline]681pub fn get_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {682self.resource_indices.get(&type_id).copied().or_else(|| {683self.queued684.read()685.unwrap_or_else(PoisonError::into_inner)686.resources687.get(&type_id)688.map(|queued| queued.id)689})690}691692/// Returns the [`ComponentId`] of the given [`Resource`] type `T`.693///694/// The returned `ComponentId` is specific to the `Components` instance695/// it was retrieved from and should not be used with another `Components`696/// instance.697///698/// Returns [`None`] if the `Resource` type has not yet been initialized using699/// [`ComponentsRegistrator::register_resource()`](super::ComponentsRegistrator::register_resource) or700/// [`ComponentsQueuedRegistrator::queue_register_resource()`](super::ComponentsQueuedRegistrator::queue_register_resource).701///702/// ```703/// use bevy_ecs::prelude::*;704///705/// let mut world = World::new();706///707/// #[derive(Resource, Default)]708/// struct ResourceA;709///710/// let resource_a_id = world.init_resource::<ResourceA>();711///712/// assert_eq!(resource_a_id, world.components().resource_id::<ResourceA>().unwrap())713/// ```714///715/// # See also716///717/// * [`Components::component_id()`]718/// * [`Components::get_resource_id()`]719#[inline]720pub fn resource_id<T: Resource>(&self) -> Option<ComponentId> {721self.get_resource_id(TypeId::of::<T>())722}723724/// # Safety725///726/// The [`ComponentDescriptor`] must match the [`TypeId`].727/// The [`ComponentId`] must be unique.728/// The [`TypeId`] and [`ComponentId`] must not be registered or queued.729#[inline]730pub(super) unsafe fn register_resource_unchecked(731&mut self,732type_id: TypeId,733component_id: ComponentId,734descriptor: ComponentDescriptor,735) {736// SAFETY: ensured by caller737unsafe {738self.register_component_inner(component_id, descriptor);739}740let prev = self.resource_indices.insert(type_id, component_id);741debug_assert!(prev.is_none());742}743744/// Gets an iterator over all components fully registered with this instance.745pub fn iter_registered(&self) -> impl Iterator<Item = &ComponentInfo> + '_ {746self.components.iter().filter_map(Option::as_ref)747}748}749750751