Path: blob/main/crates/bevy_ecs/src/component/register.rs
9353 views
use alloc::{boxed::Box, vec::Vec};1use bevy_platform::sync::PoisonError;2use bevy_utils::TypeIdMap;3use core::any::Any;4use core::{any::TypeId, fmt::Debug, ops::Deref};56use crate::component::{enforce_no_required_components_recursion, RequiredComponentsRegistrator};7use crate::{8component::{9Component, ComponentDescriptor, ComponentId, Components, RequiredComponents, StorageType,10},11query::DebugCheckedUnwrap as _,12resource::Resource,13};1415/// Generates [`ComponentId`]s.16#[derive(Debug, Default)]17pub struct ComponentIds {18next: bevy_platform::sync::atomic::AtomicUsize,19}2021impl ComponentIds {22/// Peeks the next [`ComponentId`] to be generated without generating it.23pub fn peek(&self) -> ComponentId {24ComponentId(25self.next26.load(bevy_platform::sync::atomic::Ordering::Relaxed),27)28}2930/// Generates and returns the next [`ComponentId`].31pub fn next(&self) -> ComponentId {32ComponentId(33self.next34.fetch_add(1, bevy_platform::sync::atomic::Ordering::Relaxed),35)36}3738/// Peeks the next [`ComponentId`] to be generated without generating it.39pub fn peek_mut(&mut self) -> ComponentId {40ComponentId(*self.next.get_mut())41}4243/// Generates and returns the next [`ComponentId`].44pub fn next_mut(&mut self) -> ComponentId {45let id = self.next.get_mut();46let result = ComponentId(*id);47*id += 1;48result49}5051/// Returns the number of [`ComponentId`]s generated.52pub fn len(&self) -> usize {53self.peek().054}5556/// Returns true if and only if no ids have been generated.57pub fn is_empty(&self) -> bool {58self.len() == 059}60}6162/// A [`Components`] wrapper that enables additional features, like registration.63pub struct ComponentsRegistrator<'w> {64pub(super) components: &'w mut Components,65pub(super) ids: &'w mut ComponentIds,66pub(super) recursion_check_stack: Vec<ComponentId>,67}6869impl Deref for ComponentsRegistrator<'_> {70type Target = Components;7172fn deref(&self) -> &Self::Target {73self.components74}75}7677impl<'w> ComponentsRegistrator<'w> {78/// Constructs a new [`ComponentsRegistrator`].79///80/// # Safety81///82/// The [`Components`] and [`ComponentIds`] must match.83/// For example, they must be from the same world.84pub unsafe fn new(components: &'w mut Components, ids: &'w mut ComponentIds) -> Self {85Self {86components,87ids,88recursion_check_stack: Vec::new(),89}90}9192/// Converts this [`ComponentsRegistrator`] into a [`ComponentsQueuedRegistrator`].93/// This is intended for use to pass this value to a function that requires [`ComponentsQueuedRegistrator`].94/// It is generally not a good idea to queue a registration when you can instead register directly on this type.95pub fn as_queued(&self) -> ComponentsQueuedRegistrator<'_> {96// SAFETY: ensured by the caller that created self.97unsafe { ComponentsQueuedRegistrator::new(self.components, self.ids) }98}99100/// Applies every queued registration.101/// This ensures that every valid [`ComponentId`] is registered,102/// enabling retrieving [`ComponentInfo`](super::ComponentInfo), etc.103pub fn apply_queued_registrations(&mut self) {104if !self.any_queued_mut() {105return;106}107108// Note:109//110// This is not just draining the queue. We need to empty the queue without removing the information from `Components`.111// If we drained directly, we could break invariance.112//113// For example, say `ComponentA` and `ComponentB` are queued, and `ComponentA` requires `ComponentB`.114// If we drain directly, and `ComponentA` was the first to be registered, then, when `ComponentA`115// registers `ComponentB` in `Component::register_required_components`,116// `Components` will not know that `ComponentB` was queued117// (since it will have been drained from the queue.)118// If that happened, `Components` would assign a new `ComponentId` to `ComponentB`119// which would be *different* than the id it was assigned in the queue.120// Then, when the drain iterator gets to `ComponentB`,121// it would be unsafely registering `ComponentB`, which is already registered.122//123// As a result, we need to pop from each queue one by one instead of draining.124125// components126while let Some(registrator) = {127let queued = self128.components129.queued130.get_mut()131.unwrap_or_else(PoisonError::into_inner);132queued.components.keys().next().copied().map(|type_id| {133// SAFETY: the id just came from a valid iterator.134unsafe { queued.components.remove(&type_id).debug_checked_unwrap() }135})136} {137registrator.register(self);138}139140// resources141while let Some(registrator) = {142let queued = self143.components144.queued145.get_mut()146.unwrap_or_else(PoisonError::into_inner);147queued.resources.keys().next().copied().map(|type_id| {148// SAFETY: the id just came from a valid iterator.149unsafe { queued.resources.remove(&type_id).debug_checked_unwrap() }150})151} {152registrator.register(self);153}154155// dynamic156let queued = &mut self157.components158.queued159.get_mut()160.unwrap_or_else(PoisonError::into_inner);161if !queued.dynamic_registrations.is_empty() {162for registrator in core::mem::take(&mut queued.dynamic_registrations) {163registrator.register(self);164}165}166}167168/// Registers a [`Component`] of type `T` with this instance.169/// If a component of this type has already been registered, this will return170/// the ID of the pre-existing component.171///172/// # See also173///174/// * [`Components::component_id()`]175/// * [`ComponentsRegistrator::register_component_with_descriptor()`]176#[inline]177pub fn register_component<T: Component>(&mut self) -> ComponentId {178self.register_component_checked::<T>()179}180181/// Same as [`Self::register_component_unchecked`] but keeps a checks for safety.182#[inline]183pub(super) fn register_component_checked<T: Component>(&mut self) -> ComponentId {184let type_id = TypeId::of::<T>();185if let Some(&id) = self.indices.get(&type_id) {186enforce_no_required_components_recursion(self, &self.recursion_check_stack, id);187return id;188}189190if let Some(registrator) = self191.components192.queued193.get_mut()194.unwrap_or_else(PoisonError::into_inner)195.components196.remove(&type_id)197{198// If we are trying to register something that has already been queued, we respect the queue.199// Just like if we are trying to register something that already is, we respect the first registration.200return registrator.register(self);201}202203let id = self.ids.next_mut();204// SAFETY: The component is not currently registered, and the id is fresh.205unsafe {206self.register_component_unchecked::<T>(id);207}208id209}210211/// # Safety212///213/// Neither this component, nor its id may be registered or queued. This must be a new registration.214#[inline]215unsafe fn register_component_unchecked<T: Component>(&mut self, id: ComponentId) {216// SAFETY: ensured by caller.217unsafe {218self.components219.register_component_inner(id, ComponentDescriptor::new::<T>());220}221let type_id = TypeId::of::<T>();222let prev = self.components.indices.insert(type_id, id);223debug_assert!(prev.is_none());224225self.recursion_check_stack.push(id);226let mut required_components = RequiredComponents::default();227// SAFETY: `required_components` is empty228let mut required_components_registrator =229unsafe { RequiredComponentsRegistrator::new(self, &mut required_components) };230T::register_required_components(id, &mut required_components_registrator);231// SAFETY:232// - `id` was just registered in `self`233// - RequiredComponentsRegistrator guarantees that only components from `self` are included in `required_components`;234// - we just initialized the component with id `id` so no component requiring it can exist yet.235unsafe {236self.components237.register_required_by(id, &required_components);238}239self.recursion_check_stack.pop();240241// SAFETY: we just inserted it in `register_component_inner`242let info = unsafe {243&mut self244.components245.components246.get_mut(id.0)247.debug_checked_unwrap()248.as_mut()249.debug_checked_unwrap()250};251252info.hooks.update_from_component::<T>();253254info.required_components = required_components;255}256257/// Registers a component described by `descriptor`.258///259/// # Note260///261/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]262/// will be created for each one.263///264/// # See also265///266/// * [`Components::component_id()`]267/// * [`ComponentsRegistrator::register_component()`]268#[inline]269pub fn register_component_with_descriptor(270&mut self,271descriptor: ComponentDescriptor,272) -> ComponentId {273let id = self.ids.next_mut();274// SAFETY: The id is fresh.275unsafe {276self.components.register_component_inner(id, descriptor);277}278id279}280281/// Registers a [`Resource`] of type `T` with this instance.282/// If a resource of this type has already been registered, this will return283/// the ID of the pre-existing resource.284///285/// # See also286///287/// * [`Components::resource_id()`]288/// * [`ComponentsRegistrator::register_resource_with_descriptor()`]289#[inline]290pub fn register_resource<T: Resource>(&mut self) -> ComponentId {291// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]292unsafe {293self.register_resource_with(TypeId::of::<T>(), || {294ComponentDescriptor::new_resource::<T>()295})296}297}298299/// Registers a [non-send resource](crate::system::NonSend) of type `T` with this instance.300/// If a resource of this type has already been registered, this will return301/// the ID of the pre-existing resource.302#[inline]303pub fn register_non_send<T: Any>(&mut self) -> ComponentId {304// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]305unsafe {306self.register_resource_with(TypeId::of::<T>(), || {307ComponentDescriptor::new_non_send::<T>(StorageType::default())308})309}310}311312/// Same as [`Components::register_resource_unchecked`] but handles safety.313///314/// # Safety315///316/// The [`ComponentDescriptor`] must match the [`TypeId`].317#[inline]318unsafe fn register_resource_with(319&mut self,320type_id: TypeId,321descriptor: impl FnOnce() -> ComponentDescriptor,322) -> ComponentId {323if let Some(id) = self.resource_indices.get(&type_id) {324return *id;325}326327if let Some(registrator) = self328.components329.queued330.get_mut()331.unwrap_or_else(PoisonError::into_inner)332.resources333.remove(&type_id)334{335// If we are trying to register something that has already been queued, we respect the queue.336// Just like if we are trying to register something that already is, we respect the first registration.337return registrator.register(self);338}339340let id = self.ids.next_mut();341// SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`]342unsafe {343self.components344.register_resource_unchecked(type_id, id, descriptor());345}346id347}348349/// Registers a [`Resource`] described by `descriptor`.350///351/// # Note352///353/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]354/// will be created for each one.355///356/// # See also357///358/// * [`Components::resource_id()`]359/// * [`ComponentsRegistrator::register_resource()`]360#[inline]361pub fn register_resource_with_descriptor(362&mut self,363descriptor: ComponentDescriptor,364) -> ComponentId {365let id = self.ids.next_mut();366// SAFETY: The id is fresh.367unsafe {368self.components.register_component_inner(id, descriptor);369}370id371}372373/// Equivalent of `Components::any_queued_mut`374pub fn any_queued_mut(&mut self) -> bool {375self.components.any_queued_mut()376}377378/// Equivalent of `Components::any_queued_mut`379pub fn num_queued_mut(&mut self) -> usize {380self.components.num_queued_mut()381}382}383384/// A queued component registration.385pub(super) struct QueuedRegistration {386pub(super) registrator:387Box<dyn FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor)>,388pub(super) id: ComponentId,389pub(super) descriptor: ComponentDescriptor,390}391392impl QueuedRegistration {393/// Creates the [`QueuedRegistration`].394///395/// # Safety396///397/// [`ComponentId`] must be unique.398unsafe fn new(399id: ComponentId,400descriptor: ComponentDescriptor,401func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static,402) -> Self {403Self {404registrator: Box::new(func),405id,406descriptor,407}408}409410/// Performs the registration, returning the now valid [`ComponentId`].411pub(super) fn register(self, registrator: &mut ComponentsRegistrator) -> ComponentId {412(self.registrator)(registrator, self.id, self.descriptor);413self.id414}415}416417/// Allows queuing components to be registered.418#[derive(Default)]419pub struct QueuedComponents {420pub(super) components: TypeIdMap<QueuedRegistration>,421pub(super) resources: TypeIdMap<QueuedRegistration>,422pub(super) dynamic_registrations: Vec<QueuedRegistration>,423}424425impl Debug for QueuedComponents {426fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {427let components = self428.components429.iter()430.map(|(type_id, queued)| (type_id, queued.id))431.collect::<Vec<_>>();432let resources = self433.resources434.iter()435.map(|(type_id, queued)| (type_id, queued.id))436.collect::<Vec<_>>();437let dynamic_registrations = self438.dynamic_registrations439.iter()440.map(|queued| queued.id)441.collect::<Vec<_>>();442write!(f, "components: {components:?}, resources: {resources:?}, dynamic_registrations: {dynamic_registrations:?}")443}444}445446/// A type that enables queuing registration in [`Components`].447///448/// # Note449///450/// These queued registrations return [`ComponentId`]s.451/// These ids are not yet valid, but they will become valid452/// when either [`ComponentsRegistrator::apply_queued_registrations`] is called or the same registration is made directly.453/// In either case, the returned [`ComponentId`]s will be correct, but they are not correct yet.454///455/// Generally, that means these [`ComponentId`]s can be safely used for read-only purposes.456/// Modifying the contents of the world through these [`ComponentId`]s directly without waiting for them to be fully registered457/// and without then confirming that they have been fully registered is not supported.458/// Hence, extra care is needed with these [`ComponentId`]s to ensure all safety rules are followed.459///460/// As a rule of thumb, if you have mutable access to [`ComponentsRegistrator`], prefer to use that instead.461/// Use this only if you need to know the id of a component but do not need to modify the contents of the world based on that id.462#[derive(Clone, Copy)]463pub struct ComponentsQueuedRegistrator<'w> {464components: &'w Components,465ids: &'w ComponentIds,466}467468impl Deref for ComponentsQueuedRegistrator<'_> {469type Target = Components;470471fn deref(&self) -> &Self::Target {472self.components473}474}475476impl<'w> ComponentsQueuedRegistrator<'w> {477/// Constructs a new [`ComponentsQueuedRegistrator`].478///479/// # Safety480///481/// The [`Components`] and [`ComponentIds`] must match.482/// For example, they must be from the same world.483pub unsafe fn new(components: &'w Components, ids: &'w ComponentIds) -> Self {484Self { components, ids }485}486487/// Queues this function to run as a component registrator if the given488/// type is not already queued as a component.489///490/// # Safety491///492/// The [`TypeId`] must not already be registered as a component.493unsafe fn register_arbitrary_component(494&self,495type_id: TypeId,496descriptor: ComponentDescriptor,497func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static,498) -> ComponentId {499self.components500.queued501.write()502.unwrap_or_else(PoisonError::into_inner)503.components504.entry(type_id)505.or_insert_with(|| {506// SAFETY: The id was just generated.507unsafe { QueuedRegistration::new(self.ids.next(), descriptor, func) }508})509.id510}511512/// Queues this function to run as a resource registrator if the given513/// type is not already queued as a resource.514///515/// # Safety516///517/// The [`TypeId`] must not already be registered as a resource.518unsafe fn register_arbitrary_resource(519&self,520type_id: TypeId,521descriptor: ComponentDescriptor,522func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static,523) -> ComponentId {524self.components525.queued526.write()527.unwrap_or_else(PoisonError::into_inner)528.resources529.entry(type_id)530.or_insert_with(|| {531// SAFETY: The id was just generated.532unsafe { QueuedRegistration::new(self.ids.next(), descriptor, func) }533})534.id535}536537/// Queues this function to run as a dynamic registrator.538fn register_arbitrary_dynamic(539&self,540descriptor: ComponentDescriptor,541func: impl FnOnce(&mut ComponentsRegistrator, ComponentId, ComponentDescriptor) + 'static,542) -> ComponentId {543let id = self.ids.next();544self.components545.queued546.write()547.unwrap_or_else(PoisonError::into_inner)548.dynamic_registrations549.push(550// SAFETY: The id was just generated.551unsafe { QueuedRegistration::new(id, descriptor, func) },552);553id554}555556/// This is a queued version of [`ComponentsRegistrator::register_component`].557/// This will reserve an id and queue the registration.558/// These registrations will be carried out at the next opportunity.559///560/// If this has already been registered or queued, this returns the previous [`ComponentId`].561///562/// # Note563///564/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.565/// See type level docs for details.566#[inline]567pub fn queue_register_component<T: Component>(&self) -> ComponentId {568self.component_id::<T>().unwrap_or_else(|| {569// SAFETY: We just checked that this type was not already registered.570unsafe {571self.register_arbitrary_component(572TypeId::of::<T>(),573ComponentDescriptor::new::<T>(),574|registrator, id, _descriptor| {575// SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.576#[expect(unused_unsafe, reason = "More precise to specify.")]577unsafe {578registrator.register_component_unchecked::<T>(id);579}580},581)582}583})584}585586/// This is a queued version of [`ComponentsRegistrator::register_component_with_descriptor`].587/// This will reserve an id and queue the registration.588/// These registrations will be carried out at the next opportunity.589///590/// # Note591///592/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.593/// See type level docs for details.594#[inline]595pub fn queue_register_component_with_descriptor(596&self,597descriptor: ComponentDescriptor,598) -> ComponentId {599self.register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| {600// SAFETY: Id uniqueness handled by caller.601unsafe {602registrator603.components604.register_component_inner(id, descriptor);605}606})607}608609/// This is a queued version of [`ComponentsRegistrator::register_resource`].610/// This will reserve an id and queue the registration.611/// These registrations will be carried out at the next opportunity.612///613/// If this has already been registered or queued, this returns the previous [`ComponentId`].614///615/// # Note616///617/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.618/// See type level docs for details.619#[inline]620pub fn queue_register_resource<T: Resource>(&self) -> ComponentId {621let type_id = TypeId::of::<T>();622self.get_resource_id(type_id).unwrap_or_else(|| {623// SAFETY: We just checked that this type was not already registered.624unsafe {625self.register_arbitrary_resource(626type_id,627ComponentDescriptor::new_resource::<T>(),628move |registrator, id, descriptor| {629// SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.630// SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.631#[expect(unused_unsafe, reason = "More precise to specify.")]632unsafe {633registrator634.components635.register_resource_unchecked(type_id, id, descriptor);636}637},638)639}640})641}642643/// This is a queued version of [`ComponentsRegistrator::register_non_send`].644/// This will reserve an id and queue the registration.645/// These registrations will be carried out at the next opportunity.646///647/// If this has already been registered or queued, this returns the previous [`ComponentId`].648///649/// # Note650///651/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.652/// See type level docs for details.653#[inline]654pub fn queue_register_non_send<T: Any>(&self) -> ComponentId {655let type_id = TypeId::of::<T>();656self.get_resource_id(type_id).unwrap_or_else(|| {657// SAFETY: We just checked that this type was not already registered.658unsafe {659self.register_arbitrary_resource(660type_id,661ComponentDescriptor::new_non_send::<T>(StorageType::default()),662move |registrator, id, descriptor| {663// SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.664// SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.665#[expect(unused_unsafe, reason = "More precise to specify.")]666unsafe {667registrator668.components669.register_resource_unchecked(type_id, id, descriptor);670}671},672)673}674})675}676677/// This is a queued version of [`ComponentsRegistrator::register_resource_with_descriptor`].678/// This will reserve an id and queue the registration.679/// These registrations will be carried out at the next opportunity.680///681/// # Note682///683/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.684/// See type level docs for details.685#[inline]686pub fn queue_register_resource_with_descriptor(687&self,688descriptor: ComponentDescriptor,689) -> ComponentId {690self.register_arbitrary_dynamic(descriptor, |registrator, id, descriptor| {691// SAFETY: Id uniqueness handled by caller.692unsafe {693registrator694.components695.register_component_inner(id, descriptor);696}697})698}699}700701702