Add component_id function to World and Components (#5066)
# Objective - Simplify the process of obtaining a `ComponentId` instance corresponding to a `Component`. - Resolves #5060. ## Solution - Add a `component_id::<T: Component>(&self)` function to both `World` and `Components` to retrieve the `ComponentId` associated with `T` from a immutable reference. --- ## Changelog - Added `World::component_id::<C>()` and `Components::component_id::<C>()` to retrieve a `Component`'s corresponding `ComponentId` if it exists.
This commit is contained in:
		
							parent
							
								
									f8fa229465
								
							
						
					
					
						commit
						fa56a5cd51
					
				@ -214,6 +214,23 @@ impl ComponentInfo {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A semi-opaque value which uniquely identifies the type of a [`Component`] within a
 | 
			
		||||
/// [`World`](crate::world::World).
 | 
			
		||||
///
 | 
			
		||||
/// Each time a new `Component` type is registered within a `World` using
 | 
			
		||||
/// [`World::init_component`](crate::world::World::init_component) or
 | 
			
		||||
/// [`World::init_component_with_descriptor`](crate::world::World::init_component_with_descriptor),
 | 
			
		||||
/// a corresponding `ComponentId` is created to track it.
 | 
			
		||||
///
 | 
			
		||||
/// While the distinction between `ComponentId` and [`TypeId`] may seem superficial, breaking them
 | 
			
		||||
/// into two separate but related concepts allows components to exist outside of Rust's type system.
 | 
			
		||||
/// Each Rust type registered as a `Component` will have a corresponding `ComponentId`, but additional
 | 
			
		||||
/// `ComponentId`s may exist in a `World` to track components which cannot be
 | 
			
		||||
/// represented as Rust types for scripting or other advanced use-cases.
 | 
			
		||||
///
 | 
			
		||||
/// A `ComponentId` is tightly coupled to its parent `World`. Attempting to use a `ComponentId` from
 | 
			
		||||
/// one `World` to access the metadata of a `Component` in a different `World` is undefined behaviour
 | 
			
		||||
/// and must not be attempted.
 | 
			
		||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
 | 
			
		||||
pub struct ComponentId(usize);
 | 
			
		||||
 | 
			
		||||
@ -422,11 +439,38 @@ impl Components {
 | 
			
		||||
        self.components.get_unchecked(id.0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Type-erased equivalent of [`Components::component_id`].
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn get_id(&self, type_id: TypeId) -> Option<ComponentId> {
 | 
			
		||||
        self.indices.get(&type_id).map(|index| ComponentId(*index))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the [`ComponentId`] of the given [`Component`] type `T`.
 | 
			
		||||
    ///
 | 
			
		||||
    /// The returned `ComponentId` is specific to the `Components` instance
 | 
			
		||||
    /// it was retrieved from and should not be used with another `Components`
 | 
			
		||||
    /// instance.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Returns [`None`] if the `Component` type has not
 | 
			
		||||
    /// yet been initialized using [`Components::init_component`].
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```rust
 | 
			
		||||
    /// use bevy_ecs::prelude::*;
 | 
			
		||||
    ///
 | 
			
		||||
    /// let mut world = World::new();
 | 
			
		||||
    ///
 | 
			
		||||
    /// #[derive(Component)]
 | 
			
		||||
    /// struct ComponentA;
 | 
			
		||||
    ///
 | 
			
		||||
    /// let component_a_id = world.init_component::<ComponentA>();
 | 
			
		||||
    ///
 | 
			
		||||
    /// assert_eq!(component_a_id, world.components().component_id::<ComponentA>().unwrap())
 | 
			
		||||
    /// ```
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn component_id<T: Component>(&self) -> Option<ComponentId> {
 | 
			
		||||
        self.get_id(TypeId::of::<T>())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn get_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {
 | 
			
		||||
        self.resource_indices
 | 
			
		||||
 | 
			
		||||
@ -177,10 +177,20 @@ impl World {
 | 
			
		||||
        WorldCell::new(self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Initializes a new [`Component`] type and returns the [`ComponentId`] created for it.
 | 
			
		||||
    pub fn init_component<T: Component>(&mut self) -> ComponentId {
 | 
			
		||||
        self.components.init_component::<T>(&mut self.storages)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Initializes a new [`Component`] type and returns the [`ComponentId`] created for it.
 | 
			
		||||
    ///
 | 
			
		||||
    /// This method differs from [`World::init_component`] in that it uses a [`ComponentDescriptor`]
 | 
			
		||||
    /// to initialize the new component type instead of statically available type information. This
 | 
			
		||||
    /// enables the dynamic initialization of new component definitions at runtime for advanced use cases.
 | 
			
		||||
    ///
 | 
			
		||||
    /// While the option to initialize a component from a descriptor is useful in type-erased
 | 
			
		||||
    /// contexts, the standard `World::init_component` function should always be used instead
 | 
			
		||||
    /// when type information is available at compile time.
 | 
			
		||||
    pub fn init_component_with_descriptor(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        descriptor: ComponentDescriptor,
 | 
			
		||||
@ -189,6 +199,31 @@ impl World {
 | 
			
		||||
            .init_component_with_descriptor(&mut self.storages, descriptor)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the [`ComponentId`] of the given [`Component`] type `T`.
 | 
			
		||||
    ///
 | 
			
		||||
    /// The returned `ComponentId` is specific to the `World` instance
 | 
			
		||||
    /// it was retrieved from and should not be used with another `World` instance.
 | 
			
		||||
    ///
 | 
			
		||||
    /// Returns [`None`] if the `Component` type has not yet been initialized within
 | 
			
		||||
    /// the `World` using [`World::init_component`].
 | 
			
		||||
    ///
 | 
			
		||||
    /// ```rust
 | 
			
		||||
    /// use bevy_ecs::prelude::*;
 | 
			
		||||
    ///
 | 
			
		||||
    /// let mut world = World::new();
 | 
			
		||||
    ///
 | 
			
		||||
    /// #[derive(Component)]
 | 
			
		||||
    /// struct ComponentA;
 | 
			
		||||
    ///
 | 
			
		||||
    /// let component_a_id = world.init_component::<ComponentA>();
 | 
			
		||||
    ///
 | 
			
		||||
    /// assert_eq!(component_a_id, world.component_id::<ComponentA>().unwrap())
 | 
			
		||||
    /// ```
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn component_id<T: Component>(&self) -> Option<ComponentId> {
 | 
			
		||||
        self.components.component_id::<T>()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`.
 | 
			
		||||
    /// This will panic if the `entity` does not exist. Use [`World::get_entity`] if you want
 | 
			
		||||
    /// to check for entity existence instead of implicitly panic-ing.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user